mirror of
https://github.com/MartinThoma/LaTeX-examples.git
synced 2025-04-25 06:18:05 +02:00
196 lines
No EOL
7.3 KiB
TeX
196 lines
No EOL
7.3 KiB
TeX
%!TEX root = Programmierparadigmen.tex
|
|
\chapter{$\lambda$-Kalkül}
|
|
Der $\lambda$-Kalkül (gesprochen: Lambda-Kalkül) ist eine formale Sprache.
|
|
In diesem Kalkül gibt es drei Arten von Termen $T$:
|
|
|
|
\begin{itemize}
|
|
\item Variablen: $x$
|
|
\item Applikationen: $(T S)$
|
|
\item Lambda-Abstraktion: $\lambda x. T$
|
|
\end{itemize}
|
|
|
|
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:
|
|
|
|
\[a~b~c~d = ((a~b)~c)~d\]
|
|
|
|
\begin{definition}[Gebundene Variable]\xindex{Variable!gebundene}%
|
|
Eine Variable heißt gebunden, wenn sie der Parameter einer $\lambda$-Funktion ist.
|
|
\end{definition}
|
|
|
|
\begin{definition}[Freie Variable]\xindex{Variable!freie}%
|
|
Eine Variable heißt \textit{frei}, wenn sie nicht gebunden ist.
|
|
\end{definition}
|
|
|
|
\begin{satz}
|
|
Der untypisierte $\lambda$-Kalkül ist Turing-Äquivalent.
|
|
\end{satz}
|
|
|
|
\section{Reduktionen}\index{Reduktionen|(}
|
|
\begin{definition}[Redex]\xindex{Redex}%
|
|
Eine $\lambda$-Term der Form $(\lambda x. t_1) t_2$ heißt Redex.
|
|
\end{definition}
|
|
|
|
\begin{definition}[$\alpha$-Äquivalenz]
|
|
Zwei Terme $T_1, T_2$ heißen $\alpha$-Äquivalent, wenn $T_1$ durch
|
|
konsistente Umbenennung in $T_2$ überführt werden kann.
|
|
|
|
Man schreibt dann: $T_1 \overset{\alpha}{=} T_2$.
|
|
\end{definition}
|
|
|
|
\begin{beispiel}[$\alpha$-Äquivalenz]
|
|
\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*}
|
|
\end{beispiel}
|
|
|
|
\begin{definition}[$\beta$-Äquivalenz]
|
|
Eine $\beta$-Reduktion ist die Funktionsanwendung auf einen Redex:
|
|
\[(\lambda x. t_1) t_2 \Rightarrow t_1 [x \mapsto t_2]\]
|
|
\end{definition}
|
|
|
|
\begin{beispiel}[$\beta$-Äquivalenz]
|
|
\begin{defenum}
|
|
\item $(\lambda x.x) y \overset{\beta}{\Rightarrow} x[x \mapsto y] = y$
|
|
\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)$
|
|
\end{defenum}
|
|
\end{beispiel}
|
|
|
|
\begin{definition}[$\eta$-Äquivalenz]
|
|
Zwei Terme $\lambda x. f~x$ und $f$ heißen $\eta$-Äquivalent, wenn
|
|
$x$ nicht freie Variable von $f$ ist.
|
|
\end{definition}
|
|
|
|
\begin{beispiel}[$\eta$-Äquivalenz]
|
|
TODO
|
|
\end{beispiel}
|
|
\index{Reduktionen|)}
|
|
|
|
\section{Auswertungsstrategien}
|
|
\begin{definition}[Normalenreihenfolge]\xindex{Normalenreihenfolge}%
|
|
In der Normalenreihenfolge-Auswertungsstrategie wird der linkeste äußerste
|
|
Redex ausgewertet.
|
|
\end{definition}
|
|
|
|
\begin{definition}[Call-By-Name]\xindex{Call-By-Name}%
|
|
In der Call-By-Name Auswertungsreihenfolge wird der linkeste äußerste Redex
|
|
reduziert, der nicht von einem $\lambda$ umgeben ist.
|
|
\end{definition}
|
|
|
|
Die Call-By-Name Auswertung wird in Funktionen verwendet.
|
|
|
|
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.
|
|
|
|
\todo[inline]{Was ist sharing?}
|
|
|
|
\begin{definition}[Call-By-Value]\xindex{Call-By-Value}%
|
|
In der Call-By-Value Auswertung wird der linkeste Redex reduziert, der
|
|
nicht von einem $\lambda$ umgeben ist und dessen Argument ein Wert ist.
|
|
\end{definition}
|
|
|
|
Die Call-By-Value Auswertungsreihenfolge wird in C und Java verwendet.
|
|
Auch in Haskell werden arithmetische Ausdrücke in der Call-By-Name Auswertungsreihenfolge reduziert.
|
|
|
|
\section{Church-Zahlen}
|
|
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
|
|
Variable $z$ angewendet wird. Also:
|
|
\begin{itemize}
|
|
\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))$
|
|
\end{itemize}
|
|
|
|
Auch die gewohnten Operationen lassen sich so darstellen.
|
|
|
|
\begin{beispiel}[Nachfolger-Operation]
|
|
\begin{align*}
|
|
\succ :&= \lambda n f z. f (n f z)\\
|
|
&= \lambda n. (\lambda f (\lambda z f (n f z)))
|
|
\end{align*}
|
|
Dabei ist $n$ die Zahl.
|
|
|
|
Will man diese Funktion anwenden, sieht das wie folgt aus:
|
|
\begin{align*}
|
|
\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
|
|
\end{align*}
|
|
\end{beispiel}
|
|
|
|
\begin{beispiel}[Vorgänger-Operation]
|
|
\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}
|
|
\begin{beispiel}[Addition]
|
|
\begin{align*}
|
|
\text{plus} &:= \lambda m n f z. m f (n f z)
|
|
\end{align*}
|
|
Dabei ist $m$ der erste Summand und $n$ der zweite Summand.
|
|
\end{beispiel}
|
|
|
|
\begin{beispiel}[Multiplikation]
|
|
\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*}
|
|
Dabei ist $m$ der erste Faktor und $n$ der zweite Faktor.
|
|
\end{beispiel}
|
|
|
|
\begin{beispiel}[Potenz]
|
|
\begin{align*}
|
|
\text{exp} :&= \lambda b e. eb\\
|
|
&\overset{\eta}{=} \lambda b e f z. e b f z
|
|
\end{align*}
|
|
Dabei ist $b$ die Basis und $e$ der Exponent.
|
|
\end{beispiel}
|
|
|
|
\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}
|
|
|
|
\section{Weiteres}
|
|
\begin{satz}[Satz von Curch-Rosser]
|
|
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.
|
|
\end{satz} |