I am developing a macro that lets me write sums in a nice way. A trivial example is:
# some array
x = [1, 2, 3]
# calculate sum
s = @Σ i=1:3 x[i]
I have tried this:
module MyModule
export @Σ
# fancy macro to write sums
macro Σ(limits, expr)
index = limits.args[1]
start, stop = limits.args[2].args
quote
local out = $(_indexreplace(index, start, expr))
for i = ($start+1):$stop
out += $(_indexreplace(index, :i, expr))
end
out
end
end
# replace the previous index with the loop index inside the macro
_indexreplace(old, new, e::Expr) = Expr(e.head, (_indexreplace(old, new, sub) for sub in e.args)...)
_indexreplace(old, new, e::Symbol) = e == old ? new : e
end
# tests
using MyModule
x = [1, 2, 3]
println(macroexpand(:(@Σ i=1:3 x[i])))
@Σ i=1:3 x[i]
Running this gives me
begin # /Users/davide/Research/RMCO/julia/LorenzRMCO/test/test_sums.jl, line 10:
local #2#out = (MyModule.x)[1] # /Users/davide/Research/RMCO/julia/LorenzRMCO/test/test_sums.jl, line 11:
for #3#i = 1 + 1:3 # /Users/davide/Research/RMCO/julia/LorenzRMCO/test/test_sums.jl, line 12:
#2#out += (MyModule.x)[#3#i]
end # /Users/davide/Research/RMCO/julia/LorenzRMCO/test/test_sums.jl, line 14:
#2#out
end
ERROR: LoadError: UndefVarError: x not defined
in macro expansion; at /Users/davide/Research/RMCO/julia/LorenzRMCO/test/test_sums.jl:10 [inlined]
in anonymous at ./<missing>:?
in include_from_node1(::String) at ./loading.jl:488
in include_from_node1(::String) at /Users/davide/Software/julia-0.5/usr/lib/julia/sys.dylib:?
in process_options(::Base.JLOptions) at ./client.jl:262
in _start() at ./client.jl:318
in _start() at /Users/davide/Software/julia-0.5/usr/lib/julia/sys.dylib:?
while loading /Users/davide/Research/RMCO/julia/LorenzRMCO/test/test_sums.jl, in expression starting on line 28
which results in an error because the macro code is calling MyModule.x
which is not what I want. I have tried escaping the expression with esc
, as discussed in the manual, but I can’t seem to find a solution to this. Any help is appreciated.
Thanks,
Davide