如何动态生成函数子句
Howto dynamically generate function clauses
我需要根据用户的配置动态生成函数子句。为了清楚起见,假设我有一个原子列表:
@atoms ~w|foo bar baz|a
来自,比方说,config.exs
。我需要的是生成这个函数(MCVE 过于简单,但它给我的印象是我实际需要什么):
@checker fn
{:foo, _} -> false
{:bar, _} -> false
{:baz, _} -> false
_ -> true
end
我目前正在做的是:
@clauses Enum.map(@atoms, fn tag ->
{:->, [], [[{:{}, [], [tag, {:_, [], Elixir}]}], false]}
end) ++ [{:->, [], [[{:_, [], Elixir}], true]}]
defmacrop checker, do: {:fn, [], @clauses}
它工作得很好,但我想我把事情搞得太复杂了,漏掉了一些简单的东西。所以,我的问题是:
有没有简单的方法在编译时生成函数子句?
我使用 quote
:
使其更具可读性(更多信息见下文)
defmodule A do
@atoms ~w|foo bar baz|a
@clauses Enum.flat_map(@atoms, fn tag ->
quote do: ({unquote(tag), _} -> false)
end) ++ quote(do: (_ -> true))
defmacro checker, do: {:fn, [], @clauses}
end
defmodule B do
require A
f = A.checker
IO.inspect f.({:foo, :ok})
IO.inspect f.({:bar, :ok})
IO.inspect f.({:baz, :ok})
IO.inspect f.({:quux, :ok})
end
输出:
false
false
false
true
我希望 quote(do: a -> b)
可以工作,但现在是一个解析错误所以我们必须做 quote(do: (a -> b))
将我们想要的引用片段包装在列表中。
我还希望 unquote
在 fn
里面工作,但它在 quote
里面,但那也不行。
iex(1)> quote do
...(1)> fn
...(1)> unquote()
...(1)> _ -> true
...(1)> end
...(1)> end
** (SyntaxError) iex:2: expected clauses to be defined with -> inside: 'fn'
我认为这两个不是错误就是缺少功能。
我需要根据用户的配置动态生成函数子句。为了清楚起见,假设我有一个原子列表:
@atoms ~w|foo bar baz|a
来自,比方说,config.exs
。我需要的是生成这个函数(MCVE 过于简单,但它给我的印象是我实际需要什么):
@checker fn
{:foo, _} -> false
{:bar, _} -> false
{:baz, _} -> false
_ -> true
end
我目前正在做的是:
@clauses Enum.map(@atoms, fn tag ->
{:->, [], [[{:{}, [], [tag, {:_, [], Elixir}]}], false]}
end) ++ [{:->, [], [[{:_, [], Elixir}], true]}]
defmacrop checker, do: {:fn, [], @clauses}
它工作得很好,但我想我把事情搞得太复杂了,漏掉了一些简单的东西。所以,我的问题是:
有没有简单的方法在编译时生成函数子句?
我使用 quote
:
defmodule A do
@atoms ~w|foo bar baz|a
@clauses Enum.flat_map(@atoms, fn tag ->
quote do: ({unquote(tag), _} -> false)
end) ++ quote(do: (_ -> true))
defmacro checker, do: {:fn, [], @clauses}
end
defmodule B do
require A
f = A.checker
IO.inspect f.({:foo, :ok})
IO.inspect f.({:bar, :ok})
IO.inspect f.({:baz, :ok})
IO.inspect f.({:quux, :ok})
end
输出:
false
false
false
true
我希望 quote(do: a -> b)
可以工作,但现在是一个解析错误所以我们必须做 quote(do: (a -> b))
将我们想要的引用片段包装在列表中。
我还希望 unquote
在 fn
里面工作,但它在 quote
里面,但那也不行。
iex(1)> quote do
...(1)> fn
...(1)> unquote()
...(1)> _ -> true
...(1)> end
...(1)> end
** (SyntaxError) iex:2: expected clauses to be defined with -> inside: 'fn'
我认为这两个不是错误就是缺少功能。