2017-05-15 43 views
5

myślałem że to będzie działać:Jak zdefiniować makro julia, które definiuje makro?

macro meta_meta(x,y) 
    :(macro $x(arg) :($($y) + $arg) end) 
end 

Oczekiwane zachowanie jest, że wywołanie @meta_meta(f,2) powinna być równoważna macro f(arg) :(2 + $arg) end

Innymi słowy

julia> @meta_meta(f,2) 
julia> @f(3) 
5 

Zamiast uzyskać:

ERROR: syntax: invalid macro definition 

Nie jestem pewien, jak postępować. Widzę, że drzewo wyrażeń dla tego makra różni się od tego, które otrzymam, jeśli ręcznie wygeneruję @f i sprawdzę jego drzewo ekspresji, a ja wypróbowałem kilka iteracji @meta_meta, ale nie mogę wymyślić jak zmienić moją definicję na działaj.

+1

jako przykład: https://discourse.julialang.org/t/def-macro-generator-broken-on-master/1096/3? U = chrisrackauckas. Być może potrzebujesz czegoś uciec. –

+0

Dzięki za wskaźnik! To powinno wystarczyć. Wypróbuję to, kiedy będę miał szansę to rozgryźć. – HaberdashPI

Odpowiedz

6

Higiena makr jest delikatna, gdy mamy do czynienia z cytatem z cytatu. Często uważam, że jedynym sposobem jest całkowita odmowa higieny makr i użycie jej do symulacji.

jednak w ograniczonej przykład, to proste po prostu obrócić wewnętrzną wycenę do o Expr:

julia> macro meta_meta(x, y) 
      :(macro $(esc(x))(arg) Expr(:call, :+, $(esc(y)), esc(arg)) end) 
     end 
@meta_meta (macro with 1 method) 

julia> @meta_meta f 2 
@f (macro with 1 method) 

julia> @f 3 
5 

Jeśli robi się bardziej skomplikowana, podejście wspomniałem powyżej polega na wyłączeniu z esc makro higienę. Oznacza to, że mamy do czynienia higieny Nas, stąd gensym: Użyj tej

julia> macro meta_meta(x, y) 
      arg = gensym() 
      esc(:(macro $x($arg) :($$y + $$arg) end)) 
     end 
@meta_meta (macro with 1 method) 

julia> @meta_meta f 2 
@f (macro with 1 method) 

julia> @f 3 
5 
+0

Dzięki! Komentarz Chrisa dotarł do mnie dość blisko, ale jeszcze go nie dostałem. Wciąż natknąłem się na [ten problem] (https://github.com/JuliaLang/julia/issues/16096). Zaskakuje mnie, że twoje drugie rozwiązanie nie napotyka tego problemu. Domyślam się, że jeśli uciekniesz od * całkowitego * wyrażenia, błąd dotyczący wychodzących argumentów nie ma zastosowania. – HaberdashPI

+0

@HaberdashPI ah tak, w moim pierwszym rozwiązaniu początkowo zapomniałem uciec z arg. Nie dotyczy to jednak również tego problemu; w rzeczywistości nie tracimy tutaj żadnych nazw argumentów funkcji. Zaktualizowałem swoją odpowiedź. –