Hi. I’m a newbie of Julia macro.
I’d like to know whether it’s possible to get a function and manipulate its arguments by macro.
For example, something like this.
@mymacro func(a, b) # == func(a+b, a-b)
Hi. I’m a newbie of Julia macro.
I’d like to know whether it’s possible to get a function and manipulate its arguments by macro.
For example, something like this.
@mymacro func(a, b) # == func(a+b, a-b)
Absolutely, the general way to go about writing macros is figure out what the expression tree looks like for the thing you’re trying to transform:
julia> ex = :(func(a,b))
:(func(a, b))
julia> dump(ex)
Expr
head: Symbol call
args: Array{Any}((3,))
1: Symbol func
2: Symbol a
3: Symbol b
then figure out how to transform that ex
into the thing you want and put it inside the macro,
macro mymacro(ex)
# for your simple example above:
esc(:($(ex.args[1])($(ex.args[2])+$(ex.args[3]), $(ex.args[2])-$(ex.args[3]))))
end
then check it did the right thing:
julia> @macroexpand @mymacro func(a,b)
:(func(a + b, a - b))
The MacroTools package has some convenient tools for matching and transforming expressions which are almost always useful, that can make writing that even more concise / readable (in particular look at @capture
).
Not sure if your real case is more complex, but if not, note that there’s ways to do your simple example which don’t involve macros (and if you don’t really need one, its almost always the right choice not to):
julia> func(a,b) = (a,b)
func (generic function with 1 method)
julia> sumdiff1(a, b) = (a+b, a-b)
sumdiff1 (generic function with 1 method)
julia> func(sumdiff1(1,2)...)
(3, -1)
or
julia> sumdiff2(f) = (a,b) -> f(a+b, a-b)
sumdiff2 (generic function with 1 method)
julia> sumdiff2(func)(1,2)
(3, -1)
Thanks a lot! It’s a great explanation.
One more question: Can I use a macro to predefine some values for a certain structure?
For example, I would like to set some values of struct A
and reuse it (to avoid additional calculation) after the macro. Like this:
my_value(a::A) == 1
@value A
is identical to what I want (Can a macro receive a type? I’m not sure)@value A
a = A()
my_value(a) # == 1