如何动态生成函数子句

时间:2017-01-12 14:45:15

标签: macros elixir metaprogramming

我需要根据用户的配置动态生成函数子句。为了清楚起见,想象一下我有一个原子列表:

GetCursorPos

来自,@atoms ~w|foo bar baz|a 。我需要的是生成这个功能(MCVE过于简单,但它给我的实际需要的印象):

config.exs

我目前正在做的是:

@checker fn
  {:foo, _} -> false
  {:bar, _} -> false
  {:baz, _} -> false
  _ -> true
end

它工作得很好,但我希望我过于复杂,丢失了一些简单的东西。所以,我的问题是:

有一种简单的方法可以在编译时生成函数子句吗?

1 个答案:

答案 0 :(得分:2)

我使用3215

更具可读性(请参阅下文了解更多信息)
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

我相信这两个都是错误或缺少功能。