[英]Elixir macros, quoting and unquoting
我正在学习Elixir,并尝试使用Macro系统。
我正在尝试使变量可用于将由宏与其他代码包装在一起的块,但是我显然做错了什么。
这是我的起点宏,可以正常工作。 我知道在Elixir中有更多惯用的方法可以迭代,因此我将其写为练习:
defmodule Loops do
defmacro times(n, [do: block]) do
quote do
Enum.each(1..unquote(n), fn(_) -> unquote(block) end)
end
end
end
import Loops
times 3 do
IO.puts "Hello!"
end
现在,我要完成的工作就是能够从do
块中引用计数器。 因此,如果我给fn
参数起一个合适的名字:
Enum.each(1..unquote(n), fn(_) -> unquote(block) end)
# becomes:
Enum.each(1..unquote(n), fn(counter) -> unquote(block) end)
我希望能够做这样的事情:
times 3 do
IO.puts "Hello! iteration n: #{counter}"
end
但是,由于undefined function counter/0
因此无法正常工作并引发CompileError
。 我传递给宏调用的do
块引发了错误,我发现这有点违反直觉,因为我认为在调用unquote()
时,该块将被放置在扩展代码中。
我是用错误的方式解决问题,还是根本不可能?
您可以使用Kernel.var!/2
来使counter
成为“不卫生的”变量。 这将确保生成的代码可用它,而不会被Elixir的宏系统重命名。
defmodule Loops do
defmacro times(n, [do: block]) do
quote do
Enum.each(1..unquote(n), fn(var!(counter)) ->
unquote(block)
end)
end
end
end
defmodule Main do
require Loops
def main do
Loops.times 3 do
IO.puts "Hello! iteration n: #{counter}"
end
end
end
Main.main
输出:
Hello! iteration n: 1
Hello! iteration n: 2
Hello! iteration n: 3
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.