Sind ein paar hundert Reduktionsschritte zu viele, um die normale Form von Y fac ⌜3⌝ zu erhalten?

9

Da ich in letzter Zeit die Grundlagen des λ-Kalküls unterrichtet habe, habe ich in Common Lisp einen einfachen λ-Kalkül-Evaluator implementiert. Wenn ich nach der normalen Form der Y fac 3Reduktion in normaler Reihenfolge frage , dauert es 619 Schritte, was ein bisschen viel zu sein schien.

Natürlich habe ich jedes Mal, wenn ich ähnliche Reduzierungen auf Papier vorgenommen habe, nie den untypisierten λ-Kalkül verwendet, sondern Zahlen und Funktionen hinzugefügt, die damit arbeiten. In diesem Fall wird fac als solches definiert:

fac = λfac.λn.if (= n 0) 1 (* n (fac (- n 1)))

In diesem Fall, wenn man bedenkt =, *und -als currying Funktionen, es dauert nur etwa 50 Schritte , um Y fac 3zu seiner normalen Form 6.

In meinem Evaluator habe ich jedoch Folgendes verwendet:

true = λx.λy.x
false = λx.λy.y
⌜0⌝ = λf.λx.x
succ = λn.λf.λx.f n f x
⌜n+1⌝ = succ ⌜n⌝
zero? = λn.n (λx.false) true
mult = λm.λn.λf.m (n f)
pred = λn.λf.λx.n (λg.λh.h (g f)) (λu.x) (λu.u)
fac = λfac.λn.(zero? n) ⌜1⌝ (* n (fac (pred n)))
Y = λf.(λf.λx.f (x x)) f ((λf.λx.f (x x)) f)

In 619 Schritten komme ich von Y fac ⌜3⌝zur normalen Form von ⌜6⌝nämlich λf.λx.f (f (f (f (f (f x))))).

Nach einem kurzen Überfliegen der vielen Schritte ist es wohl die Definition pred, die eine so lange Reduzierung rechtfertigt, aber ich frage mich immer noch, ob es möglicherweise ein großer böser Fehler in meiner Implementierung ist ...

BEARBEITEN: Ich habe anfangs nach tausend Schritten gefragt, von denen einige tatsächlich eine falsche Implementierung der normalen Reihenfolge verursacht haben, also habe ich mich auf 2/3 der anfänglichen Anzahl von Schritten reduziert. Wie unten kommentiert, erhöht der Wechsel von Church zu Peano-Arithmetik bei meiner aktuellen Implementierung tatsächlich die Anzahl der Schritte…

Nirgendwo, Mann
quelle

Antworten:

11

Die Kodierung der Kirche ist wirklich schlecht, wenn Sie sie verwenden möchten pred. Ich würde Ihnen raten, eine effizientere Codierung im Peano-Stil zu verwenden:

// Arithmetik

: p_zero = λs.λz.z
: p_one = λs.λz.s p_zero
: p_succ = λn.λs.λz.sn
: p_null = λn.n (λx. ff) tt
: p_pred = λn.n (λp.p) p_zero
: p_plus = μ! f.λn.λm.n (λp. p_succ (! fpm)) m
: p_subs = μ! f.λn.λm.n (λp. p_pred (! fpm)) m
: p_eq = μ! f.λm.λn. m (λp. n (λq.! fpq) ff) (n (λx.ff) tt)
: p_mult = μ! f.λm.λn. m (λp. p_plus n (! fpn)) p_zero
: p_exp = μ! f.λm.λn. m (λp. p_mult n (! fpn)) p_one
: p_even = μ! f.λm. m (λp. nicht (! fp)) tt

// Zahlen

: p_0 = λs.λz.z
: p_1 = λs.λz.s p_0
: p_2 = λs.λz.s p_1
: p_3 = λs.λz.s p_2
...

Dies ist ein Code aus einer meiner alten Bibliotheken, der μ!f. …nur eine optimierte Konstruktion für war Y (λf. …). (Und tt, ff, notsind booleans.)

Ich bin mir nicht sicher, ob Sie dafür bessere Ergebnisse facerzielen würden.

Stéphane Gimenez
quelle
Vielen Dank für den Tipp. Durch die Arbeit mit dieser alternativen Codierung konnte ich einige Fehler in meiner Implementierung finden. Eigentlich hilft es nicht für die Anzahl der Schritte, denn nach dem Reparieren findet man die normale Form von 3! macht 619 Schritte mit Kirchenziffern und 687 mit Peano-Ziffern…
Nirgendwo Mann
Ja, das habe ich mir gedacht, weil die Verwendung einer speziellen Reduktionsregel für Yhier (insbesondere für Peano-Ziffern) entscheidend erscheint, um kurze Reduktionen zu erhalten.
Stéphane Gimenez
Nur neugierig, was ist mit 4!, 5!, 6! ?
Stéphane Gimenez
1
Seltsamerweise wird die Peano-Codierung nach 3! Effizienter als die Church-Codierung. Um die normale Form von jeweils 1!, 2!, 3!, 4! und 5! Mit Peano / Church sind die Schritte 10/10, 40/33, 157/134, 685/667, 3541/3956 und 21629/27311 erforderlich. Ungefähre Anzahl der Schritte für 6! Durch Interpolation aus den vorherigen Daten bleibt dem Leser eine Übung.
Nirgendwo Mann
1
Es scheint, dass die oben genannten genau die Scott-Ziffern "Peano + λ = Scott" sind. Etwas anderes, das es wert wäre, ausprobiert zu werden, sind ihre binären Varianten (sowohl für Church als auch für <strike> Peano </ strike> Scott).
Stéphane Gimenez
2

Wenn ich darüber nachdenke, wie viele Dinge eine CPU tut, um die Fakultät 3 zu berechnen, beispielsweise in Python, dann sind ein paar hundert Reduzierungen überhaupt keine große Sache.

Andrej Bauer
quelle