I've added trampoline to ease the conversion/creation of mutually recursive algorithms in Clojure.
Hear, hear! +1 Can I only vote once? +10
:-)
Hm, maybe a general compile-time assert would be in order, once we
have real tail-call optimization, so that even in the mutual-recursion
case you could get a nice error if you make a mistake like:
(def foo []
(+ 10
(tail-call bar 1 2)))
Although something less ugly might be nice.
--Chouser
On Tuesday 25 November 2008 06:05, Rich Hickey wrote:
> I've added trampoline to ease the conversion/creation of mutually
> recursive algorithms in Clojure.
>
> ...
Clojure's new trampolines for mutually recursive functions has caught
the attention of the Scala folks. There's a nice thread going on in the
Scala-Debate list beginning with one user's mention of this new
capability in Clojure. Two people there (one of them being Martin
Odersky, the head architect of the Scala language) showed a comparable
solution written in Scala.
Check it out:
- Subject: "Tail calls via trampolining and an explicit instruction"
- <http://dir.gmane.org/gmane.comp.lang.scala.debate>
- <http://www.nabble.com/Scala---Debate-f30218.html>
<http://www.nabble.com/Tail-calls-via-trampolining-and-an-explicit-instruction-td20702915.html>
Randall Schulz
big snip
> 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))
I'm curious about this syntax. I thought if #(function-name args)
creates a closure then I can put one in a variable and execute it
later. I entered this in a REPL.
(def myClosure #(prn "Hello"))
How can I execute the closure in myClosure now?
--
R. Mark Volkmann
Object Computing, Inc.
user=> (myClosure)
"Hello"
or now,
user=> (trampoline myClosure)
"Hello"
--Chouser
I entered this in a REPL.
(def myClosure #(prn "Hello"))
How can I execute the closure in myClosure now?
I've maybe missed something, but will this work if one wants to make
the final return value of the tail call a closure ?
Thanks! In the meantime I came up with an even simpler example that
demonstrates capturing a parameter and a local variable in a closure.
(defn greet-closure [name]
(let [salutation "Hello"]
#(println salutation name)))
(def my-closure (greet-closure "Mark"))
(my-closure)
outputs "Hello Mark"
If you want to return sets, keywords, maps, or everything that
implements the fn interface this is also an issue. Does trampolining
on keywords make sense?
> interface "fn" that distinguishes
The interface is "clojure.lang.Fn".
--Steve
Am 28.11.2008 um 22:56 schrieb André Thieme:
>> Maybe I have a wrong understanding of "closure", but
>> as far as I understand, every function definition in
>> Clojure - be it defn or #() - finally translates to (fn ...).
>> And fn creates a closure.
I tooled myself up and looked up the definition of "closure"
on Wikipedia. It seems that the definition says "one or more
bound variables". I still don't see why the "empty" environment
should that much of a special case. Why not just say:
"a closure keeps its environment". Why should it matter
whether its empty or not?
> Well, from my experience I can say that a lot of people
> think that “anon function = closure”, which would be
> fn in Clojure or lambda in Common Lisp.
> This however is not generally correct. In my previous
> posting I gave an example of how a named function
> became a closure.
There is no thing like a named function. defn expands
to (def ... (fn ...)). So an anonymous function is assigned
to a Var which has a name.
anon function != closure. This happens to be a feature
of Clojure, that it turns functions into closures.
Consider the GCC C extension for inner functions:
struct some_thing
do_something(int x)
{
int
do_more()
{
return x + 1;
}
return call_with_fun_pointer(do_more);
}
do_more could be considered an "anonymous"
function since it is only available inside do_something.
But it is not a closure. Suppose call_with_fun_pointer
stores away the pointer and returns.
Calling do_more later on is invalid, because the
stack was unwound and x doesn't exist anymore.
This is exactly, what a closure prevents.
But the whole issue is only a misunderstanding on
my side about what a closure is, and some philosophical
point, whether the empty environment is a special
case or not...
Sincerely
Meikel