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…