2017-02-17 34 views
2

По какой-то причине мне пришлось поставить quote ... end блок в макросе и ex сгенерирован программно. Этот код работает. необъем выражений и переменных в макросе Julia в модулях

macro addsum_out() 
    quote 
    ex = :(x+y) 
    sum(eval(ex)) 
    end 
end 

x = [1 1 1] 
y = [2 2 2] 

z2 = @addsum_out 

Когда макрос помещается внутри модуля, он больше не работает:

module MyModule 

export @addsum 

macro addsum() 
    quote 
    ex = :(x+y) 
    sum(eval(ex)) 
    end 
end 

end 

using MyModule 
x = [1 1 1] 
y = [2 2 2]  
z = @addsum 

Он говорит:

ERROR: LoadError: UndefVarError: x not defined 

Я думаю, что я должен поставить esc куда-то, чтобы оценить выражение ex в основной области вне модуля. Что мне с этим делать?

+3

'eval' не следует использовать в макросах. Что ты пытаешься сделать? –

+2

'eval' работает в глобальном масштабе модуля. Посмотрите на 'macroexpand (: (@ addsum))' и обратите внимание на 'MyModule.eval'. Во всяком случае, это совершенно не нужно. Вместо этого вы должны вернуть 'esc (:(x + y))'. –

ответ

4

Проблема заключается в том, что макрос (внутри модуля), ссылающийся на x, будет искать x в этом модуле, например. MyModule.x

Это часть macro hygiene.

Чтобы предотвратить макрогигиению, вам необходимо указать esc(x) - это означает, что он будет использовать любое значение x в области видимости на сайте вызова.

Ваше полное решение может выглядеть следующим образом:

macro addsum_out() 
    quote 
    esc(x) + esc(y) 
    end 
end 

или более сжато:

macro addsum_out() 
    :( esc(x) + esc(y) ) 
end 

Обратите внимание, что это немного отличается от выполнения esc(:(x+y)), который бы избежать функции + также. т. е. модуль, содержащий этот макрос, может содержать перегрузку для +, и если вы хотите использовать это, то не избегайте +, в противном случае!

Существует небольшая дискуссия по этой теме в руководстве я поставил вместе:
https://github.com/p-i-/MetaGuideJulia/wiki#example-swap-macro-to-illustrate-esc

+0

Вы имеете в виду ':($ (esc (: x)) + $ (esc (: y)))'. – tim

+0

В качестве альтернативы вы можете использовать 'esc (Expr (: call, +,: x,: y))'. – tim