IllegalStateException: attempt to call unbound fn in a macro

I am trying to write a macro that calls some functions. Functions should only be used by macros, so I put them inside letfn , wrapping the macro. Pseudocode:

 (letfn [(fn-a [] ...) (fn-b [] ...) (fn-c [] (fn-b))] (defmacro my-macro [stuff] `(let [whatever# (fn-a)] (fn-c)))) 

Calling fn-a and fn-c works, but when fn-c tries to call fn-b , I get IllegalStateException: Attempting to call unbound fn: # 'name.space/fn-b. Why is this?

If I put fn-b and fn-c in my own defn s, everything will work. But I do not want to do this because it is not clean.

Edit: just to check, I tried putting function bindings in an internal let , but ran into the same exception.

+5
source share
2 answers

I do not think it can work that way. The fn-c call, for example, expands to your.namespace/fn-c , so your code seems to call other functions that only have the same name. But you do not have your.namespace/fn-b , which throws an exception.

To refer to an unqualified character, you need to quote and cancel it: ~'fn-a But this will not work, because local functions are not defined at the extension point, you can use them only for the macro itself.

You either need to define functions in the namespace, or qualify them in a macro, or include them in macroextension, which will define them each time you use them.

+2
source

I'm not sure if this is exactly what you need, but if I do this:

 (letfn [(fn-a [] (println 1)) (fn-b [] (println 2)) (fn-c [] (fn-b))] (defmacro my-macro [stuff] `(let [whatever# ~(fn-b)] ~(fn-c)))) 

then it works - it just needs a tilde to irrevocably call function calls.

Both of the following work:

 (defn fn-x [] (println 1)) (defn fn-y [] (fn-x)) (defmacro my-macro2 [stuff] `(let [whatever# (fn-x)] (fn-y))) 

and

 (defn fn-x [] (println 1)) (defn fn-y [] (fn-x)) (defmacro my-macro2 [stuff] `(let [whatever# ~(fn-x)] ~(fn-y))) 

In the first case, functions are evaluated and their results are included in the macro at compile time, while in the second they are evaluated at runtime. With letfn (the macro itself), the results are not available at compile time (presumably because they compile after the macro is compiled), so functions can only be used at run time.

+1
source

Source: https://habr.com/ru/post/1200083/


All Articles