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