Gibt es eine Möglichkeit, zwei Funktionen auf Gleichheit zu vergleichen? Zum Beispiel (λx.2*x) == (λx.x+x)
sollte true zurückgegeben werden, da diese offensichtlich gleichwertig sind.
Gibt es eine Möglichkeit, zwei Funktionen auf Gleichheit zu vergleichen? Zum Beispiel (λx.2*x) == (λx.x+x)
sollte true zurückgegeben werden, da diese offensichtlich gleichwertig sind.
Antworten:
Es ist ziemlich bekannt, dass die allgemeine Funktionsgleichheit im Allgemeinen nicht zu entscheiden ist. Daher müssen Sie eine Teilmenge des Problems auswählen, an dem Sie interessiert sind. Sie können einige dieser Teillösungen in Betracht ziehen:
prove $ \(x::SInt32) -> 2*x .== x + x
Ergebnisse inQ.E.D.
Dies ist im Allgemeinen unentscheidbar, aber für eine geeignete Teilmenge können Sie dies heute tatsächlich effektiv mit SMT-Lösern tun:
$ 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
Weitere Informationen finden Sie unter: https://hackage.haskell.org/package/sbv
Lassen Sie uns zusätzlich zu den praktischen Beispielen in der anderen Antwort die Teilmenge der Funktionen auswählen, die in der typisierten Lambda-Rechnung ausgedrückt werden können. Wir können auch Produkt- und Summentypen zulassen. Obwohl die Überprüfung, ob zwei Funktionen gleich sind, so einfach sein kann, wie sie auf eine Variable anzuwenden und die Ergebnisse zu vergleichen , können wir die Gleichheitsfunktion nicht in der Programmiersprache selbst erstellen .
ETA: λProlog ist eine logische Programmiersprache zum Manipulieren von Funktionen (typisierter Lambda-Kalkül).
(\x -> 2*x) == (\x -> x*2)
?
2 Jahre sind vergangen, aber ich möchte dieser Frage eine kleine Bemerkung hinzufügen. Ursprünglich habe ich gefragt, ob es eine Möglichkeit gibt, festzustellen, ob dies (λx.2*x)
gleich ist (λx.x+x)
. Addition und Multiplikation auf dem λ-Kalkül können definiert werden als:
add = (a b c -> (a b (a b c)))
mul = (a b c -> (a (b c)))
Wenn Sie nun die folgenden Begriffe normalisieren:
add_x_x = (λx . (add x x))
mul_x_2 = (mul (λf x . (f (f x)))
Du erhältst:
result = (a b c -> (a b (a b c)))
Für beide Programme. Da ihre normalen Formen gleich sind, sind beide Programme offensichtlich gleich. Während dies im Allgemeinen nicht funktioniert, funktioniert es in der Praxis für viele Begriffe. (λx.(mul 2 (mul 3 x))
und (λx.(mul 6 x))
beide haben zum Beispiel die gleichen Normalformen.
In einer Sprache mit symbolischer Berechnung wie Mathematica:
Oder C # mit einer Computeralgebra-Bibliothek :
MathObject f(MathObject x) => x + x;
MathObject g(MathObject x) => 2 * x;
{
var x = new Symbol("x");
Console.WriteLine(f(x) == g(x));
}
Oben wird 'True' an der Konsole angezeigt.
(x \[Function] x + x) == (y \[Function] 2 y)
ist etwas, das es nicht einmal versucht.
Es ist im Allgemeinen unentscheidbar, zwei Funktionen als gleich zu beweisen, aber in besonderen Fällen wie in Ihrer Frage kann man immer noch die funktionale Gleichheit nachweisen.
Hier ist ein Beispielnachweis in Lean
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
Man kann dasselbe in einer anderen abhängig typisierten Sprache wie Coq, Agda, Idris tun.
Das Obige ist ein taktischer Stilbeweis. Die tatsächliche Definition von foo
(dem Beweis), der erzeugt wird, ist ein ziemlicher Bissen, der von Hand geschrieben werden muss:
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))))))