有没有办法比较两个函数是否相等?例如,(λx.2*x) == (λx.x+x)应该返回 true,因为它们显然是等价的。
(λx.2*x) == (λx.x+x)
众所周知,一般函数相等通常是不可判定的,因此您必须选择您感兴趣的问题的一个子集。你可以考虑下面这些部分解决方案:
除了在另一个答案中给出的实际例子外,让我们选择可以用有类型λ演算表示的函数子集,我们还可以允许乘积和和类型。虽然检查两个函数是否相等可以像 将它们应用于变量并比较结果一样简单,但是我们不能构建相等函数 在编程语言本身内部。
预计到达时间: ΛProlog是一种用于操作(有类型λ演算)函数的逻辑编程语言。
两年过去了,但我想对这个问题补充一点意见。最初,我问是否有任何方法来判断 (λx.2*x)是否等于 (λx.x+x)。Λ- 演算上的加法和乘法可以定义为:
(λx.2*x)
(λx.x+x)
add = (a b c -> (a b (a b c))) mul = (a b c -> (a (b c)))
现在,如果你将以下术语正常化:
add_x_x = (λx . (add x x)) mul_x_2 = (mul (λf x . (f (f x)))
你会得到:
result = (a b c -> (a b (a b c)))
两个项目都是。因为它们的规范形是相等的,所以两个程序显然是相等的。虽然这在一般情况下不起作用,但在实践中可以在很多方面起作用。例如,(λx.(mul 2 (mul 3 x))和 (λx.(mul 6 x))都具有相同的标准形式。
(λx.(mul 2 (mul 3 x))
(λx.(mul 6 x))
这在一般情况下是无法确定的,但是对于一个合适的子集,你确实可以今天使用 SMT 解决方案有效地做到这一点:
$ ghci GHCi, version 8.0.1: http://www.haskell.org/ghc/ :? for help Prelude> :m Data.SBV Prelude Data.SBV> (\x -> 2 * x) === (\x -> x + x :: SInteger) Q.E.D. Prelude Data.SBV> (\x -> 2 * x) === (\x -> 1 + x + x :: SInteger) Falsifiable. Counter-example: s0 = 0 :: Integer
有关详细信息,请参阅: https://hackage.haskell.org/package/sbv
在 Mathematica 这种有符号计算的语言中:
或者 C # 是 计算机代数库计算机代数库:
MathObject f(MathObject x) => x + x; MathObject g(MathObject x) => 2 * x; { var x = new Symbol("x"); Console.WriteLine(f(x) == g(x)); }
以上显示’真’在控制台。
证明两个函数相等在一般情况下是不可判定的,但是在你的问题中的特殊情况下,一个函数仍然可以证明函数相等。
这里有一个精益的样本证明
def foo : (λ x, 2 * x) = (λ x, x + x) := begin apply funext, intro x, cases x, { refl }, { simp, dsimp [has_mul.mul, nat.mul], have zz : ∀ a : nat, 0 + a = a := by simp, rw zz } end
可以在其他依赖类型的语言(如 Coq、 Agda、 Idris)中做同样的事情。
以上是一个战术风格的证明。生成的 foo(证明)的实际定义对于手写来说相当拗口:
foo
def foo : (λ (x : ℕ), 2 * x) = λ (x : ℕ), x + x := funext (λ (x : ℕ), nat.cases_on x (eq.refl (2 * 0)) (λ (a : ℕ), eq.mpr (id_locked ((λ (a a_1 : ℕ) (e_1 : a = a_1) (a_2 a_3 : ℕ) (e_2 : a_2 = a_3), congr (congr_arg eq e_1) e_2) (2 * nat.succ a) (nat.succ a * 2) (mul_comm 2 (nat.succ a)) (nat.succ a + nat.succ a) (nat.succ a + nat.succ a) (eq.refl (nat.succ a + nat.succ a)))) (id_locked (eq.mpr (id_locked (eq.rec (eq.refl (0 + nat.succ a + nat.succ a = nat.succ a + nat.succ a)) (eq.mpr (id_locked (eq.trans (forall_congr_eq (λ (a : ℕ), eq.trans ((λ (a a_1 : ℕ) (e_1 : a = a_1) (a_2 a_3 : ℕ) (e_2 : a_2 = a_3), congr (congr_arg eq e_1) e_2) (0 + a) a (zero_add a) a a (eq.refl a)) (propext (eq_self_iff_true a)))) (propext (implies_true_iff ℕ)))) trivial (nat.succ a)))) (eq.refl (nat.succ a + nat.succ a))))))