Reputation: 2014
I would like to build automatically many Julia functions (metaprogramming) to wrap a library.
Here is the function I would like to generate:
function myfunc(a::Array{Float64,1}, b::Array{Float64,1}; x=Int64(1), y=Float64(2))
x + y
end
here are parameters of the function I would like to use to generate such a function.
funcname = :my_func
args = (:a, :b)
args_typ = (Array{Float64,1}, Array{Float64,1})
kw_args = (:x, :y)
kw_defval = (1, 2)
kw_typ = (Int64, Float64)
I don't feel confortable with Julia macro and http://docs.julialang.org/en/release-0.4/manual/metaprogramming/ doesn't help me much.
I also would like to be able to display function (generated) code.
My first idea (not very automated) was
macro GEN_FUNC(funcname)
function $funcname(a, b, x=1, y=2)
return x
end
end
but it raises
ERROR: syntax: invalid method name "$funcname"
Upvotes: 4
Views: 721
Reputation: 1750
I learned how to do this from reading the source code to the very nice DecFP.jl package (https://github.com/stevengj/DecFP.jl), by Steven G. Johnson at MIT.
It uses simple loops with the @eval
macro to generate all of the wrappers for the C library.
Upvotes: 0
Reputation: 761
You should return an expression from macros. To make code an expression, decorate your code with either :(....)
or quote ... end
. Also, $
is valid only for expressions and strings. Lastly, there is a hygiene issue with macros. In order to keep $funcname
intact you need esc
around it. Here is corrected code
julia> macro GEN_FUNC(funcname)
fname=esc(funcname)
quote
function $fname(a, b, x=1, y=2)
return x
end
end
end
julia> macroexpand(:(@GEN_FUNC testing))
quote # none, line 4:
function testing(#21#a,#22#b,#23#x=1,#24#y=2) # none, line 5:
return #23#x
end
end
Update: Here is how myfunc
can be manually constructed (Hint:I made it an expression with quote ... end
and cheated from that)
julia> f_body=:(x+y)
:(x + y)
julia> f_parameters=Expr(:parameters, Expr(:kw,:x,Int64(1)), Expr(:kw,:y,Float64(2)))
:($(Expr(:parameters, :(x=1), :(y=2.0))))
julia> f_call=Expr(:call,:myfunc,f_parameters,:(a::Array{Float64,1}),:(b::Array{Float64,1}))
:(myfunc(a::Array{Float64,1},b::Array{Float64,1}; x=1,y=2.0))
julia> f_declare=Expr(:function,f_call,f_body)
:(function myfunc(a::Array{Float64,1},b::Array{Float64,1}; x=1,y=2.0)
x + y
end)
julia> eval(f_declare)
myfunc (generic function with 1 method)
julia> myfunc(2,3)
ERROR: MethodError: `myfunc` has no method matching myfunc(::Int64, ::Int64)
julia> myfunc([2.],[3.])
3.0
julia> myfunc([2.],[3.];x=4,y=8.)
12.0
Upvotes: 7