Of course, that whole bit with decl is unnecessary:
julia> macro deffun(ex)
body = quote
x + y
end
res = Expr(:function, esc(ex), body)
end
julia> @deffun f(x::Int, y::Int)
f (generic function with 1 method)
julia> methods(f)
# 1 method for generic function "f":
f(x::Int64, y::Int64) at none:3
julia> f(1, 2)
3
On Tuesday, October 20, 2015 at 11:19:44 AM UTC-7, David Gold wrote:
>
> IIUC, the following yields the desired behavior:
>
> macro deffun(ex)
> func = ex.args[1]
> args = ex.args[2:end]
> decl = Expr(:call, func, args...)
> body = quote
> # do some stuff
>
>
> end
> res = Expr(:function, esc(decl), body)
> end
>
> gives
>
> julia> macroexpand(:( @deffun f(x::Int, y::Int) ))
> :(function f(x::Int,y::Int)
> end)
>
>
> On Monday, October 19, 2015 at 3:11:11 PM UTC-7, Andrei Zh wrote:
>>
>> @Kristoffer, as you said, there may be cleaner (more declarative) way to
>> do it, but beyond that your definition works perfectly, thanks!
>>
>> On Monday, October 19, 2015 at 2:21:45 PM UTC+3, Kristoffer Carlsson
>> wrote:
>>>
>>> I am not very good at macros but I took a stap at doing this. It is very
>>> possible this could be done in a cleaner way.
>>>
>>> Code:
>>>
>>> macroerror() = throw(ArgumentError("invalid macro expression"))
>>>
>>> function extract(ex)
>>> if !(ex.head == :call)
>>> macroerror()
>>> end
>>> f_name = ex.args[1]
>>> vars = Symbol[]
>>> types = Symbol[]
>>> for var_ex in ex.args[2:end]
>>> if isa(var_ex, Expr)
>>> if !(var_ex.head == :(::))
>>> macroerror()
>>> end
>>> sym = var_ex.args[1]::Symbol
>>> typ = var_ex.args[2]::Symbol
>>> elseif isa(var_ex, Symbol)
>>> sym = var_ex
>>> typ = :Any
>>> end
>>> push!(vars, sym)
>>> push!(types, typ)
>>> end
>>>
>>> return f_name, vars, types
>>> end
>>>
>>> macro deffun(expr)
>>> f, args, types = extract(expr)
>>> ex = Expr(:function)
>>> ex_def = Expr(:(call))
>>> push!(ex_def.args, f)
>>> for (arg, typ) in zip(args, types)
>>> var_ex = Expr(:(::))
>>> push!(var_ex.args, arg)
>>> push!(var_ex.args, typ)
>>> push!(ex_def.args, var_ex)
>>> end
>>> push!(ex.args, ex_def)
>>>
>>> # Function body goes here
>>> ex_body = quote
>>> println("hello")
>>> end
>>>
>>> push!(ex.args, ex_body)
>>> return esc(ex)
>>> end
>>>
>>> Usage:
>>>
>>> julia> @deffun foo(a,b::Int)
>>> foo (generic function with 1 method)
>>>
>>> julia> foo(5, 3.0)
>>> ERROR: MethodError: `foo` has no method matching foo(::Int64, ::Float64)
>>> Closest candidates are:
>>> foo(::Any, ::Int64)
>>>
>>> julia> foo(5, 3)
>>> hello
>>>
>>>
>>> julia> @deffun bar(a::AbstractString,b::Int)
>>> bar (generic function with 1 method)
>>>
>>> julia> bar("hoho", 3)
>>> hello
>>>
>>>
>>>
>>> On Monday, October 19, 2015 at 9:45:14 AM UTC+2, Andrei Zh wrote:
>>>>
>>>> I'm trying to write a macro for generation of new functions given their
>>>> name and arguments, e.g. given macro call:
>>>>
>>>> @deffun foo(a, b)
>>>>
>>>> it should generate function like:
>>>>
>>>> function foo(a, b)
>>>> # do some stuff
>>>>
>>>>
>>>>
>>>> end
>>>>
>>>> Important part is that both - name of a function and name of arguments
>>>> - should be preserved. My best attempt to do it looks like this:
>>>>
>>>> macro deffun(ex)
>>>> func = ex.args[1]
>>>> args = ex.args[2:end]
>>>> return quote
>>>> function $(esc(func))($(esc(args...)))
>>>> # do some stuff
>>>>
>>>>
>>>>
>>>> end
>>>> end
>>>> end
>>>>
>>>> `$(esc(func))` works pretty well, but `args` isn't a Symbol and so
>>>> macro compilation fails.
>>>>
>>>> 1. How do I escape list of arguments here?
>>>> 2. How do I make this macro to also support argument types? E.g. given
>>>> macro call:
>>>>
>>>>
>>>> @deffun foo(a::Int, b::Float64)
>>>>
>>>> the following functions should be generated:
>>>>
>>>> function foo(a::Int, b::Float64)
>>>> # do some stuff
>>>>
>>>>
>>>>
>>>> end
>>>>
>>>>
>>>>
>>>>