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 let expression.
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 x in esc:
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 pos, zero and 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 expr in 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.