簡體   English   中英

Elixir宏,引用和取消引用

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM