Hi Mauro,

2016-06-22 21:13 GMT+02:00 Mauro:
>
> A REPL session of mine trying to figure out how to make that macro would 
> look something like this: 
>
> julia> ex = :(f(x, y, z, zz)) # this is what is passed into the macro 
> :(f(x,y,z,zz)) 
>
> julia> xdump(ex)  # xdump is nice to get an overview of nested 
> datastructures 
> Expr 
>   head: Symbol call 
>   args: Array(Any,(5,)) 
>     1: Symbol f 
>     2: Symbol x 
>     3: Symbol y 
>     4: Symbol z 
>     5: Symbol zz 
>   typ: Any::DataType  <: Any 
>

I knew and used "dump" but not "xdump".  I've seen that the latter has been 
deprecated in favor of the former in Julia 0.5.
 

> julia> target = :(f([x.re, y.re, z.re, zz.re].^2 + [x.im, y.im, z.im, 
> zz.im])) # this is your target 
> :(f([x.re,y.re,z.re,zz.re] .^ 2 + [x.im,y.im,z.im,zz.im])) 
>
> julia> xdump(target) 
> Expr 
>   head: Symbol call 
>   args: Array(Any,(2,)) 
>     1: Symbol f 
>     2: Expr 
>       head: Symbol call 
>       args: Array(Any,(3,)) 
>         1: Symbol + 
>         2: Expr 
>           head: Symbol call 
>           args: Array(Any,(3,)) 
>           typ: Any::DataType  <: Any 
>         3: Expr 
>           head: Symbol vect 
>           args: Array(Any,(4,)) 
>           typ: Any::DataType  <: Any 
>       typ: Any::DataType  <: Any 
>   typ: Any::DataType  <: Any 
>
>
> Now, writing the macro is really an exercise in manipulating nested data 
> structures.  With the added bonus that there are convenient constructors 
> for those datastructures, namely expression such as e.g. :(z = 4 +7). 
>
> julia> fn = ex.args[1] # extract the name of the function 
> :f 
>
> julia> args = ex.args[2:end] # its arguments 
> 4-element Array{Any,1}: 
>  :x 
>  :y 
>  :z 
>  :zz 
>
> julia> ar1 =:([])  # build up the first array 
> :([]) 
>
> julia> ar1.head # check 
> :vect 
>
> julia> [push!(ar1.args, :($(args[i]).re)) for i=1:length(args)] #add the 
> elements 
> 4-element Array{Any,1}: 
>  Any[:(x.re),:(y.re),:(z.re),:(zz.re)] 
>  Any[:(x.re),:(y.re),:(z.re),:(zz.re)] 
>  Any[:(x.re),:(y.re),:(z.re),:(zz.re)] 
>  Any[:(x.re),:(y.re),:(z.re),:(zz.re)] 
>
> julia> ar1 
> :([x.re,y.re,z.re,zz.re]) 
>
> julia> :($ar1^2) # square 
> :([x.re,y.re,z.re,zz.re] ^ 2) 
>
> etc. 
>
> It takes a bit of practice and patience.  Important, as Kristoffer said, 
> write out and test the code you expect the macro to form (at least until 
> you become a macro ninja), then write the macro.  For instance in one of 
> my projects I hand wrote all of the code I later built macros to 
> generate: 
> https://github.com/mauro3/Traits.jl/blob/master/test/manual-traitdef.jl 
>

Thank you so much, I've been able to change my "@uncertain" macro for 
Measurements.jl <https://github.com/giordano/Measurements.jl> package 
following your hints.  In the end, the trick was to quote rather than to 
evaluate the array of arguments.  Probably this is a good rule of thumb 
when writing macros.

Bye,
Mosè

Reply via email to