gpt4 book ai didi

macros - 在引用 block 中调用私有(private)宏

转载 作者:行者123 更新时间:2023-12-01 15:35:20 25 4
gpt4 key购买 nike

我正在尝试使用在代码块本身内定义的变量在引用 block 中调用私有(private)宏。这是显示我想做什么的伪代码(不起作用)

defmodule Foo do
defmacrop debug(msg) do
quote bind_quoted: [msg: msg], do: IO.puts(msg)
end

defmacro __using__(_) do
quote do
def hello do
my = "testme"

unquote(debug(quote do: my))
end
end
end
end

defmodule Bar do
use Foo
end

Bar.hello()

这将在编译时(在我看来)转换为:

defmodule Bar do
def hello do
my = "testme"
IO.puts(my)
end
end

有什么办法可以实现吗?我正在努力寻找与之相关的任何文档。

更新

我发现:

defmodule Foo do
defmacrop debug() do
quote do: IO.puts("hello")
end

defmacro __using__(_) do
quote do
def hello do
my = "testme"

unquote(debug())
end
end
end
end

正确转换为我需要的,但我正在努力寻找一种方法按原样传递变量,以便它变成 IO.puts(my)

最佳答案

这里的问题是嵌套引用:私有(private)宏应该返回双引号表达式(因为从外部范围调用它需要显式 unquote ,宏仍然期望返回一个引用表达式。)

旁注:您的更新部分错误;你可能会注意到,"hello"在编译阶段打印,即 use Foo 时正在编译中。那是因为需要双引号,update 部分中的代码执行 IO.puts什么时候unquote__using__满足宏。

另一方面,my应该只引用一次。这可以通过显式引用 AST 并传递 msg 来实现。有原样:

defmodule Foo do
defmacrop debug(msg) do
quote bind_quoted: [msg: msg] do
{
{:., [], [{:__aliases__, [alias: false], [:IO]}, :puts]},
[],
[msg]} # ⇐ HERE `msg` is the untouched argument
end
end

defmacro __using__(_) do
quote do
def hello do
my = "testme"

unquote(debug(quote do: my))
end
end
end
end

defmodule Bar do
use Foo
end

Bar.hello()
#⇒ "testme"

我无法在调用 Kernel.SpecialForms.quote/2 时使用选项实现相同的功能;唯一可用的相关选项是 unquote调整嵌套引号内的取消引用,而我们需要恰恰相反。


旁注:下面不起作用,我希望这是 Kernel.SpecialForms.quote/2 中的错误实现。

quote bind_quoted: [msg: msg] do
quote bind_quoted: [msg: msg], do: IO.puts(msg)
end

FWIW:我 filed an issue .

我相信这可能是对 Elixir 核心的一个很好的功能请求,允许一个禁用额外的引用的选项。


旁注 2:以下作品(最简洁的方法):

defmacrop debug(msg) do
quote bind_quoted: [msg: msg] do
quote do: IO.puts(unquote msg)
end
end

因此,您可能会避免使用显式 AST 进行处理,而只需使用上面的内容。我保留原样的答案,因为直接处理 AST 也是一个很好的选择,应该用作大锤/最后的手段,它总是有效。


如果IO.puts不是您想要的目标,您可以调用 quote do: YOUR_EXPR关于你想在 debug 中拥有什么宏观:

quote do: to_string(arg)
#⇒ {:to_string, [context: Elixir, import: Kernel], [{:arg, [], Elixir}]}

并手动取消引用 arg结果:

#                                             ✗  ⇓⇓⇓ {:arg, [], Elixir} 
# ✓ ⇓⇓⇓ arg
{:to_string, [context: Elixir, import: Kernel], [arg]}

这基本上就是我如何获得原始请求的 AST ( IO.puts 。)

关于macros - 在引用 block 中调用私有(private)宏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50483335/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com