2016-11-17 51 views
0

我想製作一個宏來替代在幾個函數中使用的長表達式來提高代碼的可讀性。每個函數都具有相同的名稱,用於宏中,但是編譯函數Julia時,宏中使用的變量即使在轉義時也是未定義的。小例子:朱莉婭 - UndefVarError宏,當在函數中使用但不是在REPL中

julia> macro mtest() 
    esc(x) 
end 
@mtest (macro with 1 method) 

julia> ftest(x) = @mtest 
ERROR: UnderVarError: x not defined 

現在這樣會很奇怪:

julia> x = 1 
1 
julia> @mtest 
1 
julia> ftest(x) = @mtest 
ftest (generic function with 1 method) 
julia> ftest(2) 
1 

爲什麼沒有這個功能定義簡單計算爲ftest(x) = x?我如何告訴宏從調用函數的範圍而不是從REPL使用x?我想用一個宏可以替換爲文本的文字塊,如C庫我使用:

#define CHECK_STUFF \ 
    big \ 
    complicated \ 
    expression \ 
    involving x; 

void func(x, y, z) { 
    //stuff 
    CHECK_STUFF 
    //more stuff 
} 

在這種情況下CHECK_STUFF必須是宏,的功能,因爲它包含gotofunc中的標籤。我的任務是把這個翻譯成朱莉婭。

+0

在宏中,'x'需要符號':x'。你的宏指的是全局變量'x',它只在你在REPL中定義它之後才存在。另見http://stackoverflow.com/q/37358528/6172490。 – tim

+0

更具體地說,宏中使用的變量指的是宏定義模塊中的全局變量。在你的情況下,它是在主模塊中定義的,因此是指在那裏定義的'x'。你的宏然後返回只包含'x'的字面值的表達式。在這種情況下,轉義不會改變任何內容。查看'macroexpand'的輸出,這在編寫宏時非常有用。 – tim

回答

1

您的宏計算值,而不是表達式。因此,由於宏在編譯時運行,而不是在運行時運行,所以它在編譯時基本上是esc(x),但由於x在編譯時爲1,所以函數將編譯爲f(x)=1。你想要做的是讓你的宏返回表達式x,這樣你的函數編譯爲f(x)=x。那就是:

macro mtest() 
    quote 
     x 
    end 
end 

會工作。雖然你可以將其設置爲:x,但這種語法非常好。

事實上,我傾向於用「後來報價」的方式編寫宏。您可以先編寫宏並在REPL中測試它,而不用它返回表達式,而是返回值。這就是你在這裏做的。讓它工作起來會更容易。然而,它實際上在函數中有用,它必須返回一個表達式。所以最簡單的方法就是做我剛纔展示的東西:把你的東西放在它周圍,然後放上quote end。現在,如果您有宏的參數,則需要修改表達式,以便正確插值。但是如果一般算法已經有效,那麼這個部分就不會那麼困難了(我已經留下了一個麪包屑的痕跡,以便如何在SO上插入許多奇怪的東西,所以如果想插入奇怪的東西,就搜索一下。