也许我误解了bind_quoted的用法,但是采用了这个简单的while循环宏:
defmodule Loop do
defmacro while(expression, do: block) do
quote bind_quoted: [expression: expression, block: block] do
for _ <- Stream.cycle([:ok]) do
if(expression) do
block
end
end
end
end
end
用法:
Interactive Elixir (1.8.0) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> c "loop.ex"
[Loop]
iex(2)> import Loop
iex(3)> while 1 == 1 do
...(3)> IO.puts "hi"
...(3)> end
hi
我希望有一个无限的“ hi”循环,但只会得到一个迭代。如果我删除每个参数的bind_quoted和简单的unquote(),它将按预期工作。有任何想法吗?
谢谢
答案 0 :(得分:0)
当您使用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
中,sum + inspect发生在引号之外,因此仅被调用一次。在宏b/1
中,总和检查发生在我们取消引用block
的任何地方。