Macros 在宏中嵌套eval调用是错误的做法吗?

Macros 在宏中嵌套eval调用是错误的做法吗?,macros,julia,eval,dsl,compile-time,Macros,Julia,Eval,Dsl,Compile Time,为了进行说明,假设我有以下宏在真值表中计算行: macro bool_to_lit(a) eval(a) ? (x -> x) : (x -> !x) end macro make_clause(xs, bools, res) lits = map((x -> @eval @bool_to_lit $x), bools.args) clause_elements = map.(lits, xs.args) and_res = all(push!

为了进行说明,假设我有以下宏在真值表中计算行:

macro bool_to_lit(a)
    eval(a) ? (x -> x) : (x -> !x)
end

macro make_clause(xs, bools, res)
    lits = map((x -> @eval @bool_to_lit $x), bools.args)
    clause_elements = map.(lits, xs.args)
    and_res = all(push!(clause_elements, res))
    return and_res
end

#@make_clause((false, false), (false, false), true) returns true
@bool_to_lit
根据其参数的值返回闭包,而
@make_子句
使用结果计算其自身的值。然而,由于
@make_子句
使用
@eval
,我的理解是它实际上运行
@bool_to_lit
(因此不只是执行语法转换)

在这种情况下,避免使用嵌套的
@eval
,这样整个宏树的整个结果一次只计算一次,是否会更好(如在更快和生成更干净的代码中)

它是在更简单的编码(即当使用
@eval
时将嵌套宏视为函数)与正确性(即当避免嵌套
@eval
时仅进行编译时语法转换)之间的折衷吗?

(免责声明:我把代码的逻辑缩短了一点。也许是我犯了一个错误,但一般的观点是一样的。)

在大多数情况下,不应该在宏中使用
eval
。有两种可能的替代方法。首先,如果只要求宏处理文本布尔值(即值
true
false
),然后这些数据存储在AST中,您可以在编译时直接进行正常计算:

julia> macro make_clause_literal(xs, bools, res)
           clause_elements = map((lit, arg) -> lit == arg, bools.args, xs.args)
           res && all(clause_elements)
       end
@make_clause_literal (macro with 1 method)

julia> @macroexpand @make_clause_literal((false, false), (false, false), true)
true
如果输入真的是文字布尔值,那么应该添加一些检查

另一方面,如果您希望同时输入其他表达式,请将代码转换为执行相同操作的高效代码,并将计算留给运行时:

julia> macro make_clause(xs, bools, res)
           clause_elements = map((lit, arg) -> :($lit == $arg), bools.args, xs.args)
           esc(:($res && $(foldr((e,f) -> :($e && $f), clause_elements))))
       end
@make_clause (macro with 1 method)

julia> @macroexpand @make_clause((false, false), (false, false), true)
:(true && (false == false && false == false))

julia> @macroexpand @make_clause((false, false), (false, x), y)
:(y && (false == false && x == false))
在避免中间数组和短路方面,构造一个
&&
序列应该尽可能好


我建议的第三种选择是,编写一个普通的运行时函数来执行子句求值,并根据对该子句的调用重写上述任何一个宏。我把它作为一个练习。您也可以同时使用这两种方法,并尽可能在编译时对表达式求值,但我猜编译r在某种程度上已经做到了。

谢谢!这个例子只是为了说明,我不是在寻找运行时优化,而是只寻找编译时计算。我实际上是在试验中描述的想法,你是在试图在编译时通过SAT解算来进行类型检查,还是这个例子真的只是虚构出来的?我是真的ly是这个领域的真正业余爱好者(甚至不是理科毕业生),目前我只是想跟上Julia macro系统的速度。我的代码取自其中一篇论文草稿(非类型最小布尔语言DSL)中的第一个示例。对于一个实现这个想法的非常棒的例子,看看这个语法例子,它是非常令人兴奋的…并且,对于一个麻醉师来说,将双向类型检查作为一种宏语言来实现是一个非常令人印象深刻的目标--太好了!回到Julia,你可能想读一读。如果你对每件事都足够熟悉的话要再次介绍抽象,请看一看。谢谢!这些都是非常有用的链接。是的,我可能不会走得太远,因为我怀疑这将证明是非常困难的,但我对计算机科学非常感兴趣,我觉得这对像julia这样的科学计算语言来说是一个真正的好处