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
>>
>>
>>
>>
>>
>>
>>
>>
>>