I just saw this in another thread. Try this version instead:

(defn f [n]
  (println "f called with" n)
  (if (zero? n)
    0
    (min (#'f (dec n))
         (#'f (dec n)))))

What's happening is that inside the body of f, the "f" is a symbol
whose contents point to the anonymous function being defined, so when
you recurse, you're recursing to the original anonymous function, not
the current value of "f". By using the #' macro in front of the f,
you're saying "Use the current value of the symbol f to calculate the
following value."

On Mon, Mar 28, 2011 at 8:47 PM, Benny Tsai <benny.t...@gmail.com> wrote:
> I was playing with "memoize" when I ran into some puzzling behavior.  A test
> case:
>
> (defn f [n]
>   (println "f called with" n)
>   (if (zero? n)
>     0
>     (min (f (dec n))
>          (f (dec n)))))
> (def f (memoize f))
>
> *The usage of "def" to rebind a function to its memoized version is taken
> from Programming Clojure.
>
> The output when I call f with 2:
>
> user=> (f 2)
> f called with 2
> f called with 1
> f called with 0
> f called with 0
> f called with 1
> f called with 0
> f called with 0
> 0
>
> Since f is memoized, my expectation was that I would see "f called with 2",
> "f called with 1", "f called with 0" each printed just once.  Instead, it's
> as though I didn't memoize f at all.  I know I did, because if I call f with
> 2 again, I get 0 back right away.
>
> user=> (f 2)
> 0
> This leads me to the second issue: Having evaluated (f 2), I assumed that
> the results for (f 2), (f 1), and (f 0) are all now available for immediate
> retrieval.  If I call (f 3), I thought I would only see "f called with 3"
> printed and then the result.  Instead, this is what I saw:
>
> user=> (f 3)
> f called with 3
> f called with 2
> f called with 1
> f called with 0
> f called with 0
> f called with 1
> f called with 0
> f called with 0
> f called with 2
> f called with 1
> f called with 0
> f called with 0
> f called with 1
> f called with 0
> f called with 0
> 0
>
> It's as though the recursive calls go to the unmemoized version of the
> function instead of the memoized one.
>
> I did find a way to get the expected behavior:
>
> (def g
>   (memoize
>    (fn [n]
>      (println "g called with" n)
>      (if (zero? n)
>        0
>        (min (g (dec n))
>             (g (dec n)))))))
>
> user=> (g 2)
> g called with 2
> g called with 1
> g called with 0
> 0
> user=> (g 3)
> g called with 3
> 0
>
> Up until now, I assumed the first formulation would work with recursive
> functions as well.  Was that incorrect?  Is something like the second
> formulation the only way to memoize recursive functions?
>
> --
> 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

Reply via email to