【问题标题】:Calling Julia macro with runtime-dependent argument使用依赖于运行时的参数调用 Julia 宏
【发布时间】:2016-02-17 10:48:42
【问题描述】:

我想使用依赖于运行时的参数调用 Julia 包(JuMP 中的@defNLExpr)中的宏。参数是一个依赖于运行时参数n 的表达式。我能想到的唯一方法如下:

macro macro1(x)
  y=length(x.args);
  return esc(:(k=$y-1))
end

macro macro2(n)
  x="0";
  for i=1:n
    x="$x+$i"
  end
  x=parse(x);
  return :(@macro1($x))
end

n=rand(1:3)
println(n)
if (n==1)
  @macro2(1)
elseif (n==2)
  @macro2(2)
elseif (n==3)
  @macro2(3)
else
  error("expected n in 1:3")
end
println(k)

这里我假设我的运行时 n 将始终在 1-3 范围内。我使用macro2n 的这些不同的可能值构建所有可能的表达式,并为它们中的每一个调用外部宏(我在这里用简化的macro1 替换)。对macro1 的调用在if 语句中,因此只有正确的调用(根据运行时n 的值确定)才会实际执行。

虽然这似乎可行,但有没有更有效的方法来实现这一点?

【问题讨论】:

  • 通常依赖于运行时的代码生成来自@generated 函数。您应该在the docs 中查看它们
  • 我相信 @generated 函数只能访问其参数的类型,因此 n 的值是未知的。
  • 你是对的,你 @generated 处理参数类型,但你可以“欺骗”系统为你工作。如果您创建一个没有字段但只有一个类型参数n 的类型,则可以使用@generated 来执行此操作。我没有考虑过你的应用程序,所以我不能说我推荐这种方法,但here's 是一个这样做的例子。请注意,我需要 d 循环(d 是一个函数参数)。因此,我将运行时 value d 作为 Degree 上的类型参数推入,并让 @generatedDegree{d} 上工作
  • 丑陋但聪明。我还不能让它在我的情况下工作 - 我认为它在生成函数之前扩展了宏,所以 n 仍然只是一个符号。

标签: macros runtime metaprogramming julia


【解决方案1】:

您似乎正在寻找eval?请注意,它应该小心使用,而且它不是很快,因为每次调用它都必须让编译器获得收益。

如果它在全局范围内评估表达式对您来说是一个限制,那么有一些方法可以解决这个问题。

【讨论】:

  • eval 在我的示例中似乎确实有效(将我示例中的所有条件 (if (n==1)...end) 替换为 eval(:(@macro2($n))) 并得到相同的结果) .我没有在我的实际代码中使用它,因为我认为在全局范围内运行会出现问题,并且因为我不确定“eval”会导致宏的扩展延迟到运行时。如果您能指出解释如何解决全局范围问题的代码示例或说明,我将不胜感激。
  • eval 在运行之前绝对不会对 AST 做任何事情。当涉及到全局范围时,解决它的一种方法是使用eval 一个函数定义,然后调用它。例如f = eval( :( ()->@(macro2($n); return k) ) ); k = f ()。这甚至可能允许您向函数添加一些普通参数,并在 n 相同的情况下重用它。
  • 我会接受你的回答,因为它确实适用于我上面的简单示例,但不幸的是,试图让它在真实代码中工作对我来说太过分了,所以我只会使用我的简单,但不优雅的方法与 if 语句。希望最终会有一种干净的方式在本地范围内运行 eval
猜你喜欢
  • 1970-01-01
  • 2016-04-28
  • 1970-01-01
  • 2015-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多