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?
 

Reply via email to