2014-07-20 143 views
0

我正在創建一個API,其中一個匿名函數由宏組成,例如,通過宏創建匿名函數

transform [x, y], do: x + y 
transform x,  do: x 

應該使用transformheadbody[:do]的頭部和身體的匿名函數。例如,上面的宏調用上面的例子應該被收集到:

fn [x, y] -> x + y; x -> x end 

隨着所享有片段可以很容易地創建新的命名功能def S,而不是新的匿名功能:

iex> val = 1 
iex> fn() -> unquote(val) end 
** (CompileError) iex:99: unquote called outside quote 
(elixir) src/elixir_exp_clauses.erl:23: :elixir_exp_clauses.clause/5 
(elixir) src/elixir_fn.erl:33: anonymous fn/3 in :elixir_fn.expand/3 
(stdlib) lists.erl:1237: :lists.map/2 
(elixir) src/elixir_fn.erl:36: :elixir_fn.expand/3 

這裏是我的目前進展:

defmacro anonymous_fn(parts) do 
    quote bind_quoted: [parts: parts] do 
    fn_branches = for {head, body} <- parts, do: {:->, [], [[head], body]} 
    unquote({:fn, [], fn_branches}) 
    end 
end 

然而,嵌套所享有失敗,同樣的unquote called outside quote錯誤。

在這一點上,我只是要使用一個普通的匿名函數,宏觀方法是矯枉過正,但我​​仍然有興趣知道這是否可能。

在此先感謝!

回答

2

在這一點上,我只是要使用一個普通的匿名函數,宏觀方法是矯枉過正,但我​​仍然有興趣知道這是否可能。

這正是我要提出的。 :)匿名函數非常簡單,它也使得範圍規則清晰,適用於合成等。

未定義片段實際上是定義模塊函數的一種方便,它們並不完全適用於任何代碼,因爲不可能知道何時應用非定義片段。例如,如果你有這樣的:

def foo do 
    fn -> unquote(bar) end 
end 

你怎麼知道,如果是指適用於foo或匿名函數?在任何情況下,回答你的問題,你需要在報價中明確定義代碼:

defmacro anonymous_fn(parts) do 
    fn_branches = for {head, body} <- parts, do: {:->, [], [[head], body]} 
    {:fn, [], fn_branches} 
end 

或者:

defmacro anonymous_fn(parts) do 
    fn_branches = for {head, body} <- parts do 
    quote do: (unquote(head) -> unquote(body)) 
    end 
    {:fn, [], fn_branches} 
end 
+0

阿爽 - 巧妙的靈藥。謝謝! – jtmoulia