2016-01-28 82 views
9

我遇到了一些Erlang代碼,我試圖將其轉換爲Elixir來幫助我學習兩種語言並理解其差異。一般而言,宏和元編程是一個主題,我仍然試圖讓自己的頭腦,所以希望你會明白我的困惑。Erlang vs Elixir Macros

Erlang的代碼

-define(p2(MAT, REP), 
     p2(W = MAT ++ STM) -> m_rep(0, W, STM, REP)) 

% where m_rep is a function already defined. 

對我來說,似乎在上面的代碼中,有p2宏映射到名爲m_rep私有函數的兩個不同的定義。不過,在Elixir中,似乎只有一種模式匹配定義。 Elixir中有不同的可能嗎?

+2

我不知道你是否熟悉C和Lisp,但簡單的比喻是Erlang的宏像C宏(這是簡單的編譯時字符串替換),Elixir的宏像Lisp宏(即代碼可以操縱AST)。 –

+0

@OnorioCatenacci這非常有趣!非常感謝你幫助我理解。 :-) – plotplot

回答

6

這些不是兩個定義。第一行是宏,第二行是替換。令人困惑的是,這個宏與它生成子句的函數名稱相同。使用例如,當你這樣的宏:

?p2("a", "b"); 
?p2("c", "d"). 

以上將擴大到:

p2(w = "a" ++ stm) -> m_rep(0, w, stm, "b"); 
p2(w = "c" ++ stm) -> m_rep(0, w, stm, "d"). 

您可以使用erlc -P產生.P文件會告訴你宏觀膨脹的影響你的碼。看看這個稍微簡單,編譯例如:

-module(macro). 
-export([foo/1]). 

-define(foo(X), 
     foo(X) -> X). 

?foo("bar"); 
?foo("baz"); 
?foo("qux"). 

使用erlc -P macro.erl你會得到下面的輸出macro.P

-file("macro.erl", 1). 

-module(macro). 

-export([foo/1]). 

foo("bar") -> 
    "bar"; 
foo("baz") -> 
    "baz"; 
foo("qux") -> 
    "qux". 

在靈藥,你可以定義使用宏,以及多個功能的條款。它更冗長,但我認爲它也更清晰。仙丹相當於是:

defmodule MyMacros do 
    defmacro p2(mat, rep) do 
    quote do 
     def p2(w = unquote(mat) ++ stm) do 
     m_rep(0, w, stm, unquote(rep)) 
     end 
    end 
    end 
end 

,你可以用它來定義多個功能的語句,就像二郎神對方:

defmodule MyModule do 
    require MyMacros 

    MyMacros.p2('a', 'b') 
    MyMacros.p2('c', 'd') 
end 
+1

你在這裏教了我很多。謝謝你的詳細解答。 – plotplot

2
-define(p2(MAT, REP), 
     p2(w = MAT ++ stm) -> m_rep(0, w, stm, REP)) 

% where m_rep is a function already defined. 

上面的代碼有一些問題。

有沒有這樣的事情,在Erlang中有多個子句的宏。上面的代碼沒有定義宏的兩個單獨的定義,它們映射到一個稱爲m_rep的私有函數。它所做的是定義了一個2參數的宏,它定義了一個參數爲p2的函數,並調用了m_rep。然而,內部p2函數的參數定義是不正確的:

  • 它嘗試使用++與第二個參數不是列表
  • 它試圖將值分配到一個原子(你的意思是一個資本W,一個變量,而不是一個小的w,原子?)
  • 它嘗試在不允許賦值的地方進行賦值 - 在函數頭中。

您是否嘗試測試其是否相等(==而不是=),而不是進行分配?如果是這樣,你必須使用警衛。

此外,在我看來,你試圖使用wstm就好像它們是變量並將它們傳遞給m_rep,但它們不是! Erlang中的變量必須以大寫字母開頭。另一方面,Elixir的變量則不會。這可能是你混淆了兩種相似但仍然不同語言的概念。

我的一般建議是選擇一種語言並學習它,然後才能在你的帶子上使用不同的語言。如果你對編程完全陌生,那就選擇Erlang--這很簡單,事先學習的東西更少。如果你已經知道Ruby,或者更加熟悉你的技能,那麼選擇Elixir。

請多說你的意圖,我可能會想出表達它的代碼。上面的代碼片段太模糊了。

+0

你對變量名稱是正確的。爲混淆道歉! – plotplot

3

我不能自己在這裏。 :-)如果是你使用的宏,那麼使用LFE (Lisp Flavoured Erlang)會給你太多比erlang或elixir更好的宏處理。它也與兩者兼容。