Hi,
to implement letrec in a language with eager evaluation strategy some
kind of mutability is probably needed. Consider for example a self-
referential definition such as
(let [fibo (lazy-cat [1 1] (map + fibo (rest fibo)))]
(take 10 fibo))
This will not work since fibo is not in scope when the binding is
established. The standard solution would probably be something like
this
(let [fibo (promise)]
(deliver fibo (lazy-cat [1 1] (map + @fibo (rest @fibo))))
(take 10 @fibo))
Not as nice as the original version due to explicit dereferencing, but
workable. As an alternative one could use a macro to expand to this
and use a code walker (or symbol-macros) to automatically include the
@ calls. The following is untested, but should be close:
(defmacro letrec [binding & body]
(let [[var expr] binding
g-var (gensym)]
`(let [~g-var (promise)]
(symbol-macrolet [~var @~g-var]
(deliver ~g-var ~expr)
~@body))))
and voila
(letrec [fibo (lazy-cat [1 1] (map + fibo (rest fibo)))]
(take 10 fibo))
produces (1 1 2 3 5 8 13 21 34 55).
Best,
Nils
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
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