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-20 15:18:50 +01:00
\begin { definition} [Typsystem $ \Gamma \vdash t: T $ ]\label { def:typsystem-t1}
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-03-20 15:18:50 +01:00
\VAR : & \frac { \Gamma (x) = \tau } { \Gamma \vdash c: \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-03-20 15:18:50 +01:00
\APP : & \frac { \Gamma \vdash t_ 1, \tau _ 2 \tau \; \; \; \Gamma \vdash t_ 2: \tau _ 2} { \Gamma \vdash t_ 1 t_ 2: \tau }
\end { align*}
\end { definition}
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}
\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-03-20 17:08:27 +01:00
\[ \ABS \frac { \ABS \frac { \textstyle \ABS \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 } \]
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.