[英]Elixir macros, quoting and unquoting
I'm learning Elixir and experimenting with the Macro system. 我正在学习Elixir,并尝试使用Macro系统。
I am trying to make a variable available to a block that will be wrapped with other code by a macro, but I am clearly doing something wrong. 我正在尝试使变量可用于将由宏与其他代码包装在一起的块,但是我显然做错了什么。
This is my starting point macro, which works. 这是我的起点宏,可以正常工作。 I am ware that there are more idiomatic ways to iterate in Elixir, and I wrote it just as an exercise:
我知道在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
Now, what I want to accomplish is being able to reference the counter from the do
block. 现在,我要完成的工作就是能够从
do
块中引用计数器。 So, if I give a proper name to the fn
argument: 因此,如果我给
fn
参数起一个合适的名字:
Enum.each(1..unquote(n), fn(_) -> unquote(block) end)
# becomes:
Enum.each(1..unquote(n), fn(counter) -> unquote(block) end)
I would like to be able to do something like this: 我希望能够做这样的事情:
times 3 do
IO.puts "Hello! iteration n: #{counter}"
end
This however doesn't work and raises a CompileError
because of undefined function counter/0
. 但是,由于
undefined function counter/0
因此无法正常工作并引发CompileError
。 The error is raised from the do
block I passed to the macro invocation , which I find a bit counterintuitive because I thought that the block would be placed in the expanded code when calling unquote()
. 我传递给宏调用的
do
块引发了错误,我发现这有点违反直觉,因为我认为在调用unquote()
时,该块将被放置在扩展代码中。
Am I approaching the problem in the wrong way, or is this simply not possible? 我是用错误的方式解决问题,还是根本不可能?
You can use Kernel.var!/2
to make counter
an "unhygienic" variable. 您可以使用
Kernel.var!/2
来使counter
成为“不卫生的”变量。 This will make sure it is available to the generated code without being renamed by Elixir's macro system. 这将确保生成的代码可用它,而不会被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
Output: 输出:
Hello! iteration n: 1
Hello! iteration n: 2
Hello! iteration n: 3
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.