2014-01-12 23 views
2

我正在通過Dave即將推出的Elixir書籍進行工作,並且在一個練習中,我想基於一個字符的內容動態構建一個函數參考Kernel.+/2Kernel.-/2等的字符串,'+','-'等等。如何動態調用Elixir中的運算符

基於另一個SO問題,我希望能夠調用apply/3路過內核,:+和兩個數字是這樣的:

apply(Kernel, :+, [5, 7]) 

這不起作用,因爲(如果我的理解對不對)Kernel.+/2是一個宏,而不是一個功能。我擡起頭的源代碼,並+是在__op__定義的,我可以從iex稱之爲:

__op__(:+, 5, 7) 

這工作,直到我把:+到一個變量:

iex(17)> h = list_to_atom('+') 
:+ 
iex(18)> __op__(h, 5, 7) 
** (CompileError) iex:18: undefined function __op__/3 
    src/elixir.erl:151: :elixir.quoted_to_erl/3 
    src/elixir.erl:134: :elixir.eval_forms/4 

我猜測沒有辦法使用apply/3致電__op__

當然,蠻力方法可以完成工作。

defp _fn(?+), do: &Kernel.+/2 
    defp _fn(?-), do: &Kernel.-/2 
    defp _fn(?*), do: &Kernel.*/2 
# defp _fn(?/), do: &Kernel.//2 # Nope, guess again 
    defp _fn(?/), do: &div/2  # or &(&1/&2) or ("#{div &1, &2} remainder #{rem &1, &2}") 

但有沒有更簡潔和動態的東西?


何塞瓦利姆釘了下面的答案。以下是在上下文中的代碼:

def calculate(str) do 
    {x, op, y} = _parse(str, {0, :op, 0}) 
    apply :erlang, list_to_atom(op), [x, y] 
    end 

    defp _parse([]  , acc  )     , do: acc 
    defp _parse([h | t], {a, b, c}) when h in ?0..?9, do: _parse(t, {a, b, c * 10 + h - ?0}) 
    defp _parse([h | t], {_, _, c}) when h in '+-*/', do: _parse(t, {c, [h], 0}) 
    defp _parse([_ | t], acc  )     , do: _parse(t, acc) 

回答

8

你可以使用Erlang的一個:

apply :erlang, :+, [1,2] 

我們都知道,這是令人困惑,我們正在研究如何使其或者更明確或更透明。

更新:由於Elixir 1.0,您可以直接發送到內核(apply Kernel, :+, [1, 2])甚至使用OP首次嘗試的語法(&Kernel.+/2)。

+0

謝謝!這對我來說是訣竅。 –

+0

順便說一下,自從&Kernel。// 2不起作用以後,對/宏來說什麼纔是正確的咒語? –

+2

這應該這樣做:'&(Kernel ./)/ 2'(或'&(&1 /&2)') –