2014-03-02 18:02:13 +01:00
%!TEX root = Programmierparadigmen.tex
\chapter { $ \lambda $ -Kalkül}
2014-03-07 12:20:14 +01:00
Der $ \lambda $ -Kalkül (gesprochen: Lambda-Kalkül) ist eine formale Sprache.
2014-03-02 18:02:13 +01:00
In diesem Kalkül gibt es drei Arten von Termen $ T $ :
\begin { itemize}
2014-03-07 12:20:14 +01:00
\item Variablen: $ x $
\item Applikationen: $ ( T S ) $
\item Lambda-Abstraktion: $ \lambda x. T $
2014-03-02 18:02:13 +01:00
\end { itemize}
2014-03-07 12:20:14 +01:00
In der Lambda-Abstraktion nennt man den Teil vor dem Punkt die \textit { Parameter}
der $ \lambda $ -Funktion. Wenn etwas dannach kommt, auf die die Funktion angewendet
wird so heißt dieser Teil das \textit { Argument} :
\[ ( \lambda \underbrace { x } _ { \mathclap { \text { Parameter } } } . x ^ 2 ) \overbrace { 5 } ^ { \mathclap { \text { Argument } } } = 5 ^ 2 \]
\begin { beispiel} [$ \lambda $ -Funktionen]
\begin { bspenum}
\item $ \lambda x. x $ heißt Identität.
\item $ ( \lambda x. x ^ 2 ) ( \lambda y. y + 3 ) = \lambda y. ( y + 3 ) ^ 2 $
\item \label { bsp:lambda-3} $ \begin { aligned } [ t ]
& (\lambda x.\Big (\lambda y.yx \Big ))~ab\\
\Rightarrow & (\lambda y.ya)b\\
\Rightarrow & ba
\end { aligned} $
\end { bspenum}
In \cref { bsp:lambda-3} sieht man, dass $ \lambda $ -Funktionen die Argumente
von Links nach rechts einziehen.
\end { beispiel}
Die Funktionsapplikation sei linksassoziativ. Es gilt also:
2014-03-02 18:02:13 +01:00
\[ a~b~c~d = ( ( a~b ) ~c ) ~d \]
2014-03-07 12:20:14 +01:00
\begin { definition} [Gebundene Variable]\xindex { Variable!gebundene} %
Eine Variable heißt gebunden, wenn sie der Parameter einer $ \lambda $ -Funktion ist.
2014-03-02 18:02:13 +01:00
\end { definition}
2014-03-07 12:20:14 +01:00
\begin { definition} [Freie Variable]\xindex { Variable!freie} %
Eine Variable heißt \textit { frei} , wenn sie nicht gebunden ist.
2014-03-02 18:02:13 +01:00
\end { definition}
2014-03-07 12:20:14 +01:00
\begin { satz}
Der untypisierte $ \lambda $ -Kalkül ist Turing-Äquivalent.
\end { satz}
2014-03-20 13:42:52 +01:00
\section { Reduktionen} \index { Reduktion|(}
2014-03-08 14:05:57 +01:00
\begin { definition} [Redex]\xindex { Redex} %
Eine $ \lambda $ -Term der Form $ ( \lambda x. t _ 1 ) t _ 2 $ heißt Redex.
\end { definition}
2014-03-20 13:42:52 +01:00
\begin { definition} [$ \alpha $ -Äquivalenz]\xindex { Reduktion!Alpha ($ \alpha $ )} \xindex { Äquivalenz!Alpha ($ \alpha $ )} %
2014-03-07 12:20:14 +01:00
Zwei Terme $ T _ 1 , T _ 2 $ heißen $ \alpha $ -Äquivalent, wenn $ T _ 1 $ durch
konsistente Umbenennung in $ T _ 2 $ überführt werden kann.
2014-03-02 18:02:13 +01:00
2014-03-07 12:20:14 +01:00
Man schreibt dann: $ T _ 1 \overset { \alpha } { = } T _ 2 $ .
2014-03-02 18:02:13 +01:00
\end { definition}
\begin { beispiel} [$ \alpha $ -Äquivalenz]
2014-03-07 12:20:14 +01:00
\begin { align*}
\lambda x.x & \overset { \alpha } { =} \lambda y. y\\
\lambda x. x x & \overset { \alpha } { =} \lambda y. y y\\
\lambda x. (\lambda y. z (\lambda x. z y) y) & \overset { \alpha } { =}
\lambda a. (\lambda x. z (\lambda c. z x) x)
\end { align*}
2014-03-02 18:02:13 +01:00
\end { beispiel}
2014-03-20 13:42:52 +01:00
\begin { definition} [$ \beta $ -Äquivalenz]\xindex { Reduktion!Beta ($ \beta $ )} \xindex { Äquivalenz!Beta ($ \beta $ )} %
2014-03-08 14:05:57 +01:00
Eine $ \beta $ -Reduktion ist die Funktionsanwendung auf einen Redex:
2014-03-23 19:28:44 +01:00
\[ ( \lambda x. t _ 1 ) \ t _ 2 \Rightarrow t _ 1 [ x \mapsto t _ 2 ] \]
2014-03-02 18:02:13 +01:00
\end { definition}
\begin { beispiel} [$ \beta $ -Äquivalenz]
2014-03-08 14:05:57 +01:00
\begin { defenum}
2014-03-23 19:28:44 +01:00
\item $ ( \lambda x. \ x ) \ y \overset { \beta } { \Rightarrow } x [ x \mapsto y ] = y $
2014-04-05 18:31:51 +02:00
\item $ ( \lambda x. \ x \ ( \lambda x. \ x ) ) ( y \ z ) \overset { \beta } { \Rightarrow } ( x \ ( \lambda x. \ x ) ) [ x \mapsto y \ z ] = ( y \ z ) ( \lambda x. \ x ) $
2014-03-08 14:05:57 +01:00
\end { defenum}
2014-03-02 18:02:13 +01:00
\end { beispiel}
2014-03-23 19:28:44 +01:00
\begin { definition} [$ \eta $ -Äquivalenz\footnote { Folie 158} ]\xindex { Reduktion!Eta ($ \eta $ )} \xindex { Äquivalenz!Eta ($ \eta $ )} %
Die Terme $ \lambda x. f~x $ und $ f $ heißen $ \eta $ -Äquivalent, wenn $ x \notin FV ( f ) $ gilt.
Man schreibt: $ \lambda x. f~x \overset { \eta } { = } f $ .
2014-03-02 18:02:13 +01:00
\end { definition}
2014-03-23 19:28:44 +01:00
\begin { beispiel} [$ \eta $ -Äquivalenz\footnote { Folie 158} ]%
\begin { align*}
\lambda x.\ \lambda y.\ f\ z\ x\ y & \overset { \eta } { =} \lambda x.\ f\ z\ x\\
f\ z & \overset { \eta } { =} \lambda x.\ f\ z\ x\\
\lambda x.\ x & \overset { \eta } { =} \lambda x.\ (\lambda x.\ x)\ x\\
\lambda x.\ f\ x\ x & \overset { \eta } { \neq } f\ x
\end { align*}
2014-03-02 18:02:13 +01:00
\end { beispiel}
2014-03-20 13:42:52 +01:00
\index { Reduktion|)}
2014-03-02 18:02:13 +01:00
\section { Auswertungsstrategien}
\begin { definition} [Normalenreihenfolge]\xindex { Normalenreihenfolge} %
2014-03-07 12:20:14 +01:00
In der Normalenreihenfolge-Auswertungsstrategie wird der linkeste äußerste
Redex ausgewertet.
2014-03-02 18:02:13 +01:00
\end { definition}
\begin { definition} [Call-By-Name]\xindex { Call-By-Name} %
2014-03-07 12:20:14 +01:00
In der Call-By-Name Auswertungsreihenfolge wird der linkeste äußerste Redex
reduziert, der nicht von einem $ \lambda $ umgeben ist.
2014-03-02 18:02:13 +01:00
\end { definition}
Die Call-By-Name Auswertung wird in Funktionen verwendet.
2014-03-18 15:45:40 +01:00
Haskell verwendet die Call-By-Name Auswertungsreihenfolge zusammen mit \enquote { sharing} . Dies nennt man \textit { Lazy Evaluation} . Ein spezialfall der Lazy-Evaluation ist die sog. \textit { Kurzschlussauswertung} .\xindex { Kurzschlussauswertung} \xindex { Short-circuit evaluation}
Das bezeichnet die Lazy-Evaluation von booleschen Ausdrücken.
2014-04-05 18:18:47 +02:00
\todo [inline] { Was ist sharing? Vermutlich so etwas wie in folgendem Beispiel:}
\begin { beispiel} [Sharing]
In dem Ausdruck \texttt { (plus, (fac, 42), (fac, 42))} muss der Teilausdruck
\texttt { (fac, 42)} nicht zwei mal ausgewertet werden, wenn er Seiteneffektfrei
ist.
\end { beispiel}
2014-03-09 16:38:27 +01:00
2014-03-02 18:02:13 +01:00
\begin { definition} [Call-By-Value]\xindex { Call-By-Value} %
2014-03-07 12:20:14 +01:00
In der Call-By-Value Auswertung wird der linkeste Redex reduziert, der
nicht von einem $ \lambda $ umgeben ist und dessen Argument ein Wert ist.
2014-03-02 18:02:13 +01:00
\end { definition}
Die Call-By-Value Auswertungsreihenfolge wird in C und Java verwendet.
2014-03-09 16:38:27 +01:00
Auch in Haskell werden arithmetische Ausdrücke in der Call-By-Name Auswertungsreihenfolge reduziert.
2014-03-02 18:02:13 +01:00
\section { Church-Zahlen}
2014-03-07 12:20:14 +01:00
Im $ \lambda $ -Kalkül lässt sich jeder mathematische Ausdruck darstellen, also
insbesondere beispielsweise auch $ \lambda x. x + 3 $ . Aber \enquote { $ 3 $ } und
\enquote { $ + $ } ist hier noch nicht das $ \lambda $ -Kalkül.
Zuerst müssen wir uns also Gedanken machen, wie man natürliche Zahlen $ n \in \mdn $
darstellt. Dafür dürfen wir nur Variablen und $ \lambda $ verwenden. Eine Möglichkeit
das zu machen sind die sog. \textit { Church-Zahlen} .
Dabei ist die Idee, dass die Zahl angibt wie häufig eine Funktion $ f $ auf eine
2014-03-09 16:38:27 +01:00
Variable $ z $ angewendet wird. Also:
2014-03-07 12:20:14 +01:00
\begin { itemize}
2014-03-09 16:38:27 +01:00
\item $ 0 : = \lambda f~z. z $
\item $ 1 : = \lambda f~z. f z $
\item $ 2 : = \lambda f~z. f ( f z ) $
\item $ 3 : = \lambda f~z. f ( f ( f z ) ) $
2014-03-07 12:20:14 +01:00
\end { itemize}
Auch die gewohnten Operationen lassen sich so darstellen.
\begin { beispiel} [Nachfolger-Operation]
\begin { align*}
2014-03-09 16:38:27 +01:00
\succ :& = \lambda n f z. f (n f z)\\
& = \lambda n. (\lambda f (\lambda z f (n f z)))
2014-03-07 12:20:14 +01:00
\end { align*}
Dabei ist $ n $ die Zahl.
Will man diese Funktion anwenden, sieht das wie folgt aus:
\begin { align*}
2014-03-09 16:38:27 +01:00
\succ 1& = (\lambda n f z. f(n f z)) 1\\
& = (\lambda n f z. f(n f z)) \underbrace { (\lambda f~z. f z)} _ { n} \\
& = \lambda f z. f (\lambda f~z. f z) f z\\
& = \lambda f z. f (f z)\\
& = 2
2014-03-07 12:20:14 +01:00
\end { align*}
\end { beispiel}
2014-09-13 17:28:03 +02:00
\begin { beispiel} [Vorgänger-Operation]\xindex { pred} \xindex { pair} \xindex { next} \xindex { fst} \xindex { snd}
2014-03-09 19:06:23 +01:00
\begin { align*}
\pair & := \lambda a. \lambda b. \lambda f. f a b\\
\fst & := \lambda p. p (\lambda a. \lambda b. a)\\
\snd & := \lambda p. p (\lambda a. \lambda b. b)\\
\nxt & := \lambda p. \pair (\snd p)~(\succ (\snd p))\\
\pred & := \lambda n. \fst (n \nxt (\pair c_ 0 c_ 0))
\end { align*}
\end { beispiel}
2014-03-07 12:20:14 +01:00
\begin { beispiel} [Addition]
\begin { align*}
2014-03-09 16:38:27 +01:00
\text { plus} & := \lambda m n f z. m f (n f z)
2014-03-07 12:20:14 +01:00
\end { align*}
Dabei ist $ m $ der erste Summand und $ n $ der zweite Summand.
\end { beispiel}
\begin { beispiel} [Multiplikation]
2014-03-09 16:38:27 +01:00
\begin { align*}
\text { times} :& = \lambda m n f. m~s~(n~f~z)\\
& \overset { \eta } { =} \lambda m n f z. n (m s) z
\end { align*}
2014-03-07 12:20:14 +01:00
Dabei ist $ m $ der erste Faktor und $ n $ der zweite Faktor.
\end { beispiel}
\begin { beispiel} [Potenz]
2014-03-09 16:38:27 +01:00
\begin { align*}
\text { exp} :& = \lambda b e. eb\\
& \overset { \eta } { =} \lambda b e f z. e b f z
\end { align*}
2014-03-07 12:20:14 +01:00
Dabei ist $ b $ die Basis und $ e $ der Exponent.
\end { beispiel}
2014-03-02 18:02:13 +01:00
2014-03-09 16:38:27 +01:00
\section { Church-Booleans}
\begin { definition} [Church-Booleans]\xindex { Church-Booleans} %
\texttt { True} wird zu $ c _ { \text { true } } : = \lambda t. \lambda f. t $ .\\
\texttt { False} wird zu $ c _ { \text { false } } : = \lambda t. \lambda f. f $ .
\end { definition}
2014-03-02 18:02:13 +01:00
2014-03-20 15:18:50 +01:00
Hiermit lässt sich beispielsweise die Funktion \texttt { is\_ zero} definieren, die
\texttt { True} zurückgibt, wenn eine Zahl $ 0 $ repräsentiert und sonst \texttt { False}
zurückgibt:
\[ \text { \texttt { is \_ zero } } = \lambda n. \ n \ ( \lambda x. \ c _ { \text { False } } ) \ c _ { \text { True } } \]
2014-03-09 16:38:27 +01:00
\section { Weiteres}
2014-03-02 18:02:13 +01:00
\begin { satz} [Satz von Curch-Rosser]
2014-03-07 12:20:14 +01:00
Wenn zwei unterschiedliche Terme $ a $ und $ b $ äquivalent sind, d.h. mit Reduktionsschritten beliebiger Richtung ineinander transformiert werden können, dann gibt es einen weiteren Term $ c $ , zu dem sowohl $ a $ als auch $ b $ reduziert werden können.
2014-03-20 13:42:52 +01:00
\end { satz}
\section { Fixpunktkombinator}
\begin { definition} [Fixpunkt]\xindex { Fixpunkt} %
Sei $ f: X \rightarrow Y $ eine Funktion mit $ \emptyset \neq A = X \cap Y $ und
$ a \in A $ .
$ a $ heißt \textbf { Fixpunkt} der Funktion $ f $ , wenn $ f ( a ) = a $ gilt.
\end { definition}
\begin { beispiel} [Fixpunkt]
\begin { bspenum}
\item $ f _ 1 : \mdr \rightarrow \mdr ; f ( x ) = x ^ 2 \Rightarrow x _ 1 = 0 $ ist
Fixpunkt von $ f $ , da $ f ( 0 ) = 0 $ . $ x _ 2 = 1 $ ist der einzige weitere
Fixpunkt dieser Funktion.
\item $ f _ 2 : \mdn \rightarrow \mdn $ hat ganz $ \mdn $ als Fixpunkte, also
insbesondere unendlich viele Fixpunkte.
\item $ f _ 3 : \mdr \rightarrow \mdr ; f ( x ) = x + 1 $ hat keinen einzigen Fixpunkt.
\item $ f _ 4 : \mdr [ X ] \rightarrow \mdr [ X ] ; f ( p ) = p ^ 2 $ hat $ p _ 1 ( x ) = 0 $ und
$ p _ 2 ( x ) = 1 $ als Fixpunkte.
\end { bspenum}
\end { beispiel}
\begin { definition} [Kombinator]\xindex { Kombinator} %
Ein Kombinator ist eine Abbildung ohne freie Variablen.
\end { definition}
\begin { beispiel} [Kombinatoren\footnotemark ]%
2014-09-13 17:28:03 +02:00
Folgende $ \lambda $ -Funktionen sind Beispiele für Kombinatoren:
2014-03-20 13:42:52 +01:00
\begin { bspenum}
\item $ \lambda a. \ a $
\item $ \lambda a. \ \lambda b. \ a $
\item $ \lambda f. \ \lambda a. \ \lambda b. f \ b \ a $
2014-09-13 17:28:03 +02:00
\item $ \lambda x. \ \lambda y. \ x $ \\
Diese $ \lambda $ -Funktion hat nur die gebundene Variable $ x $ , also
ist es ein Kombinator.
\end { bspenum}
Folgende $ \lambda $ -Funktionen sind keine Kombinatoren:
\begin { bspenum}
\item $ \lambda x. \ y $
\item $ x \ \lambda y. \ y $ \\
Der Gesamtausdruck ist kein $ \lambda $ -Ausdruck, also ist es auch
kein Kombinator. Außerdem ist $ x $ eine freie Variable.
\item $ ( \lambda x. \ x ) \ y $ \\
Der Ausdruck ist kein $ \lambda $ -Ausdruck, sondern eine
Funktionsanwendung. Also ist es kein Kombinator.
2014-03-20 13:42:52 +01:00
\end { bspenum}
\end { beispiel}
\footnotetext { Quelle: \url { http://www.haskell.org/haskellwiki/Combinator} }
\begin { definition} [Fixpunkt-Kombinator]\xindex { Fixpunkt-Kombinator} %
Sei $ f $ ein Kombinator, der $ f \ g = g \ ( f \ g ) $ erfüllt. Dann heißt $ f $
\textbf { Fixpunktkombinator} .
\end { definition}
Insbesondere ist also $ f \ g $ ein Fixpunkt von $ g $ .
\begin { definition} [Y-Kombinator]\xindex { Y-Kombinator} %
Der Fixpunktkombinator
\[ Y : = \lambda f. \ ( \lambda x. \ f \ ( x \ x ) ) \ ( \lambda x. \ f \ ( x \ x ) ) \]
heißt $ Y $ -Kombinator.
\end { definition}
2014-09-13 17:28:03 +02:00
Der Y-Kombinator hat einen Paramter. Er nimmt eine nicht-rekursive Funktion
und gibt eine rekursive zurück.
2014-03-20 13:42:52 +01:00
\begin { behauptung}
Der $ Y $ -Kombinator ist ein Fixpunktkombinator.
\end { behauptung}
\begin { beweis} \footnote { Quelle: Vorlesung WS 2013/2014, Folie 175} \leavevmode
\textbf { Teil 1:} Offensichtlich ist $ Y $ ein Kombinator.
\textbf { Teil 2:} z.~Z.: $ Y f \Rightarrow ^ * f \ ( Y \ f ) $
\begin { align*}
Y\ f & =\hphantom { ^ \beta f\ } (\lambda f.\ (\lambda x.\ f\ (x\ x))\ (\lambda x.\ f\ (x\ x)))\ f\\
& \Rightarrow ^ \beta \hphantom { f \ (\lambda f.\ } (\lambda x. f\ (x\ x))\ (\lambda x.\ f\ (x\ x))\\
& \Rightarrow ^ \beta f \ (\hphantom { \lambda f.\ } (\lambda x.\ f\ (x\ x))\ (\lambda x.\ f\ (x\ x)))\\
& \Rightarrow ^ \beta f \ (\lambda f.\ (\lambda x.\ f\ (x\ x))\ (\lambda x.\ f\ (x\ x))\ f)\\
& =\hphantom { ^ \beta } f \ (Y \ f)
\end { align*}
$ \qed $
\end { beweis}
\begin { definition} [Turingkombinator]\xindex { Turingkombinator} %
Der Fixpunktkombinator
\[ \Theta : = ( \lambda x. \lambda y. y \ ( x \ x \ y ) ) ( \lambda x. \ \lambda y. \ y \ ( x \ x \ y ) ) \]
heißt \textbf { Turingkombinator} .
\end { definition}
\begin { behauptung}
Der Turing-Kombinator $ \Theta $ ist ein Fixpunktkombinator.
\end { behauptung}
\begin { beweis} \footnote { Quelle: Übungsblatt 6, WS 2013/2014}
\textbf { Teil 1:} Offensichtlich ist $ \Theta $ ein Kombinator.
\textbf { Teil 2:} z.~Z.: $ \Theta f \Rightarrow ^ * f \ ( \Theta \ f ) $
Sei $ \Theta _ 0 : = ( \lambda x. \ \lambda y. \ y \ ( x \ x \ y ) ) $ . Dann gilt:
\begin { align*}
\Theta \ f & = ((\lambda x.\ \lambda y.\ y\ (x\ x\ y))\ \Theta _ 0)\ f\\
& \Rightarrow ^ \beta (\lambda y. y\ (\Theta _ 0 \ \Theta _ 0 \ y))\ f\\
& \Rightarrow ^ \beta f \ (\Theta _ 0 \Theta _ 0 f)\\
& = f \ (\Theta \ f)
\end { align*}
$ \qed $
\end { beweis}
2014-03-23 19:28:44 +01:00
\section { Literatur}
\begin { itemize}
\item \url { http://c2.com/cgi/wiki?FreeVariable}
\item \url { http://www.lambda-bound.com/book/lambdacalc/node9.html}
2014-09-13 17:28:03 +02:00
\item \url { http://mvanier.livejournal.com/2897.html}
2014-03-23 19:28:44 +01:00
\end { itemize}