Now that you've gone this far, why not do this?

- class clojure.lang.TailCall contains an AFn
- Compiler checks for a tail call position and instead of calling it,
returns new TailCall(AFn)
- In invoke, while returnvalue instanceof TailCall, returnvalue =
returnvalue.fn.invoke(returnvalue)

I confess I don't yet have much familiarity with the compiler; I'm
just reading through it now. Is the above idea workable?

Upside: you could have real TCO tonight, with J2SE 5.

Downside: as soon as they finally get around to putting TCO in the
JVM, it becomes useless cruft.

I would think you could take it back out, though. And who knows when
they'll finally do it? And wouldn't it be better to put TCO workaround
cruft in the compiler, rather than in the language definition, around
which people are already (foolishly, perhaps) starting to build
serious programs?


On Nov 25, 9:05 am, Rich Hickey <[EMAIL PROTECTED]> wrote:
> I've added trampoline to ease the conversion/creation of mutually
> recursive algorithms in Clojure.
>
> Trampolines are a well known technique for implementing TCO - instead
> of actually making a call in the tail, a function returns the function
> to be called, and a controlling loop calls it, thus allowing chained
> execution without stack growth.
>
> In order to do this I've made the following changes (SVN 1122):
>
> Added clojure.lang.Fn marker interface, used on all true fns.
> Breaking change - fn? now tests for Fn, not IFn (this was frequently
> requested)
> Added ifn? which will test for anything callable (IFn)
> Added trampoline, implements trampoline protocol for TCO
>
> Here's how it works. Normally, if you have mutual recursion (i.e.
> which can't be replaced with recur), you can blow the stack:
>
> (declare bar)
>
> (defn foo [n]
>   (if (pos? n)
>     (bar (dec n))
>     :done-foo))
>
> (defn bar [n]
>   (if (pos? n)
>     (foo (dec n))
>     :done-bar))
>
> (foo 1000000)
> -> java.lang.StackOverflowError
>
> To convert to a trampoline, simply return closures over your tail
> calls, rather than direct calls. This is as simple as prepending #
>
> (declare bar)
>
> (defn foo [n]
>   (if (pos? n)
>     #(bar (dec n))
>     :done-foo))
>
> (defn bar [n]
>   (if (pos? n)
>     #(foo (dec n))
>     :done-bar))
>
> Then make the top-level call via trampoline:
>
> (trampoline #(foo 1000000))
> -> :done-foo
>
> Rich

--~--~---------~--~----~------------~-------~--~----~
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
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to