Когда вы используете bind_quoted, он оценивает фрагменты, которые вы передаете. Таким образом, IO.puts "hi"
оценивается в [expression: expression, block: block]
, а не в вашем блоке if
. Вы просто вводите туда :ok
.
В качестве примера давайте определим некоторые макросы, которые ничего не делают, кроме оценки того, что было передано:
defmodule AB do
defmacro a(block) do
quote bind_quoted: [block: block] do
block
block
:ok
end
end
defmacro b(block) do
quote do
unquote(block)
unquote(block)
:ok
end
end
end
Игнорируя некоторые предупреждения из первого, давайте вызовем каждое из них с блоком, содержащим IO.inspect/1
и посмотрим, что произойдет:
iex> require AB
iex> AB.a(IO.inspect(1 + 1))
... (some warnings)
2
:ok
iex> AB.b(IO.inspect(1 + 1))
2
2
:ok
В макросе a/1
проверка суммы + происходит вне кавычек, поэтому она вызывается только один раз. В макросе b/1
сумма + проверка происходит везде, где мы не цитируем block
.