On Wednesday, May 4, 2016 at 1:05:07 PM UTC-4, Yichao Yu wrote:
> Do not use `@eval` in macro, it happens in the wrong scope and in this
> case, the wrong time.
>
> macro symbol_dict(symbols...)
> :(Dict($([:($(QuoteNode(sym)) => $(esc(sym))) for sym in
> symbols]...)))
> end
>
>
> When using a macro, you want to generate the expression but not evaluate.
>
> iiuc what you want is sth like
>
> macro value_dict(vars...)
> :(let $([:($(esc(var)) = value($(esc(var)))) for var in vars]...)
> @symbol_dict($([esc(var) for var in vars]...))
> end)
> end
>
Thank you for the careful explanation and code. It's exactly what I want. I
have a follow-up question:
1. I thought I'd make make a (personal) cosmetic modification to your
`value_dict`.
macro value_dict(vars...)
rebindings = [:($(esc(var)) = value($(esc(var)))) for var in vars]
quote
let $(:($rebindings)...)
@symbol_dict($([esc(var) for var in vars]...))
end
end
end
It macroexpands into the same code, which is what I want. But I still have
trouble understanding the $(:($. For example, in a not-macro environment
julia> a = 2
2
julia> quote
$(:($a))
end
quote # none, line 2:
2
end
julia> quote
(($a))
end
quote # none, line 2:
2
end
The $ evaluates an expression and : quotes an expression, so I expect
$(:($a)) to be the same as $a, and indeed it is in this case. But if I try
to do the same simplification in the let expression, stripping off a shell
of $(:()), it macroexpands to
let [:($(Expr(:escape, :a)) = value($(Expr(:escape,
:a)))),:($(Expr(:escape, :b)) = value($(Expr(:escape, :b))))]...
which causes `ERROR: syntax: invalid let syntax`. And I don't quite get why
they macroexpand differently.
2. Can `macroexpand` do only one layer (so to speak) of macro expansion?
Can I do a `macroexpand(value_dict(x,y))` that still shows the invocation
of @symbol_dict, without expanding it recursively?