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.