【问题标题】:Creating anonymous functions via macros通过宏创建匿名函数
【发布时间】:2014-07-21 03:09:13
【问题描述】:

我正在制作一个 API,其中匿名函数由宏组成,例如

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

应该使用 transform headbody[:do] 作为匿名函数的头部和主体。比如上面的宏调用上面的例子应该收集成:

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

使用取消引用片段可以很容易地创建新的命名函数defs,但不是新的匿名函数:

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 错误。

此时我将只使用一个普通的匿名函数,宏方法有点矫枉过正,但我​​仍然想知道这是否可行。

提前致谢!

【问题讨论】:

    标签: elixir


    【解决方案1】:

    此时我将只使用一个普通的匿名函数,宏方法有点矫枉过正,但我​​仍然想知道这是否可行。

    这正是我要提议的。 :) 匿名函数要简单得多,而且它还使作用域规则清晰,可以很好地配合组合等等。

    unquote 片段确实为定义模块函数提供了便利,它们并不完全适用于任何代码,因为这样就无法知道 unquote 片段何时适用。例如,如果你有这个:

    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
    

    【讨论】:

      猜你喜欢
      • 2013-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-31
      • 2015-02-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多