Macros 使用运行时相关参数调用Julia宏

Macros 使用运行时相关参数调用Julia宏,macros,runtime,metaprogramming,julia,Macros,Runtime,Metaprogramming,Julia,我想使用依赖于运行时的参数调用Julia包中的宏(@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) p

我想使用依赖于运行时的参数调用Julia包中的宏(
@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范围内。我使用
macro2
n
的这些不同的可能值建立所有可能的表达式,并为每个表达式调用外部宏(我在这里用简化的
macro1
代替)。对
macro1
的调用在
if
语句中,因此实际上只会执行正确的调用(根据运行时
n
的值确定)


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

似乎是您想要的?但是,请注意,应该谨慎使用它,而且它的速度不是很快,因为每次调用它时都需要编译器处理


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

通常依赖于运行时的代码生成是通过
@生成的
函数完成的。你应该在中检查它们,我相信
@generated
函数只能访问它们的参数类型,因此值
n
是未知的。你是对的,你
@generated
可以处理参数类型,但你可以“欺骗”系统为你工作。如果创建的类型没有字段,只有一个类型参数
n
,则可以使用
@generated
执行此操作。我还没有考虑过您的应用程序,所以我不能说我推荐这种方法,但我举了一个例子。注意,我需要
d
循环(
d
是一个函数参数)。因此,我将运行时值
d
作为
Degree
上的类型参数,并让
@generated
处理
Degree{d}
丑陋但聪明。在我的例子中,我还没能让它工作-我认为它在生成函数之前正在扩展宏,所以
n
仍然只是一个符号。
eval
在我的例子中确实起作用(用
eval(:(@macro2($n))替换我例子中的所有条件(
if(n==1)
end
您将得到相同的结果)。我没有在实际代码中使用它,因为我认为在全局范围内运行会有问题,而且我不确定“eval”是否会导致宏的扩展延迟到运行时。如果您能指出一个代码示例或描述,解释如何解决全局范围问题,我将不胜感激。
eval
在运行时之前肯定不会对AST做任何事情。当涉及到全局范围时,一种解决方法是
eval
函数定义,然后调用它。例如
f=eval(:(()->@(macro2($n);返回k));k=f()
。这甚至可能允许您向函数添加一些常规参数,并在
n
相同的情况下重用它。我接受您的答案,因为它对我上面的简单示例有效,但不幸的是,试图让它在实际代码中工作对我来说太多了,所以我将只使用我的简单但不雅观的,方法使用
if
语句。希望最终会有一种干净的方式来运行本地范围的
eval