我想制作一个API,其中匿名函数由宏组成,例如
transform [x, y], do: x + y
transform x, do: x
应使用transform
head
和body[:do]
作为匿名函数的头部和正文。例如,上面的宏调用上面的例子应该收集到:
fn [x, y] -> x + y; x -> x end
使用非引用片段,可以轻松创建新的命名函数def
,但不能创建新的匿名函数:
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失败并出现相同的unquote called outside quote
错误。
此时我只是使用简单的匿名函数,宏观方法过度,但我仍然有兴趣知道这是否可行。
提前致谢!
答案 0 :(得分: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