2014-03-02 19:35:37 +01:00
%!TEX root = Programmierparadigmen.tex
\chapter { Typinferenz}
\begin { definition} [Datentyp]\index { Typ|see{ Datentyp} } \xindex { Datentyp} %
Ein \textit { Datentyp} oder kurz \textit { Typ} ist eine Menge von Werten, mit
denen eine Bedeutung verbunden ist.
\end { definition}
\begin { beispiel} [Datentypen]
\begin { itemize}
\item $ \text { \texttt { bool } } = \Set { \text { True } , \text { False } } $
\item $ \text { \texttt { char } } = \text { vgl. \cpageref { sec:ascii - tabelle } } $
\item $ \text { \texttt { int } } _ { \text { Haskell } } = [ - 2 ^ { 29 } , 2 ^ { 29 } - 1 ] \cap \mathbb { N } $
\item $ \text { \texttt { int } } _ { \text { C 90 } } = [ - 2 ^ { 15 } - 1 , 2 ^ { 15 } - 1 ] \cap \mathbb { N } $ \footnote { siehe ISO/IEC 9899:TC2, Kapitel 7.10: Sizes of integer types <limits.h>}
\item \texttt { float} = siehe IEEE 754
\item Funktionstypen, z.~B. $ \text { \texttt { int } } \rightarrow \text { \texttt { int } } $ oder
$ \text { \texttt { char } } \rightarrow \text { \texttt { int } } $
\end { itemize}
\end { beispiel}
\underline { Hinweis:} Typen sind unabhängig von ihrer Repräsentation. So kann ein
\texttt { bool} durch ein einzelnes Bit repräsentiert werden oder eine Bitfolge
zugrunde liegen.
Auf Typen sind Operationen definiert. So kann man auf numerischen Typen eine
Addition (+), eine Subtraktion (-), eine Multiplikation (*) und eine Division (/)
definieren.\\
Ich schreibe hier bewusst \enquote { eine} Multiplikation und nicht \enquote { die}
Multiplikation, da es verschiedene Möglichkeiten gibt auf Gleitpunktzahlen
Multiplikationen zu definieren. So kann man beispielsweise die Assoziativität
unterschiedlich wählen.
\begin { beispiel} [Multiplikation ist nicht assoziativ]
In Python 3 ist die Multiplikation linksassoziativ. Also:
\inputminted [numbersep=5pt, tabsize=4] { python} { scripts/python/multiplikation.py}
\end { beispiel}
\begin { definition} [Typvariable]\xindex { Typvariable} %
Eine Typvariable repräsentiert einen Typen.
\end { definition}
\underline { Hinweis:} Üblicherweise werden kleine griechische Buchstaben ($ \alpha , \beta , \tau _ 1 , \tau _ 2 , \dots $ ) als Typvariablen gewählt.
Genau wie Typen bestimmte Operationen haben, die auf ihnen definiert sind,
kann man sagen, dass Operationen bestimmte Typen, auf die diese Anwendbar sind. So ist
\[ \alpha + \beta \]
für numerische $ \alpha $ und $ \beta $ wohldefiniert, auch wenn $ \alpha $ und $ \beta $ boolesch sind
oder beides Strings sind könnte das Sinn machen. Es macht jedoch z.~B. keinen Sinn,
wenn $ \alpha $ ein String ist und $ \beta $ boolesch.
Die Menge aller Operationen, die auf die Variablen angewendet werden, nennt man
\textbf { Typkontext} \xindex { Typkontext} . Dieser wird üblicherweise mit $ \Gamma $
bezeichnet.
Das Ableiten einer Typisierung für einen Ausdruck nennt man \textbf { Typinferenz} \xindex { Typinferenz} .
Man schreibt: $ \vdash ( \lambda x. 2 ) : \alpha \rightarrow \text { int } $ .
Bei solchen Ableitungen sind häufig viele Typen möglich. So kann der Ausdruck
\[ \lambda x. 2 \]
Mit folgenderweise typisiert werden:
\begin { itemize}
\item $ \vdash ( \lambda x. 2 ) : \text { bool } \rightarrow int $
\item $ \vdash ( \lambda x. 2 ) : \text { int } \rightarrow int $
\item $ \vdash ( \lambda x. 2 ) : \text { Char } \rightarrow int $
\item $ \vdash ( \lambda x. 2 ) : \alpha \rightarrow int $
\end { itemize}
In der letzten Typisierung stellt $ \alpha $ einen beliebigen Typen dar.
2014-03-28 10:01:36 +01:00
\section { Typsystem}
2014-04-05 18:18:47 +02:00
\begin { definition} [Typsystem $ \Gamma \vdash t: T $ \footnotemark ]\label { def:typsystem-t1} \xindex { Typregel} \xindex { Typsystem} \xindex { APP@$ \APP $ } \xindex { ABS@$ \ABS $ } \xindex { VAR@$ \VAR $ } \xindex { CONST@$ \CONST $ } %
2014-03-20 15:18:50 +01:00
Ein Typkontext $ \Gamma $ ordnet jeder freien Variable $ x $ einen Typ $ \Gamma ( x ) $
durch folgende Regeln zu:
\begin { align*}
\CONST :& \frac { c \in \text { Const} } { \Gamma \vdash c: \tau _ c} \\
2014-03-20 17:08:27 +01:00
& \\
2014-04-05 18:31:51 +02:00
\VAR : & \frac { \Gamma (x) = \tau } { \Gamma \vdash x: \tau } \\
2014-03-20 17:08:27 +01:00
& \\
2014-03-20 15:18:50 +01:00
\ABS : & \frac { \Gamma , x: \tau _ 1 \vdash t: \tau _ 2} { \Gamma \vdash \lambda x. t: \tau _ 1 \rightarrow \tau _ 2} \\
2014-03-20 17:08:27 +01:00
& \\
2014-04-05 18:18:47 +02:00
\APP : & \frac { \Gamma \vdash t_ 1: \tau _ 2 \rightarrow \tau \; \; \; \Gamma \vdash t_ 2: \tau _ 2} { \Gamma \vdash t_ 1 t_ 2: \tau } \\
2014-03-20 15:18:50 +01:00
\end { align*}
\end { definition}
2014-03-28 10:01:36 +01:00
\footnotetext { WS 2013 / 2014, Folie 192}
2014-03-02 19:35:37 +01:00
Dabei ist der lange Strich kein Bruchstrich, sondern ein Symbol der Logik das als
\textbf { Schlussstrich} \xindex { Schlussstrich} bezeichnet wird. Dabei ist der
Zähler als Voraussetzung und der Nenner als Schlussfolgerung zu verstehen.
\begin { definition} [Typsubstituition]\xindex { Typsubstituition} %
Eine \textit { Typsubstituition} ist eine endliche Abbildung von Typvariablen auf
Typen.
\end { definition}
Für eine Menge von Typsubsitutionen wird überlicherweise $ \sigma $ als Symbol
verwendet. Man schreibt also beispielsweise:
\[ \sigma = [ \alpha _ 1 \text { \pointer } \text { \texttt { bool } } , \alpha _ 2 \text { \pointer } \alpha _ 1 \rightarrow \alpha _ 1 ] \]
\begin { definition} [Lösung eines Typkontextes]
Sei $ t $ eine beliebige freie Variable, $ \tau = \tau ( t ) $ ein beliebiger Typ
$ \sigma $ eine Menge von Typsubstitutionen und $ \Gamma $ ein Typkontext.
$ ( \sigma , \tau ) $ heißt eine Lösung für $ ( \Gamma , t ) $ , falls gilt:
\[ \sigma \Gamma \vdash t : \tau \]
2014-03-20 15:18:50 +01:00
\end { definition}
2014-03-26 09:17:52 +01:00
\begin { beispiel} [Typisierungsregel]\xindex { Typisierungsregel} %
Das Folgende nennt man eine Typisierungsregel:\footnote { Klausur WS 2010 / 2011}
\[ \frac { \Gamma \vdash b: \text { \texttt { bool } } \; \; \; \Gamma \vdash x: \tau \; \; \; \Gamma \vdash y: \tau } { \Gamma \vdash \text { \textbf { if } b \textbf { then } x \textbf { else } y } : \tau } \]
\end { beispiel}
2014-04-05 18:18:47 +02:00
\section { Constraint-Mengen}
Die Konstraint-Mengen ergeben sich direkt aus den Typisierungsregeln:
\begin { align*}
\CONST :& \text { z.~B.} \CONST \frac { 2 \in \text { Const} } { \Gamma \vdash 2 : \alpha _ 5} \text { ergibt } \alpha _ 5 = \text { \texttt { int} } \\
& \\
\VAR : & \\
& \\
\ABS : & \frac { \alpha _ 2 \vdash \alpha _ 3} { \alpha _ 1} \text { ergibt } \alpha _ 1 = \alpha _ 2 \rightarrow \alpha _ 3\\
& \\
\APP : & \frac { \vdash \alpha _ 2 \; \; \; \vdash \alpha _ 3} { \alpha _ 1} \text { ergibt } \alpha _ 2 = \alpha _ 3 \rightarrow \alpha _ 1\\
\end { align*}
2014-03-28 10:01:36 +01:00
\section { Let-Polymorphismus} \xindex { let-Polymorphismus} \footnote { WS 2013 / 2014, Folie 205ff} %
Das Programm $ P = \text { let } f = \lambda x. \ 2 \text { in } f \ ( f \ \text { \texttt { true } } ) $
ist eine polymorphe Hilfsfunktion, da sie beliebige Werte auf 2 Abbildet.
Auch solche Ausdrücke sollen typisierbar sein.
Die Kodierung
\[ \text { let } x = t _ 1 \text { in } t _ 2 \]
ist bedeutungsgleich mit
\[ ( \lambda x. \ t _ 2 ) t _ 1 \]
Das Problem ist, dass
\[ P = \lambda f. \ f ( f \ \text { \texttt { true } } ) \ ( \lambda x. \ 2 ) \]
so nicht typisierbar ist, da in
\[ \ABS \frac { f: \tau _ f \vdash f \ ( f \ \text { \texttt { true } } ) : \dots } { \vdash \lambda f. \ f \ ( f \ \text { \texttt { true } } ) : \dots } \]
müsste
\[ \tau _ f = \text { bool } \rightarrow \text { int } \]
und zugleich
\[ \tau _ f = \text { int } \rightarrow \text { int } \]
in den Typkontext eingetragen werden. Dies ist jedoch nicht möglich. Stattdessen
wird
\[ \text { let } x = t _ 1 \text { in } t _ 2 \]
als neues Konstrukt im $ \lambda $ -Kalkül erlaubt.
\begin { definition} [Typschema]\xindex { Typschema} %
Ein Typ der Gestalt $ \forall \alpha _ 1 . \ \forall \alpha _ 2 . \ \dots \ \forall \alpha _ n. \tau $
heißt \textbf { Typschema} . Es bindet freie Variablen $ \alpha _ 1 , \dots , \alpha _ n $
in $ \tau $ .
\end { definition}
\begin { beispiel} [Typschema]
Das Typschema $ \forall \alpha . \ \alpha \rightarrow \alpha $ steht für unendlich
viele Typen und insbesondere für folgende:
\begin { bspenum}
\item int $ \rightarrow $ int, bool $ \rightarrow $ bool, \dots
\item (int $ \rightarrow $ int) $ \rightarrow $ (int $ \rightarrow $ int), \dots
\item \dots
\end { bspenum}
\end { beispiel}
\begin { definition} [Typschemainstanziierung]\xindex { Typschemainstanziierung} %
Sei $ \tau _ 2 $ ein Nicht-Schema-Typ. Dann heißt der Typ
\[ \tau [ \alpha \mapsto \tau _ 2 ] \]
eine \textbf { Instanziierung} vom Typschema $ \forall \alpha . \ \tau $
und man schreibt:
\[ ( \forall \alpha . \ \tau ) \succeq \tau [ \alpha \mapsto \tau _ 2 ] \]
\end { definition}
\begin { beispiel} [Typschemainstanziierung]
Folgendes sind Beispiele für Typschemainstanziierungen:
\begin { bspenum}
\item $ \forall \alpha . \ \alpha \rightarrow \alpha \succeq \text { int } \rightarrow \text { int } $
\item $ \forall \alpha . \ \alpha \rightarrow \alpha \succeq ( \text { int } \rightarrow \text { int } ) \rightarrow ( \text { int } \rightarrow \text { int } ) $
\item $ \text { int } \succeq \text { int } $
\end { bspenum}
Folgendes sind keine Typschemainstanziierungen:
\begin { bspenum}
\item $ \alpha \rightarrow \alpha \nsucceq \text { int } \rightarrow \text { int } $
\item $ \alpha \nsucceq \text { bool } $
\item $ \forall \alpha . \ \alpha \rightarrow \alpha \nsucceq \text { bool } $
\end { bspenum}
\end { beispiel}
Zu Typschemata gibt es angepasste Regeln:\xindex { Typregel!mit Typabstraktionen} %
\[ \VAR \frac { \Gamma ( x ) = \tau ' \; \; \; \tau ' \succeq \tau } { \gamma \vdash x: \tau } \]
und
\[ \ABS \frac { \Gamma , x: \tau _ 1 \vdash t: \tau _ 2 \; \; \; \tau _ 1 \text { kein Typschema } } { \Gamma \vdash \lambda x. t: \tau _ 1 \rightarrow \tau _ 2 } \]
\todo [inline] { Folie 208ff}
2014-03-20 15:18:50 +01:00
\section { Beispiele}
Im Folgenden wird die Typinferenz für einige $ \lambda $ -Funktionen durchgeführt.
\subsection [$\lambda x.\ \lambda y.\ x\ y$] { $ \lambda x. \ \lambda y. \ x \ y $ \footnote { Lösung von Übungsblatt 6, WS 2013 / 2014} }
Gesucht ist ein Typ $ \tau $ , sodass sich $ \vdash \lambda x. \ \lambda y. \ x \ y: \tau $
mit einem Ableitungsbaum nachweisen lässt. Es gibt mehrere solche $ \tau $ , aber
wir suchen das allgemeinste. Die Regeln unseres Typsystems (siehe \cpageref { def:typsystem-t1} )
sind \textit { syntaxgerichtet} , d.~h. zu jedem $ \lambda $ -(Teil)-Term gibt es genau
eine passende Regel.
2014-03-20 17:08:27 +01:00
Für $ \lambda x. \ \lambda y. \ x \ y $ wissen wir also schon, dass jeder Ableitungsbaum\xindex { Ableitungsbaum}
2014-03-20 15:18:50 +01:00
von folgender Gestalt ist. Dabei sind $ \alpha _ i $ Platzhalter:
2014-04-05 18:31:51 +02:00
\[ \ABS \frac { \ABS \frac { \textstyle \APP \frac { \textstyle \VAR \frac { ( x: \alpha _ 2 , y: \alpha _ 4 ) \ ( x ) = \alpha _ 6 } { x: \alpha _ 2 , y: \alpha _ 4 \vdash x: \alpha _ 6 } \ \ \VAR \frac { ( x: \alpha _ 2 , y: \alpha _ 4 ) \ ( y ) = \alpha _ 7 } { x: \alpha _ 2 , y: \alpha _ 4 \vdash y : \alpha _ 7 } } { \textstyle x: \alpha _ 2 , y: \alpha _ 4 \vdash x \ y: \alpha _ 5 } } { x: \alpha _ 2 \vdash \lambda y. \ x \ y \ : \ \alpha _ 3 } } { \vdash \lambda x. \ \lambda \ y. \ x \ y: \alpha _ 1 } \]
2014-03-20 17:08:27 +01:00
Das was wir haben wollen steht am Ende, also unter dem unterstem Schlussstrich.
Dann bedeutet die letzte Zeile
\[ \vdash \lambda x. \ \lambda \ y. \ x \ y: \alpha _ 1 \]
Ohne (weitere) Voraussetzungen lässt sich sagen, dass der Term
\[ \lambda x. \ \lambda \ y. \ x \ y \]
vom Typ $ \alpha _ 1 $ ist.
Links der Schlussstriche steht jeweils die Regel, die wir anwenden. Also entweder
$ \ABS $ , $ \VAR $ , $ \CONST $ oder $ \APP $ .
Nun gehen wir eine Zeile höher:
\[ x: \alpha _ 2 \vdash \lambda y. \ x \ y \ : \ \alpha _ 3 \]
Diese Zeile ist so zu lesen: Mit der Voraussetzung, dass $ x $ vom Typ $ \alpha _ 2 $
ist, lässt sich syntaktisch Folgern, dass der Term $ \lambda y. \ x \ y $ vom
Typ $ \alpha _ 3 $ ist.
\underline { Hinweis:} Alles was in Zeile $ i $ dem $ \vdash $ steht, steht auch in
jedem \enquote { Nenner} in Zeile $ j < i $ vor jedem einzelnen $ \vdash $ .
Folgende Typgleichungen $ C $ lassen sich aus dem Ableitungsbaum ablesen:
\begin { align*}
C & = \Set { \alpha _ 1 = \alpha _ 2 \rightarrow \alpha _ 3} \\
& \cup \Set { \alpha _ 3 = \alpha _ 4 \rightarrow \alpha _ 5} \\
& \cup \Set { \alpha _ 6 = \alpha _ 7 \rightarrow \alpha _ 5} \\
& \cup \Set { \alpha _ 6 = \alpha _ 2} \\
& \cup \Set { \alpha _ 7 = \alpha _ 4}
\end { align*}
Diese Bedingungen (engl. \textit { Constraints} )\xindex { Constraints} haben eine
allgemeinste Lösung mit einem allgemeinsten Unifikator $ \sigma _ C $ :
\begin { align*}
\sigma _ C = [& \alpha _ 1 \Parr (\alpha _ 4 \rightarrow \alpha _ 5) \rightarrow \alpha _ 4 \rightarrow \alpha _ 5,\\
& \alpha _ 2 \Parr \alpha _ 4 \rightarrow \alpha _ 5,\\
& \alpha _ 3 \Parr \alpha _ 4 \rightarrow \alpha _ 5,\\
& \alpha _ 6 \Parr \alpha _ 4 \rightarrow \alpha _ 5,\\
& \alpha _ 7 \Parr \alpha _ 4]
\end { align*}
\underline { Hinweis:} Es gilt $ ( \alpha _ 4 \rightarrow \alpha _ 5 ) \rightarrow \alpha _ 4 \rightarrow \alpha _ 5 = ( \alpha _ 4 \rightarrow \alpha _ 5 ) \rightarrow ( \alpha _ 4 \rightarrow \alpha _ 5 ) $
Also gilt: Der allgemeinste Typ von $ \lambda x. \ \lambda y. \ x \ y $ ist $ \sigma _ C ( \alpha _ 1 ) = ( \alpha _ 4 \rightarrow \alpha _ 5 ) \rightarrow \alpha _ 4 \rightarrow \alpha _ 5 $ .
\subsection [Selbstapplikation] { Selbstapplikation\footnote { Lösung von Übungsblatt 6, WS 2013 / 2014} } \xindex { Selbstapplikation}
Im Folgenden wird eine Typinferenz für die Selbstapplikation, also
\[ \lambda x. \ x \ x \]
durchgeführt.
Zuerst erstellt man den Ableitungsbaum:
\[ \ABS \frac { \APP \frac { \VAR \frac { ( x: \alpha _ 2 ) \ ( x ) = \alpha _ 5 } { x: \alpha _ 2 \vdash x: \alpha _ 5 } \; \; \; \VAR \frac { ( x: \alpha _ 2 ) \ ( x ) = \alpha _ 4 } { x: \alpha _ 2 \vdash x: \alpha _ 4 } } { x: \alpha _ 2 \vdash x \ x \ : \ \alpha _ 3 } } { \vdash \lambda x. \ x \ x: \alpha _ 1 } \]
Dies ergibt die Constraint-Menge
\begin { align}
C& = \Set { \alpha _ 1 = \alpha _ 2 \rightarrow \alpha _ 3} & \text { $ \ABS $ -Regel} \label { eq:bsp2.c1} \\
& \cup \Set { \alpha _ 5 = \alpha _ 4 \rightarrow \alpha _ 3} & \text { $ \APP $ -Regel} \label { eq:bsp2.c2} \\
& \cup \Set { \alpha _ 5 = \alpha _ 2} & \text { Linke $ \VAR $ -Regel} \label { eq:bsp2.c3} \\
& \cup \Set { \alpha _ 4 = \alpha _ 2} & \text { Rechte $ \VAR $ -Regel} \label { eq:bsp2.c4}
\end { align}
Aus \cref { eq:bsp2.c3} und \cref { eq:bsp2.c4} folgt:
\[ \alpha _ 2 = \alpha _ 4 = \alpha _ 5 \]
Also lässt sich \cref { eq:bsp2.c2} umformulieren:
\[ \alpha _ 2 = \alpha _ 2 \rightarrow \alpha _ 3 \]
Offensichtlich ist diese Bedingung nicht erfüllbar. Daher ist ist die Selbstapplikation
nicht typisierbar. Dies würde im Unifikationsalgorithmus
(vgl. \cref { alg:klassischer-unifikationsalgorithmus} )
durch den \textit { occur check} festgestellt werden.