2014-07-20 91 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