Very helpful. Thanks so much!

2012/12/18 Chas Emerick <c...@cemerick.com>

> On Dec 17, 2012, at 12:39 PM, Ben Wolfson wrote:
>
> > On Mon, Dec 17, 2012 at 9:32 AM, Chas Emerick <c...@cemerick.com> wrote:
> >>
> >> What you're trying to do is really a special case of mutual recursion:
> >> because Clojure's methods are separate functions, calling back through
> the
> >> multimethod (and its dispatch fn) will always consume stack space.  The
> >> general solution for this is to use `trampoline`, which will
> continuously
> >> call through functions returned from calling a function until a
> non-function
> >> value is returned.  This would allow you to make your multimethod
> >> mutually-recursive, as long as those recursive calls are made by
> returning a
> >> function (that the user of the multimethod would `trampoline` through):
> >
> > Also as long as you don't want to return a function from the
> multimethod, no?
>
> Correct.  As noted in the docs for `trampoline`:
>
>         ...if you want to return a fn as a final value, you must wrap it
> in some data structure and unpack it after trampoline returns.
>
> I can't say I've ever needed to write mutually-recursive higher-order
> functions.  I can only presume that doing so while needing to meet
> trampoline's contract for that corner case would be fairly cumbersome.
>
> IIRC, `trampoline` predated functions supporting metadata by some time.
>  If it were written again now, it might specify that metadata should be
> used to indicate that a function should be called-through, rather than
> returned as a non-intermediate value.  e.g.:
>
> (defn meta-trampoline
>   ([f]
>      (let [ret (f)]
>        (if (and (fn? ret) (-> ret meta :trampoline))
>          (recur ret)
>          ret)))
>   ([f & args]
>      (meta-trampoline #(apply f args))))
>
> With this, you can return whatever you want/need to, as long as you mark
> the self- or mutually-recursive calls with {:trampoline true} metadata:
>
> => (defmethod foo String
>      [x]
>      #(str "I got " x ", you gave me " %))
> #<MultiFn clojure.lang.MultiFn@4f0ab3f2>
> => (defmethod foo Long
>      [x]
>      ^:trampoline #(foo (str x)))
> #<MultiFn clojure.lang.MultiFn@4f0ab3f2>
> => (meta-trampoline foo 5)
> #<user$eval1992$fn__1993$fn__1994 user$eval1992$fn__1993$fn__1994@7466a008
> >
> => (*1 6)
> "I got 5, you gave me 6"
>
> Cheers,
>
> - Chas
>
> --
> 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