Well, a more important matter, this example in the documentation of atom is wrong! The recursive calls will not be memoized if called like that. Running this code clearly shows:
(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: 1218.15834 msecs" (def fib (memoize fib)) (time (fib 35)) user=> "Elapsed time: 953.94816 msecs" I believe this is caused because defn creates a named fn: user=> (macroexpand '(defn fib [n] (if (<= n 1) n (+ (fib (dec n)) (fib (- n 2)))))) (def fib (.withMeta (clojure.core/fn fib ([n] (if (<= n 1) n (+ (fib (dec n)) (fib (- n 2)))))) (.meta (var fib)))) So the recursive call don't go through the global user/fib that has been memoized, but by the local fib which hasn't. So a correct way to write it would be: (defn fib [n] (if (<= n 1) n (+ (user/fib (dec n)) (user/fib (- n 2))))) (def fib (memoize fib)) (time (fib 35)) user=> "Elapsed time: 0.814599 msecs" By fully qualifying the recursive call, it forces it to use the global var, memoizing all the recursive calls. This example should be corrected. On Nov 12, 2:13 pm, Joseph Smith <j...@uwcreations.com> wrote: > In this case 'memoize' returns a memoized version of the function 'f', which > closes over 'mem'. Each time 'memoize' is called a new atom is created, not > each time the function it returns is called. > > --- > Joseph Smith > j...@uwcreations.com > > On Nov 11, 2010, at 2:06 PM, Manoj 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. > > > Thanks. > > > -- > > 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 -- 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