如何使用宏初始化列表,然后在2个不同的模块中生成相同的功能集?

时间:2016-10-13 21:48:36

标签: metaprogramming elixir

是否可以使用宏初始化列表,然后使用另一个宏根据该列表在2个不同的模块中生成2组函数?

伪代码示例:

defmodule ABC do
  defmacro rules() do
    quote do
      defrule("a")
      |> defrule("b")
      |> defrule("c")
    end
  end
end

defmodule BasicTokenizer do
  use TokenizerBuilder
  require ABC

  ABC.rules()
  |> deftokenizer()
end


defmodule ExtendedTokenizer do
  use TokenizerBuilder
  require ABC

  ABC.rules()
  |> defrule("d")
  |> deftokenizer() 
end

import ExUnit.Assertions, only: [assert: 1, assert: 2]

assert BasicTokenizer.tokenize("a") == "a"
assert BasicTokenizer.tokenize("b") == "b"
assert BasicTokenizer.tokenize("c") == "c"
assert ExtendedTokenizer.tokenize("a") == "a"
assert ExtendedTokenizer.tokenize("b") == "b"
assert ExtendedTokenizer.tokenize("c") == "c"
assert ExtendedTokenizer.tokenize("d") == "d"

我尝试了以下方法,但我陷入deftokenizer

defmodule TokenizerBuilder do

  defmacro __using__(_) do
    quote do
      require unquote(__MODULE__)
      import unquote(__MODULE__)
    end
  end

  defmacro defrule(str) do
    quote do
      [unquote(str)]
    end
  end

  defmacro defrule(rules, str) do
    quote do
      Enum.concat(unquote(rules), [unquote(str)])
    end
  end

  defmacro deftokenizer(rules) do
    # rules is AST, how to get builded list value outside quote?
    Enum.each(rules, fn(str) ->
      quote do
        def tokenize(unquote(str)) do
          unquote(str)
        end
      end
    end)
  end
end

1 个答案:

答案 0 :(得分:1)

很难准确说出你要求的内容,但请考虑以下代码:

iex(1)> f = &String.upcase/1
&String.upcase/1
iex(2)> g = &String.trim/1
&String.trim/1
iex(3)> h = &String.reverse/1
&String.reverse/1
iex(4)> fs = [f,g,h]
[&String.upcase/1, &String.trim/1, &String.reverse/1]
iex(5)> r = for f <- fs, do: f.("hello")
["HELLO", "hello", "olleh"]

我的意思是如果您正在尝试构建要应用于值的函数列表,那么这可能会起作用。我认为有一些方法可以构建一个应用于值的函数列表,而不必使用宏来执行此操作。但是你的用例对我来说还不是很清楚。