Как определить функции на основе атрибута эликсира?

Допустим, у меня есть модули Silent и Definer. Я хочу определить пару функций для Silent на основе его атрибута. Позволь мне объяснить:

defmodule Silent do
  @function_names [:a, :b, :c]

  use Definer
end

defmodule Definer do
  defmacro __using__(_) do
    quote do
      Enum.each(@function_names, fn(n) ->
        def unquote(n)() do # line 5
          IO.puts "a new method is here!"
        end
      end)
    end
  end
end

Но этот подход на самом деле не работает, потому что у меня undefined function n/0 on line 5. Как я могу реализовать желаемый функционал?


person asiniy    schedule 06.05.2016    source источник
comment
Я хотел бы знать, каков вариант использования для этого. Вы пытаетесь сделать какой-то интерфейс для бедняков? Если это так, вам, вероятно, следует взглянуть на протоколы Elixir: elixir-lang.org/getting-started /протоколы.html   -  person Onorio Catenacci    schedule 06.05.2016


Ответы (1)


Вам нужно передать unquote: false в quote в Definer.__using__/1, чтобы иметь возможность внедрить фрагмент unquote внутрь quote.

defmodule Definer do
  defmacro __using__(_) do
    quote unquote: false do
      Enum.each(@function_names, fn(n) ->
        def unquote(n)() do # line 5
          IO.puts "a new method is here!"
        end
      end)
    end
  end
end

defmodule Silent do
  @function_names [:a, :b, :c]

  use Definer
end

Silent.a
Silent.b
Silent.c

отпечатки

a new method is here!
a new method is here!
a new method is here!

Подобный случай подробно описан в Kernel.SpecialForms.quote/2 docs, в котором также упоминается, как использовать bind_quoted, если вы хотите внедрить некоторые переменные в quote и создать unquote фрагменты.

person Dogbert    schedule 06.05.2016