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 3
Reduktion 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 3
zu 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…