`recur` throws control flow to the nearest `loop` head or fn body, and each method is itself a function, so `recur` within a method body will simply jump to the start of the method, _not_ tail-call the multimethod. e.g.:
=> (defmulti foo type) #'user/foo => (defmethod foo Long [x] (assert (integer? x) (str "x isn't an integer! " (pr-str x))) (recur (str x))) #<MultiFn clojure.lang.MultiFn@4f0ab3f2> => (foo 5) AssertionError Assert failed: x isn't an integer! "4" (integer? x) user/eval1831/fn--1832 (NO_SOURCE_FILE:3) 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): => (defmethod foo String [x] (str "got " x "!")) #<MultiFn clojure.lang.MultiFn@4f0ab3f2> => (defmethod foo Long [x] #(foo (str x))) #<MultiFn clojure.lang.MultiFn@4f0ab3f2> => (foo 5) #<user$eval1888$fn__1889$fn__1890 user$eval1888$fn__1889$fn__1890@3852fdeb> => (trampoline foo 5) "got 5!" >From an API standpoint, you would presumably name the multimethod itself >something like `trans*`, and expose only a helper function `trans` that would >implicitly trampoline through any functions returned by `trans*`. There is a >cost associated with trampolining isn't zero, but won't swamp actual work as >long as the methods are doing something nontrivial anyway. Another option you might consider is using agents. I see your methods already take a single state argument; this would then make it really easy to lift the automata onto an agent (or set of agents). That state would become the agents' state, and "recursive" calls would become a `send` (or `send-off` if you're doing IO or other blocking things) to the same agent (e.g. `(send *agent* trans)`). Cheers, - Chas -- http://cemerick.com [Clojure Programming from O'Reilly](http://www.clojurebook.com) On Dec 17, 2012, at 11:56 AM, juan.facorro wrote: > What about recur? > > It's a special form used for tail call optimizations. > > Juan > > On Monday, December 17, 2012 1:32:31 PM UTC-3, bruce li wrote: > Hello, everyone. > > I'm currently trying to model an automata using multi-method. So in my code, > I have something like: > > (defmethod trans :state > [state] > ; ....... > (trans ......)))) > > In the last line, the trans will be called with some different state. > > However, it seems that such call still consumes stack and I quickly come to a > stack overflow error when the states are reached multiple times. > > I'm wondering if there is some ways to optimize the code. > > 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