I've noticed that a common pattern in my code is to use macroexpand inside
functions/macros to generate expressions which are then further manipulated
into what I need. As an example, here's a short function I wrote to unroll
a finite difference stencil at a wall (which is then spliced into a larger
function to compute the requested derivatives)
julia> function unroll_left(st, idx, N=3)
pd = quote end
for j=1:size(st,2)
ex = Expr(:call, :+)
for i=1:size(st,1)
solref = macroexpand(:(@nref $N sol
d->(d==$idx?$i:i_{d})))
push!(ex.args, :($solref*$(st[i,j])))
end
derref = macroexpand(:(@nref $N der d->(d==$idx?$j:i_{d})))
push!(pd.args, :($derref = $ex))
end
pd
end
julia> a = rand(4,2)
4x2 Array{Float64,2}:
0.0352328 0.342554
0.898077 0.489546
0.933981 0.558188
0.721357 0.0678564
julia> unroll_left(a, 1)
quote
der[1,i_2,i_3] = sol[1,i_2,i_3] * 0.035232761679327096 + sol[2,i_2,i_3]
* 0.8980770465285655 + sol[3,i_2,i_3] * 0.9339813198913125 + sol[4,i_2,i_3]
* 0.7213570230346098
der[2,i_2,i_3] = sol[1,i_2,i_3] * 0.34255367557827077 + sol[2,i_2,i_3]
* 0.4895461571970048 + sol[3,i_2,i_3] * 0.5581879223691961 + sol[4,i_2,i_3]
* 0.06785635982311189
end
julia> unroll_left(a, 2)
quote
der[i_1,1,i_3] = sol[i_1,1,i_3] * 0.035232761679327096 + sol[i_1,2,i_3]
* 0.8980770465285655 + sol[i_1,3,i_3] * 0.9339813198913125 + sol[i_1,4,i_3]
* 0.7213570230346098
der[i_1,2,i_3] = sol[i_1,1,i_3] * 0.34255367557827077 + sol[i_1,2,i_3]
* 0.4895461571970048 + sol[i_1,3,i_3] * 0.5581879223691961 + sol[i_1,4,i_3]
* 0.06785635982311189
end
This works perfectly but using macroexpand in this way feels a bit hackish.
Is there a better way?