gpt4 book ai didi

metaprogramming - Elixir:使用 Code.eval_quoted/3 在模块上下文中评估代码

转载 作者:行者123 更新时间:2023-12-03 23:36:51 25 4
gpt4 key购买 nike

给定以下模块:

defmodule Foo do

def bar do
IO.puts "I'm bar"
end

def eval(quoted_code) do
Code.eval_quoted(quoted_code, [], __ENV__)
end

end

然后下面的代码输出 Foo像预期的那样:
# Outputs Foo
quote do
IO.inspect __MODULE__
end |> Foo.eval

那为什么我不能调用 Foo 中的其他函数?从引用的 block 内?例如,下面的代码给了我一个 CompileError :
# CompileError: undefined function bar/0
quote do
bar
end |> Foo.eval

但以下代码有效:
# Outputs "I'm bar"
quote do
import Foo
bar
end |> Foo.eval
import 到底是什么声明做什么?进口 Foo进入 Foo ?这对我来说没有意义。

据我了解, Foo.eval正在评估 Foo 上下文中的引用代码模块。但显然那是错误的,因为我不能从 Foo 调用其他函数/宏,而无需在调用前加上 Foo. .此外,我不明白 import 如何/为什么声明有效:为什么我需要 import Foo当我已经处于 Foo 的上下文中时?

这里发生了什么?谢谢您的帮助!

最佳答案

Elixir 中的宏是卫生的。这意味着,他们不使用调用者上下文。让我们看一个来自 "Metaprogramming Elixir" book 的例子

number = 5
ast = quote do
number * 10
end
Code.eval_quoted ast
** (CompileError) nofile:1: undefined function number/0

第二个:
number = 5
ast = quote do
unquote(number) * 10 #the only change is unquote here
end
Code.eval_quoted ast
{50, []}

这个想法是,您可以在编译时计算一些东西,然后(使用宏)将此值注入(inject)生成的代码。宏可以使用与您的代码相同的变量名并且它们不会冲突。如果您知道自己在做什么并且真的想从外部范围访问变量,您可以使用 var! .

你正试图做相反的事情。您想在宏中使用代码中的某些内容。这使您的宏不可重用。

在开始时使用 import 似乎是一个好主意,表明您的宏依赖于这个特定的模块。由于那条线,它将在任何地方工作。

[编辑回答评论]:

当你通过 __ENV__作为最后一个论点,您不会从环境中导入所有内容。只有那些可以设置的选项是:
  • :file
  • :line
  • :aliases
  • :requires
  • :macros

  • 问题是,环境还有其他键。我们要覆盖的一个是 context_modules .这将允许从模块内部调用事物。恐怕做不到。这是一个设计决定。

    在旧版本的 elixir 中(我检查了 1.0),还有一个附加选项 :delegate_locals_to ,但在 1.2 中不存在。

    关于metaprogramming - Elixir:使用 Code.eval_quoted/3 在模块上下文中评估代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34757093/

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