I’m trying to figure out how to make variables defined in a
let expression be visible in a hygienic macro which is evaluated in that
macro insertx(x) x end let y = 5 @insertx(y) end >UndefVarError: y not defined.
Note, because programmers have to manually call
gensym in Common Lisp, analogous code works:
* (defmacro insertx (x) x) INSERTX *(let ((y 5)) (insertx y)) 5
I can get this macro to work by wrapping
macro insert_nonhygienicx(x) esc(x) end let y = 5 @insert_nonhygienicx(y) end >> 5
in this toy example the lack of hygiene isn’t a problem, but with more complicated examples it is. For instance, if I try to create the Lisp
nif macro (from Let over Lambda), I run into problems.
macro nif(expr, pos, zero, neg) #Three argument "if". if expr > 0 esc(pos) elseif expr == 0 esc(zero) else esc(neg) end end let x = "Positive!" @nif(3, x, "Zero", "Negative") end >> "Positive!"
I can use a local variable in the
neg arguments of
@nif. But if I want to use a local variable in the
expr argument, I get an error:
let x = 2 @nif(x, "Positive", "Zero", "Negative) end >> LoadError: Method Error: no method matching isless(::Int64, ::Symbol)
Here, for type reasons, I cannot wrap
esc. I could wrap the whole body of the macro in
esc(quote...end), but it’s not hard to expand this example to one in which I need to define variables inside the macro (say as a function of
expr), while preserving hygiene. Perhaps there’s a way to manually use
gensym myself to hid only the variables internal to the macro (and which I therefore don’t want to interact with the outside code), but I can’t figure it out.