问题
I'm tying to make an API where an anonymous function are composed from macros, e.g.
transform [x, y], do: x + y
transform x, do: x
should use the transform
head
and body[:do]
as the heads and bodies for an anonymous function. For example, the above macro calls The example above should be collected into:
fn [x, y] -> x + y; x -> x end
With unquote fragments it's easy to create new named function def
s, but not new anonymous functions:
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
Here's my current progress:
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
However, the nested unquote fails with the same unquote called outside quote
error.
At this point I'm just going to use a plain anonymous function, the macro approach was overkill, but I'd still be interested to know if this is possible.
Thanks in advance!
回答1:
At this point I'm just going to use a plain anonymous function, the macro approach was overkill, but I'd still be interested to know if this is possible.
This is exactly what I was going to propose. :) The anonymous function is much simpler and it also makes the scoping rules clear, works nice with composition and so on.
unquote fragments are really a convenience for defining module functions, they do not apply for any code exactly because it then becomes impossible to know when the unquote fragment applies. For example, if you had this:
def foo do
fn -> unquote(bar) end
end
How do you know if it is meant to apply to foo
or to the anonymous function? In any case, to answer your question, you need to define the code explicitly in the quote:
defmacro anonymous_fn(parts) do
fn_branches = for {head, body} <- parts, do: {:->, [], [[head], body]}
{:fn, [], fn_branches}
end
Or:
defmacro anonymous_fn(parts) do
fn_branches = for {head, body} <- parts do
quote do: (unquote(head) -> unquote(body))
end
{:fn, [], fn_branches}
end
来源:https://stackoverflow.com/questions/24849774/creating-anonymous-functions-via-macros