Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
(defn inc-more [nums]
(if (first nums)
(cons (inc (first nums))
(inc-more (rest nums)))
(list)))
(inc-more [1 2])
(if (first [1 2])
(cons (inc (first [1 2]))
(inc-more (rest [1 2])))
(list))
(if 1
(cons (inc (first [1 2]))
(inc-more (rest [1 2])))
(list))
(cons (inc (first [1 2]))
(inc-more (rest [1 2])))
(cons (inc 1)
(inc-more (rest [1 2])))
(cons (inc 1)
(inc-more (rest [1 2])))
(cons 2
(inc-more (rest [1 2])))
(cons 2
(inc-more (rest [2])))
(cons 2
(if (first [2])
(cons (inc (first [2]))
(inc-more (rest [2])))
(list)))
(cons 2
(if 2
(cons (inc (first [2]))
(inc-more (rest [2])))
(list)))
(cons 2
(cons (inc (first [2]))
(inc-more (rest [2]))))
(cons 2
(cons (inc 2)
(inc-more (rest [2]))))
(cons 2
(cons (inc 2)
(inc-more [])))
(cons 2
(cons 3
(inc-more [])))
(cons 2
(cons 3
(if (first [])
(cons (inc (first []))
(inc-more (rest [])))
(list))))
(cons 2
(cons 3
(if nil
(cons (inc (first []))
(inc-more (rest [])))
(list))))
(cons 2
(cons 3
(list)))
(cons 2 (3))
(2 3)
@jafingerhut
Copy link

jafingerhut commented Aug 9, 2018

And if you add org.clojure/tools.trace "0.7.9" as a dependency to a project, you can get run-time messages every time a function is called, with its parameter values, or every time it returns, with the return value, like this:

user=> (require '[clojure.tools.trace :as t])
nil

user=> (inc-more [5 7])
(6 8)

user=> (t/trace-vars inc-more)
#'user/inc-more

user=> (inc-more [5 7])
TRACE t1696: (user/inc-more [5 7])
TRACE t1697: | (user/inc-more (7))
TRACE t1698: | | (user/inc-more ())
TRACE t1698: | | => ()
TRACE t1697: | => (8)
TRACE t1696: => (6 8)
(6 8)

Loading

@jafingerhut
Copy link

jafingerhut commented Aug 9, 2018

This is almost certainly too many words, and not as clear as if it were interactively on a whiteboard, but here goes.

When you call (inc-more [5]), the computer creates a collection of values for inc-more's parameters, only one in this case, and it will remember that nums has the value [5] for this function call to inc-more (we'll call it the 1st one).

It starts executing the code of inc-more, taking the 'then' branch, which includes a call to inc-more with argument ().

That value of () does not overwrite the value of noms in the 1st call to inc-more. It becomes the value of an independent variable nums for the 2nd call to inc-more.

That 2nd call starts running at its beginning, taking the 'else' branch and returning the value '()'.

Where does it return it to? The computer pops off the top of the stack with the information about the 2nd call of inc-more, and finds at the top the information about the 1st call of inc-more. There it finds not only that it has a value of nums equal to [5], but that it has been waiting for the return value from a function call, which it now knows has the return value (). It takes that value and puts it into the expression in the then branch where the call to inc-more was, and continues executing from there.

When the 1st call to inc-more completes, it returns a value of (6).'

Where does it return that value to? It looks on the call stack, after popping off the information about the 1st call to inc-more. If you typed the expression (inc-more [5]) at the Clojure REPL, the caller is the function that implements the REPL behavior. It gets the return value, and prints it out for you to see.

Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment