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

Reply via email to