bind_quoted не создает привязку внутри определения - PullRequest
0 голосов
/ 20 октября 2018

bind_quoted, похоже, не работает для меня.Вот пример, в котором не используется bind_quoted, и он работает должным образом:

defmodule Animals do

  defmacro dog do
    x = 4 

    quote do
      def go do
        IO.puts unquote(x)
      end
    end

  end

end

defmodule Test do
  require Animals
  Animals.dog  #inject the definition of go() into the Test module
end

В iex:

iex(10)> c "a.exs"
warning: redefining module Animals (current version defined in memory)
  a.exs:1

warning: redefining module Test (current version defined in memory)
  a.exs:15

[Test, Animals]

iex(11)> Test.go  
4
:ok

iex(12)>

Но документы bind_quoted скажем:

... опция: bind_quoted рекомендуется каждый раз, когда кто-то хочет вставить значение в кавычку.

Хорошо, давайте будем согласны:

defmodule Animals do

  defmacro dog do
    x = 4 

    quote bind_quoted: [x: x] do
      def go do
        IO.puts x
      end
    end

  end

end

defmodule Test do
  require Animals
  Animals.dog  #inject go() into the Test module
end

Компиляция в iex:

iex(10)> c "a.exs"
warning: redefining module Animals (current version defined in memory)
  a.exs:1

warning: redefining module Test (current version defined in memory)
  a.exs:15

warning: variable "x" does not exist and is being expanded to "x()", please use parentheses to remove the ambiguity or change the variable name
  a.exs:17


== Compilation error in file a.exs ==
** (CompileError) a.exs:17: undefined function x/0 
    (stdlib) lists.erl:1338: :lists.foreach/2
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
** (CompileError)  compile error
    (iex) lib/iex/helpers.ex:183: IEx.Helpers.c/2
iex(10)> 

Соответствующее сообщение в отчете об ошибке:

warning: variable "x" does not exist

Почему бы и нет?

1 Ответ

0 голосов
/ 20 октября 2018

Обычно да.Вот как это будет работать.Но сам вызов def является макросом, поэтому вам все равно придется использовать unquote внутри него.Если бы вы прямо цитировали IO.puts, он бы работал без проблем.

Вот несколько измененная версия вашего кода, демонстрирующая это:

defmodule Animals do
  defmacro dog do
    x = 4

    quote(bind_quoted: [xx: x]) do
      IO.puts(xx)
    end
  end
end

defmodule Test do
  require Animals

  def go do
    Animals.dog
  end
end

Теперь вернемся к вашей реализации;В этом примере я связал x с xx, чтобы явным образом показать вам, что если вы попытаетесь снять здесь x (вместо xx), он выдаст ошибку компиляции:

defmodule Animals do
  defmacro dog do
    x = 4

    quote(bind_quoted: [xx: x]) do
      def go do
        IO.puts(unquote(xx))
      end
    end
  end
end
...