I'm not sure if this is โsimplerโ as such, but I thought I'd share the approach I took to re-implement letfn for the CPS transformer I wrote.
The key is to enter the variables, but the delay assigns the values โโuntil they are included in the scope. Basically, you would like to write:
(let [f nil] (set! f (memoize (fn [] <body-of-f>))) (f))
Of course, this does not work as it is, because let bindings are immutable in Clojure. However, we can get around this using a reference type - for example, promise :
(let [f (promise)] (deliver! f (memoize (fn [] <body-of-f>))) (@f))
But this still doesn't work, because we have to replace each instance of f with <body-of-f> with (deref f) . But we can solve this by introducing another function that calls the function stored in the promise. So the whole solution might look like this:
(let [f* (promise)] (letfn [(f [] (@f*))] (deliver f* (memoize (fn [] <body-of-f>))) (f)))
If you have a set of mutually recursive functions:
(let [f* (promise) g* (promise)] (letfn [(f [] (@f*)) (g [] (@g*))] (deliver f* (memoize (fn [] (g)))) (deliver g* (memoize (fn [] (f)))) (f)))
Obviously, a lot of boiler stove. But it's pretty hard to create a macro that gives you the letfn syntax.
Nathan davis
source share