好的,我的标题不好,但可以通过示例轻松解释。
invalid operands to binary expression ('const std::optional<n1::tag>' and 'const std::optional<n2::tag>')
我有两个表达式a和b。我想知道他们是否会给我未经评估的结果。
尽管我可以像+或*这样的可交换运算符推断出结果将是相同的。
编辑: 理解它的另一种方式是比较一个非常具体的表达式子集,这些子集可以推断函数的可交换性: Expr(:call,+,a,b)<=> Expr(:call,+,b,a)
答案 0 :(得分:2)
这是不可能的。找出两个程序是否具有相同结果而不进行评估的结果称为 Function Problem (函数问题),并且可以证明等同于解决停止问题。
不可能计算出代码段是否具有相同的结果。
答案 1 :(得分:2)
我们可以编写一个相当简单的函数,以模序的形式检查两个数组是否具有相同的元素:
function eq_modulo_ordering!(xs, ys) # note !, mutates xs and ys
while !isempty(xs)
i = findfirst(isequal(pop!(xs)), ys)
i === nothing && return false
deleteat!(ys, i)
end
isempty(ys)
end
eq_modulo_ordering(xs, ys) = eq_modulo_ordering!(copy(xs), copy(ys))
我们可以使用然后使用此功能来检查两个顶级表达式是否等效。
function expr_equiv(a::Expr, b::Expr, comm)
a.head === b.head || return false
a.head === :call || return a == b
a.args[1] ∈ comm || return a == b
eq_modulo_ordering(a.args, b.args)
end
expr_equiv(a, b, comm) = a == b
expr_equiv(a, b) = expr_equiv(a, b, [:+])
在我们要检查两个表达式在顶级以外完全相等的情况下,我们可以修改函数以使用相互递归来检查子表达式是否为expr_equiv
而不是{{1} }。
isequal
我们现在可以按预期使用function eq_modulo_ordering!(xs, ys, comm) # note !, mutates xs and ys
while !isempty(xs)
x = pop!(xs)
i = findfirst(b -> expr_equiv(x, b, comm), ys)
i === nothing && return false
deleteat!(ys, i)
end
isempty(ys)
end
eq_modulo_ordering(xs, ys, comm) = eq_modulo_ordering!(copy(xs), copy(ys), comm)
function expr_equiv(a::Expr, b::Expr, comm)
a.head === b.head || return false
a.head === :call || return a == b
a.args[1] ∈ comm || return all(expr_equiv.(a.args, b.args, Ref(comm)))
eq_modulo_ordering(a.args, b.args, comm)
end
expr_equiv(a, b, comm) = a == b
expr_equiv(a, b) = expr_equiv(a, b, [:+])
,可以选择提供可交换的函数列表。
expr_equiv