Anonyme Rekursion
Ein Festkommakombinator ist eine Funktion höherer Ordnung fix
, die per Definition die Äquivalenz erfüllt
forall f. fix f = f (fix f)
fix f
stellt eine Lösung x
für die Festpunktgleichung dar
x = f x
Die Fakultät einer natürlichen Zahl kann durch bewiesen werden
fact 0 = 1
fact n = n * fact (n - 1)
Unter Verwendung fix
beliebiger konstruktiver Beweise über allgemeine / μ-rekursive Funktionen können ohne nonymöse Selbstreferenzialität abgeleitet werden.
fact n = (fix fact') n
wo
fact' rec n = if n == 0
then 1
else n * rec (n - 1)
so dass
fact 3
= (fix fact') 3
= fact' (fix fact') 3
= if 3 == 0 then 1 else 3 * (fix fact') (3 - 1)
= 3 * (fix fact') 2
= 3 * fact' (fix fact') 2
= 3 * if 2 == 0 then 1 else 2 * (fix fact') (2 - 1)
= 3 * 2 * (fix fact') 1
= 3 * 2 * fact' (fix fact') 1
= 3 * 2 * if 1 == 0 then 1 else 1 * (fix fact') (1 - 1)
= 3 * 2 * 1 * (fix fact') 0
= 3 * 2 * 1 * fact' (fix fact') 0
= 3 * 2 * 1 * if 0 == 0 then 1 else 0 * (fix fact') (0 - 1)
= 3 * 2 * 1 * 1
= 6
Dieser formale Beweis dafür
fact 3 = 6
Verwendet methodisch die Äquivalenz des Festkomma-Kombinators für das Umschreiben
fix fact' -> fact' (fix fact')
Lambda-Kalkül
Der untypisierte Lambda-Kalkül- Formalismus besteht aus einer kontextfreien Grammatik
E ::= v Variable
| λ v. E Abstraction
| E E Application
wo v
erstreckt sich über Variablen zusammen mit den Beta und eta Reduktion Regeln
(λ x. B) E -> B[x := E] Beta
λ x. E x -> E if x doesn’t occur free in E Eta
Die Beta-Reduktion ersetzt alle freien Vorkommen der Variablen x
im Abstraktionskörper ("Funktion") B
durch den Ausdruck ("Argument") E
. Eta-Reduktion eliminiert redundante Abstraktion. Es wird manchmal aus dem Formalismus weggelassen. Ein irreduzibler Ausdruck, für den keine Reduktionsregel gilt, liegt in normaler oder kanonischer Form vor .
λ x y. E
ist eine Abkürzung für
λ x. λ y. E
(Abstraktionsmultiarität),
E F G
ist eine Abkürzung für
(E F) G
(Anwendung Linksassoziativität),
λ x. x
und
λ y. y
sind Alpha-Äquivalent .
Abstraktion und Anwendung sind die beiden einzigen „Sprachprimitive“ des Lambda-Kalküls, ermöglichen jedoch die Codierung beliebig komplexer Daten und Operationen.
Die Kirchenzahlen sind eine Kodierung der natürlichen Zahlen, die den peanoaxiomatischen Naturzahlen ähnlich sind.
0 = λ f x. x No application
1 = λ f x. f x One application
2 = λ f x. f (f x) Twofold
3 = λ f x. f (f (f x)) Threefold
. . .
SUCC = λ n f x. f (n f x) Successor
ADD = λ n m f x. n f (m f x) Addition
MULT = λ n m f x. n (m f) x Multiplication
. . .
Ein formeller Beweis dafür
1 + 2 = 3
Verwenden der Umschreiberegel der Beta-Reduzierung:
ADD 1 2
= (λ n m f x. n f (m f x)) (λ g y. g y) (λ h z. h (h z))
= (λ m f x. (λ g y. g y) f (m f x)) (λ h z. h (h z))
= (λ m f x. (λ y. f y) (m f x)) (λ h z. h (h z))
= (λ m f x. f (m f x)) (λ h z. h (h z))
= λ f x. f ((λ h z. h (h z)) f x)
= λ f x. f ((λ z. f (f z)) x)
= λ f x. f (f (f x)) Normal form
= 3
Kombinatoren
In der Lambda-Rechnung sind Kombinatoren Abstraktionen, die keine freien Variablen enthalten. Am einfachsten: I
der Identitätskombinator
λ x. x
isomorph zur Identitätsfunktion
id x = x
Solche Kombinatoren sind die primitiven Operatoren von Kombinatorkalkülen wie dem SKI-System.
S = λ x y z. x z (y z)
K = λ x y. x
I = λ x. x
Die Beta-Reduktion normalisiert sich nicht stark . Nicht alle reduzierbaren Ausdrücke, „Redexes“, konvergieren unter Beta-Reduktion zur normalen Form. Ein einfaches Beispiel ist die unterschiedliche Anwendung des Omega- ω
Kombinators
λ x. x x
zu sich selbst:
(λ x. x x) (λ y. y y)
= (λ y. y y) (λ y. y y)
. . .
= _|_ Bottom
Die Reduzierung der am weitesten links stehenden Unterausdrücke („Köpfe“) wird priorisiert. Die anwendbare Reihenfolge normalisiert die Argumente vor der Substitution, die normale Reihenfolge nicht. Die beiden Strategien sind analog zu eifriger Bewertung, z. B. C, und fauler Bewertung, z. B. Haskell.
K (I a) (ω ω)
= (λ k l. k) ((λ i. i) a) ((λ x. x x) (λ y. y y))
divergiert unter eifriger Beta-Reduktion in der Anwendungsreihenfolge
= (λ k l. k) a ((λ x. x x) (λ y. y y))
= (λ l. a) ((λ x. x x) (λ y. y y))
= (λ l. a) ((λ y. y y) (λ y. y y))
. . .
= _|_
da in strengen Semantik
forall f. f _|_ = _|_
konvergiert aber unter fauler Beta-Reduktion normaler Ordnung
= (λ l. ((λ i. i) a)) ((λ x. x x) (λ y. y y))
= (λ l. a) ((λ x. x x) (λ y. y y))
= a
Wenn ein Ausdruck eine normale Form hat, wird er durch eine Beta-Reduktion normaler Ordnung gefunden.
Y.
Die wesentliche Eigenschaft des Y
Festkommakombinators
λ f. (λ x. f (x x)) (λ x. f (x x))
ist gegeben durch
Y g
= (λ f. (λ x. f (x x)) (λ x. f (x x))) g
= (λ x. g (x x)) (λ x. g (x x)) = Y g
= g ((λ x. g (x x)) (λ x. g (x x))) = g (Y g)
= g (g ((λ x. g (x x)) (λ x. g (x x)))) = g (g (Y g))
. . . . . .
Die Äquivalenz
Y g = g (Y g)
ist isomorph zu
fix f = f (fix f)
Der untypisierte Lambda-Kalkül kann beliebige konstruktive Beweise über allgemeine / μ-rekursive Funktionen codieren.
FACT = λ n. Y FACT' n
FACT' = λ rec n. if n == 0 then 1 else n * rec (n - 1)
FACT 3
= (λ n. Y FACT' n) 3
= Y FACT' 3
= FACT' (Y FACT') 3
= if 3 == 0 then 1 else 3 * (Y FACT') (3 - 1)
= 3 * (Y FACT') (3 - 1)
= 3 * FACT' (Y FACT') 2
= 3 * if 2 == 0 then 1 else 2 * (Y FACT') (2 - 1)
= 3 * 2 * (Y FACT') 1
= 3 * 2 * FACT' (Y FACT') 1
= 3 * 2 * if 1 == 0 then 1 else 1 * (Y FACT') (1 - 1)
= 3 * 2 * 1 * (Y FACT') 0
= 3 * 2 * 1 * FACT' (Y FACT') 0
= 3 * 2 * 1 * if 0 == 0 then 1 else 0 * (Y FACT') (0 - 1)
= 3 * 2 * 1 * 1
= 6
(Multiplikation verzögert, Zusammenfluss)
Für den kirchlichen untypisierten Lambda-Kalkül wurde gezeigt, dass es außerdem eine rekursiv aufzählbare Unendlichkeit von Festpunktkombinatoren gibt Y
.
X = λ f. (λ x. x x) (λ x. f (x x))
Y' = (λ x y. x y x) (λ y x. y (x y x))
Z = λ f. (λ x. f (λ v. x x v)) (λ x. f (λ v. x x v))
Θ = (λ x y. y (x x y)) (λ x y. y (x x y))
. . .
Die Beta-Reduktion normaler Ordnung macht den nicht erweiterten untypisierten Lambda-Kalkül zu einem Turing-vollständigen Umschreibungssystem.
In Haskell kann der Festkomma-Kombinator elegant implementiert werden
fix :: forall t. (t -> t) -> t
fix f = f (fix f)
Haskells Faulheit normalisiert sich auf eine Endlichkeit, bevor alle Unterausdrücke ausgewertet wurden.
primes :: Integral t => [t]
primes = sieve [2 ..]
where
sieve = fix (\ rec (p : ns) ->
p : rec [n | n <- ns
, n `rem` p /= 0])