On Thu, Nov 11, 2010 at 3:06 PM, Manoj <andhappi...@gmail.com> wrote: > I am a newbie to Clojure, so have some confusion around lexical > scoping especially when "let" is used in a recursive function call. To > be more precise, I am taking the example memoize() function used for > explaining the concept of atom at clojure.org. > > Here is how it is explained: > > (defn memoize [f] > (let [mem (atom {})] > (fn [& args] > (if-let [e (find @mem args)] > (val e) > (let [ret (apply f args)] > (swap! mem assoc args ret) > ret))))) > > (defn fib [n] > (if (<= n 1) > n > (+ (fib (dec n)) (fib (- n 2))))) > > (time (fib 35)) > user=> "Elapsed time: 941.445 msecs" > > (def fib (memoize fib)) > > (time (fib 35)) > > user=> "Elapsed time: 0.044 msecs" > > My question is when "let" is used in this context, wouldn't it create > a fresh binding to a new atom{}? Any explanation would be highly > appreciated.
It would create a fresh binding to a new atom{} every time memoize is called. So if you memoize another function, it gets its own atom, and say you memoized square as well as fib, (fib 3) would be stored in one and (square 3) in the other instead of one of them getting in the other one's way. The memoize function returns a new function, a closure created inside the let, so the let's binding is fixed for that function; so the memoized fib holds a single atom that it always uses. If you called (memoize fib) twice you'd get two different atoms; indeed two memoized fib functions where neither knew about the saved results of the other. For pure functions this obviously isn't very useful, hence why it's usually done once and assigned to a def. One reason you might want to do it is as a memory saving strategy: if you detected memory was low you might eval an expression that redefs in the appropriate namespaces all your memoized functions, thus clearing their memories and freeing RAM. But it's cleaner in that case to avoid memoize in preference to a memoize-like system that exposes the cached results; if you can get at the atom from outside you can (reset! a {}) when you need to free up the memory without having to diddle around with eval and redefing stuff at runtime and other ugly hacks like that. :) -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en