Looks like I was accidentally on 0.4, and hygiene rules changed in 0.5. 
This works:

using MacroTools

macro withself(fdef)
    @assert @capture(fdef, fname_() = expr_)
    esc(:(@generated function $(fname)(self)
        expr = $(Expr(:quote, expr))
        # Replace this with recursive traversal. For demo, I'm assuming a 
single function call
        @assert @capture(expr, f_(args__))
        :(($f)($([arg in fieldnames(self) ? Expr(:., :self, QuoteNode(arg)) 
: arg for arg in args]...)))
    end))
end

type A
    ii
    oo
end

a = 20
@withself foo() = ii + oo + a

foo(A(33, 44))  # 97



On Friday, September 30, 2016 at 9:59:37 AM UTC-4, Cedric St-Jean wrote:
>
> This only works if A and type_fields are defined in the same module 
>> though. Although to be honest it surprised me a bit that it works at all, I 
>> guess the type definitions are evaluated prior to macro expansions? 
>>
>
> Good point. 
>
> You can use a generated function then:
>
> using MacroTools
>
> macro withself(fdef)
>     @assert @capture(fdef, fname_() = expr_) # could accept other arguments
>     :(@generated function $(esc(fname))(self)
>         expr = $(Expr(:quote, expr))   # grab the `expr` from the macro 
> body
>         # Replace this with recursive traversal. For demo, I'm assuming a 
> single function call
>         @assert @capture(expr, f_(args__))
>         :($f($([arg in fieldnames(self) ? Expr(:., :self, QuoteNode(arg)) 
> : arg for arg in args]...)))
>     end)
> end
>
> type A
>     ii
>     oo
> end
>
> a = 20
> @withself foo() = ii + oo + a
>
> foo(A(33, 44))  # 97
>
> Since generated functions are passed the _type_ of their arguments, which 
> is what you were looking for. It's an abuse of Julia's metaprogramming 
> facilities in strict Lisp tradition ;)
>
> On Friday, September 30, 2016 at 5:32:49 AM UTC-4, Marius Millea wrote:
>
>>
>> Would eval'ing the type inside the macro work? This shows [:x, :y]
>>>
>>>
>> This only works if A and type_fields are defined in the same module 
>> though. Although to be honest it surprised me a bit that it works at all, I 
>> guess the type definitions are evaluated prior to macro expansions? 
>>
>>
>> A macro which defines a type-specific version @self_MyType of your @self 
>>> macro at the definition of the type: 
>>
>>
>> Yea, the solutions both me and fcard coded up originally involved having 
>> to call a macro on the type definition, this is precisely what I'm trying 
>> to get rid of right now. The reason for not using @unpack is just that its 
>> more verbose than this solution (at the price of the type redefinition 
>> thing, but for me its a fine tradeoff). It *really* like getting to write 
>> super concise functions which read just like the math they represent, 
>> nothing extra distracting, e.g. from my actual code:
>>
>> """Hubble constant at redshift z"""
>> @self Params Hubble(z) = Hfac*sqrt(ρx_over_ωx*((ωc+ωb)*(1+z)^3 + ωk*(1+z
>> )^2 + ωΛ) + ργ(z) + ρν(z))
>>
>>
>> """Optical depth between two redshifts given a free electron fraction 
>> history Xe"""
>> @self Params function τ(Xe::Function, z1, z2)
>>     σT*(ωb*ρx_over_ωx)/mH*(1-Yp) * quad(z->Xe(z)/Hubble(z)*(1+z)^2, z1, 
>> z2)
>> end
>>
>>
>>
>>
>>
>>
>>  
>>
>>

Reply via email to