Live data from Hacker News

Tail-call optimization added to 6to5 compiler

github.com

11–20 of 33 posts

Re: Tail-call optimization added to 6to5 compiler

#11
post #9

Earlier quoted context omitted.

Tail call optimization is more than optimized tail recursion . Recur provides an explicit form of support for the latter, but not the former.

I wonder whether you could add a tail-call construct to Clojure, not just a tail-recursion construct. But I guess, to preserve JVM semantics, you'd need a trampoline or so.

There was an effort, in 2012, to create a generalized TCO in Clojure using CPS and trampolining. I don't remember why it wasn't fully pursued, but the JVM team is now talking about eventually fixing the core issue behind not supporting tail calls.

Clojure Conj 2012: http://youtu.be/RLqqGSthmC0

Source: https://github.com/cjfrisz/clojure-tco

Re: Tail-call optimization added to 6to5 compiler

#14
post #10

Earlier quoted context omitted.

There is a lot of good stuff in there. I have to ask, though: what the tap-dancing Christ was the purpose of the new Symbol objects? They're completely alien to any other symbols implementation I've seen. They aren't global by default, they don't compare equally to one another, and even the global ones can't really be used for, say, KV lookups in a global table. WTF?

I believe they're similar to uninterned symbols in Lisp, i.e. what you get in Common Lisp from make-symbol (or gensym ). The main intended use-case seems to be to get "private" property names, by conjuring up a fresh name-like thing is not equal to any other name-like thing, and not findable/enumerable in the usual way either. You can then monkey-patch that into a class or do whatever other nefarious thing you were p…

So, that sort of makes sense if you were to use them as keys in the new Map and Set objects...but I again, I can't help but notice that I haven't felt their absence yet.

Thanks for the reference about CL make-symbol. Is there a practical use for this we actually would spot in the wild, or do I need to go up on the mountain with a copy of The Art of the Metaobject Protocol?

Re: Tail-call optimization added to 6to5 compiler

#15
post #10

Earlier quoted context omitted.

I believe they're similar to uninterned symbols in Lisp, i.e. what you get in Common Lisp from make-symbol (or gensym ). The main intended use-case seems to be to get "private" property names, by conjuring up a fresh name-like thing is not equal to any other name-like thing, and not findable/enumerable in the usual way either. You can then monkey-patch that into a class or do whatever other nefarious thing you were p…

So, that sort of makes sense if you were to use them as keys in the new Map and Set objects...but I again, I can't help but notice that I haven't felt their absence yet. Thanks for the reference about CL make-symbol . Is there a practical use for this we actually would spot in the wild, or do I need to go up on the mountain with a copy of The Art of the Metaobject Protocol ?

The standard Lisp use for generated symbols is to provide a way to reliably avoid name clashes during macro expansion.

I'm not sure if that qualifies as a practical use in the out in the wild or just a practical way to fix pain (e.g. CPP nonsense) that you can see out in the wild.

Re: Tail-call optimization added to 6to5 compiler

#16
post #10

Earlier quoted context omitted.

I believe they're similar to uninterned symbols in Lisp, i.e. what you get in Common Lisp from make-symbol (or gensym ). The main intended use-case seems to be to get "private" property names, by conjuring up a fresh name-like thing is not equal to any other name-like thing, and not findable/enumerable in the usual way either. You can then monkey-patch that into a class or do whatever other nefarious thing you were p…

So, that sort of makes sense if you were to use them as keys in the new Map and Set objects...but I again, I can't help but notice that I haven't felt their absence yet. Thanks for the reference about CL make-symbol . Is there a practical use for this we actually would spot in the wild, or do I need to go up on the mountain with a copy of The Art of the Metaobject Protocol ?

I had no idea what a Symbol even was until I stumbled upon alt - https://github.com/goatslacker/alt

It's a small and simple code base, and much easier way to grok the concept than reading a book.

Re: Tail-call optimization added to 6to5 compiler

#17
post #6

Earlier quoted context omitted.

Clojure has recur, which is tail recursion that detects not being in the tail. I prefer that to implicit tails with quiet , expensive fails like scheme.

Tail call optimization is more than optimized tail recursion . Recur provides an explicit form of support for the latter, but not the former.

In practice recursion probably covers most of the cases where it matters. Corecursion could (if awkwardly) be converted into ordinary recursion.

Re: Tail-call optimization added to 6to5 compiler

#18
post #17

Earlier quoted context omitted.

Tail call optimization is more than optimized tail recursion . Recur provides an explicit form of support for the latter, but not the former.

In practice recursion probably covers most of the cases where it matters. Corecursion could (if awkwardly) be converted into ordinary recursion.

Corecursion doesn't mean what you think it means. You mean mutual recursion.

Re: Tail-call optimization added to 6to5 compiler

#19
post #9

Earlier quoted context omitted.

I wonder whether you could add a tail-call construct to Clojure, not just a tail-recursion construct. But I guess, to preserve JVM semantics, you'd need a trampoline or so.

There was an effort, in 2012, to create a generalized TCO in Clojure using CPS and trampolining. I don't remember why it wasn't fully pursued, but the JVM team is now talking about eventually fixing the core issue behind not supporting tail calls. Clojure Conj 2012: http://youtu.be/RLqqGSthmC0 Source: https://github.com/cjfrisz/clojure-tco

I experimented with this too. It doesn't work out because you need to know at fn definition time and at the call site that you're using a non-standard calling convention. You can't rewrite all functions without a substantial performance overhead, so you need to be selective. Scala has a compiler plugin for type-directed CPS, but you have to annotate the crap out of your functions and things break down in a bad way for generic higher-order functions. If you wanted to take a real run at this in Clojure, you'd have to compile two versions of every function: the usual `invoke` methods plus an `invokeCPS` method with compiler-inserted call-site trampolining code. Then the programmer would still be saddled with ^:cps metadata or similar.

Re: Tail-call optimization added to 6to5 compiler

#20
post #17

Earlier quoted context omitted.

Tail call optimization is more than optimized tail recursion . Recur provides an explicit form of support for the latter, but not the former.

In practice recursion probably covers most of the cases where it matters. Corecursion could (if awkwardly) be converted into ordinary recursion.

It doesn't. Most of the advantage of tail calls over loops comes exactly from the fact that they work for all tail calls not just direct recursive calls. Examples: loops with a non-trivial iteration structure, programming in CPS, programming with monads, and doing state machines.
Post reply on HN