I want to generate named functions with fn and return them from the macro, I tried the following example:
(defmacro getfn
[namestr children]
`(fn fn-name# []
(println "Recursing" ~namestr)
(doall (map (fn [child#] (child#)) ~children))))
(def foo (getfn "foo" []))
(def bar (getfn "bar" [foo]))
(defn -main [& args]
(bar))
The resulting output is usually as expected:
Recursing bar
Recursing foo
However, when I run this compiled ahead-of-time (AOT) I get:
Recursing bar
Recursing bar
...
Recursing bar
Recursing bar
Exception in thread "main" java.lang.StackOverflowError
I find it pretty strange that bar keeps calling itself instead of foo, the only sensible reason for this is for the generated symbol fn-name#
to leak outside its scope. Is this a bug in Clojure or intended behaviour?
Update: For clarity should mention that removing the fn-name#
symbol and making the function anonymous fixes this problem. However, in my actual code I need to call it recursively sometimes, so naming it is necessary.
One solution I have for this problem is to use gensym to get a new symbol for each version of the macro, this would work by modifying the getfn as follows:
(defmacro getfn
[namestr children]
`(let [fn-name# (gensym)]
(fn fn-name# []
(println "Recursing" ~namestr)
(doall (map (fn [child#] (child#)) ~children)))))
This feels a bit unnecessary since by definition the fn name should be relevant only inside its own scope.
Update: Just tested with alpha releases and it seems Clojure 1.7.0-alpha3 and later work without this hack, Clojure 1.7.0-alpha2 and earlier are broken. Using this workaround is probably ok until stable version of 1.7.0 is released, unless someone can think of something better.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With