Определите и используйте функции внутри макросов - PullRequest
0 голосов
/ 16 мая 2018

В следующем примере:

defmodule Greetify do

  defmacro __using__(_) do
    quote do
      Module.register_attribute __MODULE__, :greet, accumulate: true,
        persist: false
      @before_compile Greetify
    end
  end

  defmacro __before_compile__(env) do
    greetings = Module.get_attribute(env.module, :greet)
    for {name, age} <- greetings do
      IO.puts "#{name} is #{age} years old"
    end
  end

end

Можно ли определить внутренние функции для использования в макросе?

Например:

  defmacro __before_compile__(env) do
    greetings = Module.get_attribute(env.module, :greet)
    say_greetings(greetings)

    defp say_greetings(grettings) do
      for {name, age} <- greetings do
        IO.puts "#{name} is #{age} years old"
      end
    end
  end

При попытке компилятора не работает функция say_grettings

Этот пример источника http://elixir -recipes.github.io / метапрограммирование / накопление аннотаций /

1 Ответ

0 голосов
/ 16 мая 2018

Ну, это возможно.Проблема с вашим кодом заключается в том, что вы смешиваете области видимости.Макросы в Elixir расширяются на этапе компиляции.В данный момент нет скомпилированной say_greetings/1 функции (кроме того, что нельзя вызвать defp изнутри defmacro, но это может быть преодолено при правильном цитировании.)

Что вам нужно для этогоработа, будет означать объявление say_greetings/1 в той же области, что и __before_compile__/1, чтобы сделать его доступным.Вы не можете определить его как функцию (см. Выше), но обходной путь должен был бы определить его как макрос .Таким образом, он будет расширен во время компиляции, и все будет работать (также я сомневаюсь, что понимаю причину этого.)

Подведение итогов:

defmodule Greetify do    
  defmacro __using__(_) do
    quote do
      Module.register_attribute __MODULE__, :greet, accumulate: true, persist: false
      @before_compile Greetify
    end
  end

  defmacrop say_greetings(greetings) do
    quote do
      for {name, age} <- unquote(greetings) do
        IO.puts "#{name} is #{age} years old"
      end
    end
  end

  defmacro __before_compile__(env) do
    greetings = Module.get_attribute(env.module, :greet)
    say_greetings(greetings)
  end
end

defmodule Test do
  use Greetify

  @greet {"Jon", 21}
  @greet {"Sam", 23}
end
...