Как написать DSL, который создает функцию с аргументами? - PullRequest
0 голосов
/ 10 июня 2018

Я хотел бы определить макрос таким образом, чтобы я мог передать в него блок do и заставить макрос создать функцию, которая вызывает блок с аргументом .Я сталкиваюсь с проблемой курицы и яйца, потому что код ниже жалуется, что name не определено.

defmodule MyMacro do
  defmacro greet(do: block) do
    quote do
      def hello(name), do: unquote(block)
    end
  end
end

defmodule Test do
  import MyMacro
  greet do
    IO.puts("Hello, #{name}!")
  end
end

Попытка скомпилировать этот код приводит к:

(CompileError) iex:6: undefined function name/0
(stdlib) lists.erl:1338: :lists.foreach/2
(stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
(iex) lib/iex/evaluator.ex:250: IEx.Evaluator.handle_eval/5

Из моегопонимая, это взрывается еще до того, как он попадет в мой макрос, потому что elixir пытается сгенерировать AST для блока do перед вызовом моего макроса, но name не определено.

Моя цель - иметь возможность вызвать Test.hello("world") после компиляции DSL.Это возможно в эликсире?

1 Ответ

0 голосов
/ 10 июня 2018

Макросы Elixir гигиенические , поэтому, если вы объявите переменную в макросе quote, она не будет доступна вызывающей стороне.Вы можете отключить это, поместив объявление переменной в var!:

quote do
  def hello(var!(name)), do: unquote(block)
end
...