Grundlagen der Programmierung 2 (3A) Typen und Typcheck

Werbung
Grundlagen der Programmierung 2
(3A)
Typen und Typcheck
Prof. Dr. Manfred Schmidt-Schauß
Künstliche Intelligenz und Softwaretechnologie
12. Mai 2010
Haskell, Typen, und Typberechnung
Ziele:
•
Haskells Typisierung
•
Typisierungs-Regeln
•
Typ-Berechnung
•
Zutaten zu: Milners Typcheck
Grundlagen der Programmierung 2 (3A)
- 1 -
Typisierung in Haskell
Haskell hat eine starke, statische Typisierung.
•
jeder Ausdruck muss einen Typ haben
•
Der Typchecker berechnet Typen aller Ausdrücke
(auch von Funktionen!)
und prüft Typen zur Compilezeit
•
die Theorie sagt:
Es gibt keine Typfehler zur Laufzeit
d.h. kein dynamischer Typcheck nötig.
Grundlagen der Programmierung 2 (3A)
- 2 -
Typisierung:
sprachen)
Monomorphe
Typisierung
Konsequenz:
Begriffe
(andere
Programmier-
Alle Objekte, Funktionen haben einen
eindeutigen Typ
Typvariablen gibt es nicht
pro Typ der Listen-Argumente braucht man eine extra
Längenfunktionen
Polymorphe
Typisierung
Funktion arbeitet auf mehreren Daten-Typen
Typvariablen: Mittel zur Schematisierung.
parametrischer Polymorphismus.
Konsequenz:
Eine einzige Längenfunktion für alle Listen reicht aus
Ist auch in Java 5 für generische Typen anwendbar
Grundlagen der Programmierung 2 (3A)
- 3 -
Bemerkungen zu anderen Programmiersprachen
Verwendung der arithmetischen Operatoren
und Überladung von +, ∗, . . .
Manche Programmiersprachen nutzen automatische (dynamische)
Typkonversion
Haskell:
keine Typkonversion
eingegebene Zahlkonstanten sind überladen
eine eingegebene 8 wird vom Compiler
(fromInteger 8) eingefügt
als
Typkonversion von Hand einfügen:
Z.B. pi + 2%3 ergibt einen Typfehler,
pi + (fromRational (2%3)) ergibt 3.80825932::Double
Grundlagen der Programmierung 2 (3A)
- 4 -
Typisierung, Begriffe
polymorph:
Ein Ausdruck kann viele Typen haben (vielgestaltig,
polymorph).
parametrisch Die (i.a. unendliche) Menge der Typen entspricht eipolymorph:
nem schematischen Typausdruck
Beispiel
Schema:
[a]->Int
Instanzen:
[Int]->Int,
Grundlagen der Programmierung 2 (3A)
[Char]->Int,
[[Char]]->Int
- 5 -
Syntax von Typen in Haskell (ohne Typklassen)
hTypi
::= hBasistypi | (hTypi) | hTypvariablei
| hTypkonstruktorni{hTypi}n
(n = Stelligkeit)
hBasistypi ::= Int | Integer | Float | Rational | Char
Grundlagen der Programmierung 2 (3A)
- 6 -
Syntax von Typen
Typkonstruktoren können benutzerdefiniert sein (z.B. Baum a)
Vordefinierte
Liste
Typkonstruktoren: Tupel
Funktionen
[·]
(.,...,.)
· →·
(Stelligkeit 2, Infix)
Konvention zu Funktionstypen mit →
a→b→c→d
bedeutet:
Grundlagen der Programmierung 2 (3A)
a → (b → (c → d)).
- 7 -
Bemerkungen und Wiederholung
spezielle syntaktische Konventionen für Tupel und Listen.
Beispiel:
Typangabe
•
•
•
(Int, Char)
Paar von Int und Char
[Int]
Liste von Ints
t :: τ
Basistypen nennt man elementare Typen
Grundtyp: Typ ohne Typvariablen (auch monomorph)
polymorph wenn der Typ Typvariablen enthält.
Grundlagen der Programmierung 2 (3A)
- 8 -
Interpretation der Typen
length :: [a] → Int
Interpretation:
Für alle Typen a ist length eine Funktion, die vom
Typ [a] → Int ist.
Logisch gilt dann:
∀x.x :: [a] ⇒ (length x) :: Int
Grundlagen der Programmierung 2 (3A)
- 9 -
Typregeln
Wie berechnet man Typen von Ausdrücken?
Anwendung von Funktionen auf Argumente (σ, τ sind Typen)
s :: σ → τ , t :: σ
(s t) :: τ
Beispiele:
quadrat :: Int → Int , 2 :: Int
(quadrat 2) :: Int
+ :: Int → (Int → Int) , 1 :: Int
(1 +) :: (Int → Int)
((1 +) 2) :: Int
Grundlagen der Programmierung 2 (3A)
,
2:: Int
- 10 -
Typregel
Anwendung“: mehrere Argumente
”
s :: σ1 → σ2 . . . → σn → τ , t1 :: σ1 , . . . , tn :: σn
(s t1 . . . tn) :: τ
Beispiele
+ :: Int → Int → Int, 1 :: Int , 2 :: Int
(+ 1 2) :: Int
+ :: Int → Int → Int
(1 + 2) :: Int
Grundlagen der Programmierung 2 (3A)
- 11 -
Erweiterung der Anwendungsregel
auf polymorphe Typen
Ziel: Anwendung der Typregel für z.B. length oder map
Die Funktion γ ist eine Typsubstitution
wenn sie Typen für Typvariablen einsetzt
γ(τ ) nennt man Instanz von τ
Beispiel
Typsubstitution:
Instanz:
γ = {a 7→ Char, b 7→ Float}
γ([a] → Int) = [Char] → Int
Grundlagen der Programmierung 2 (3A)
- 12 -
Erweiterung der Anwendungsregel
auf polymorphe Typen
s :: σ → τ,
t :: ρ und γ(σ) = γ(ρ)
(s t) :: γ(τ )
Hierbei ist zu beachten:
die Typvariablen in ρ müssen vorher umbenannt werden,
so dass σ und ρ keine gemeinsamen Typvariablen haben.
Grundlagen der Programmierung 2 (3A)
- 13 -
Beispiel zur polymorphen Anwendungsregel
Typ von (map quadrat) ?
map :: (a → b) → [a] → [b]
Instanziiere mit:
ergibt:
{a 7→ Int, b 7→ Int}
map :: (Int → Int) → [Int] → [Int]
Regelanwendung ergibt:
map :: (Int → Int) → [Int] → [Int], quadrat :: (Int → Int)
(map quadrat) :: [Int] → [Int]
Grundlagen der Programmierung 2 (3A)
- 14 -
Polymorphe Anwendungsregel für n Argumente
s :: σ1 → σ2 . . . → σn → τ, t1 :: ρ1, . . . , tn :: ρn und ∀i : γ(σi) = γ(ρi)
(s t1 . . . tn) :: γ(τ )
Die Typvariablen in ρ1, . . . , ρn müssen vorher umbenannt werden.
Beachte verwende möglichst allgemeines γ
Grundlagen der Programmierung 2 (3A)
- 15 -
Wie Berechnet man die Typsubstitutionen?
Unifikation:
Berechnung der allgemeinsten Typsubstitution
Unifikation wird benutzt im Typchecker !
Grundlagen der Programmierung 2 (3A)
- 16 -
Erweiterung der Anwendungsregel
auf polymorphe Typen
mit Unifikation
s :: σ → τ,
.
t :: ρ und γ ist allgemeinster Unifikator von σ = ρ
(s t) :: γ(τ )
Hierbei ist zu beachten:
die Typvariablen in ρ müssen vorher umbenannt werden.
Grundlagen der Programmierung 2 (3A)
- 17 -
Unifikation: Regelbasierter Algorithmus
Man braucht 4 Regeln, die auf den Gleichungen E operieren:
E: Menge von Typgleichungen,
G: Lösung; mit Komponenten der Form x 7→ t.
Beachte; x sind Typvariablen, t sind Typen, f, g sind Typkonstruktoren
Grundlagen der Programmierung 2 (3A)
- 18 -
Unifikation: Die Regeln
Start mit Lösung G = ∅ und der Menge der Eingabegleichungen E
•
G;
.
{x = x} ∪ E
G; E
•
.
G; {t = x} ∪ E
.
G; {x = t} ∪ E
•
.
G; {x = t} ∪ E
G[t/x] ∪ {x 7→ t}; E[t/x]
•
G;
Wenn t keine Variable ist
Wenn x nicht in t
.
{(f s1 . . . sn) = (f t1 . . . tn)} ∪ E
.
.
G; {s1 = t1, . . . , sn = tn)} ∪ E
Ersetzung:
Effekt:
E[t/x]: alle Vorkommen von x werden durch t ersetzt
G[t/x]: jedes y 7→ s wird durch y 7→ s[t/x] ersetzt
Grundlagen der Programmierung 2 (3A)
- 19 -
Unifikation: Regelbasierter Algorithmus
Fehlerabbruch, wenn:
•
.
x = t in E, x 6= t und x kommt in t vor.
•
.
(f (. . .) = g(. . .) kommt in E vor und f 6= g.
Fehlerabbruch bedeutet: nicht typisierbar
Grundlagen der Programmierung 2 (3A)
- 20 -
Beispiel mit Typvariablen
id x = x
id :: a → a.
Berechne Typ von (map id)
map::
id::
(a → b)
a0 → a0
→ [a] → [b]
Regelanwendung benötigt
.
Lösung von (a → b) = (a0 → a0) (mit Unifikation)
.
Unifikation von (a → b) = (a0 → a0) ergibt:
G
∅;
∅;
{a 7→ a0};
{a 7→ a0, b 7→ a0};
Grundlagen der Programmierung 2 (3A)
E
.
{(a → b) = (a0 → a0)}
.
.
{a = a0, b = a0}
.
{b = a0}
∅
- 21 -
Beispiel mit Typvariablen
map :: (a → b) → ([a] → [b]), id :: a0 → a0
(map id) :: γ([a] → [b])
.
.
Einsetzung der Lösung {a = a0, b = a} ergibt
(map id) :: ([a] → [a]).
Grundlagen der Programmierung 2 (3A)
- 22 -
Beispiel zu Typberechnung
Typ von map length
map :: (a → b) → ([a] → [b]), length :: [a0] → Int
(map length) :: ?
.
Unifiziere (a → b) = [a0] → Int
G
∅;
∅;
{a 7→ [a0]};
{a 7→ [a0], b 7→ Int};
Grundlagen der Programmierung 2 (3A)
E
.
{(a → b) = ([a0] → Int)}
.
.
{a = [a0], b = Int}
.
{b = Int}
∅
- 23 -
Beispiel zu Typberechnung
Typ von map length
map :: (a → b) → ([a] → [b]), length :: [a0] → Int
(map length) :: ?
.
Unifiziere (a → b) = [a0] → Int
G
∅;
∅;
{a 7→ [a0]};
{a 7→ [a0], b 7→ Int};
E
.
{(a → b) = ([a0] → Int)}
.
.
{a = [a0], b = Int}
.
{b = Int}
∅
Somit: (map length) :: γ([a] → [b]) = [[a0]] → [Int]
Grundlagen der Programmierung 2 (3A)
- 24 -
Beispiele zu polymorpher Typberechnung
Berechne Typ der Liste [1]:
1. [1] = 1 : []
2. 1 :: Int und [] :: [b]
(Typen der Konstanten)
3. (:) :: a → [a] → [a]
4. Anwendungsregel mit γ = {a 7→ Int} ergibt:
(1 :) :: [Int] → [Int]
(mit Unifikation)
5. Anwendungsregel mit γ2 = {b 7→ Int} ergibt:
(1 : []) :: [Int]
(mit Unifikation)
Grundlagen der Programmierung 2 (3A)
- 25 -
Beispiel zu Typfehler
[1, ’a’] hat keinen Typ:
•
•
•
1 : ( ’a’ : [])
(voll geklammert)
1 :: Integer, [] :: [b], ’a’ :: Char
Typen der Konstanten.
(1 :) :: [Integer] → [Integer] und
’a’:[] :: [Char].
Kein Typ als Resultat, denn:
[Integer] und [Char] sind verschieden unter allen γ.
Grundlagen der Programmierung 2 (3A)
- 26 -
Beispiel zu Typfehler im Interpreter
> [1,’a’]
ERROR - Illegal Haskell 98 class constraint in inferred type
*** Expression : [1,’a’]
*** Type
: Num Char => [Char]
Im aktuellen Interpreter:
No instance for (Num Char)
arising from the literal ‘1’ at <interactive>:1:1
Possible fix: add an instance declaration for (Num Char)
In the expression: 1
Grundlagen der Programmierung 2 (3A)
- 27 -
Typ eines Ausdrucks
Typ von (map quadrat [1,2,3,4]) :
•
map::
(a → b) → [a] → [b]
•
quadrat::
Integer → Integer, und [1, 2, 3, 4] :: [Integer].
•
γ=
{a 7→ Integer, b 7→ Integer}.
•
Das ergibt:
γ(a) = Integer, γ([a]) = [Integer], γ([b]) = [Integer].
•
Resultat:
γ([b]) = [Integer]
Grundlagen der Programmierung 2 (3A)
- 28 -
Typisierung von Funktionen und Ausdrücken
Problematik:
rekursiv definierte Funktionen
Lambda-Ausdrücke, let-Ausdrücke
Listen-Komprehensionen.
Typcheckalgorithmus von Robin Milner (in Haskell und ML)
•
•
•
ist schnell,
liefert allgemeinste (Milner-)Typen
benutzt Unifikation (eine optimierte Variante)
•
schlechte worst-case Komplexität:
in seltenen Fällen exponentieller Platzbedarf
Liefert in seltenen Fällen nicht die allgemeinsten möglichen polymorphen Typen
•
Grundlagen der Programmierung 2 (3A)
- 29 -
Typisierung von Funktionen, Milner
Satz zur Milner-Typisierung in Haskell:
Sei t ein getypter Haskell-Ausdruck, ohne freie Variablen.
Dann wird die Auswertung des Ausdrucks t
nicht mit einem Typfehler abbrechen.
Allgemeine Aussage zu starken Typsystemen
Keine dynamischen Typfehler, wenn das Programm korrekt getypt ist
Grundlagen der Programmierung 2 (3A)
- 30 -
Typisierung und Reduktion: Zusammenhang
Erinnerung Beta-Reduktion: ((λx.t) s) −→ t[s/x]
λx.t :: τ1 → τ2 , s :: σ , γ(τ1) = γ(σ)
((λx.t) s) :: γ(τ2)
Zum Ermitteln von γ(τ2)
benötigt man eine Typsubstitution γ,
so dass γ(τ1) = γ(σ) ist.
Grundlagen der Programmierung 2 (3A)
- 31 -
Typisierung und Reduktion: Zusammenhang
((λx.t) s) −→ t[s/x]
Was ist der Typ von t[s/x]?
Beh:
((λx.t) s) :: τ impliziert t[s/x] :: τ
Argumentation:
Folgerung:
Milner-Typcheck beachtet nur den Typ der Unterterme,
nicht deren syntaktische Form.
Typ von x und s ist aber gleich (als Unterterm von t)
denn γ(τ1) = γ(σ)
auch mehrere Beta-Reduktionen erhalten den ursprünglichen Typ
Analoge Argumentation für andere Auswertungsregeln!
Grundlagen der Programmierung 2 (3A)
- 32 -
Typisierung und Reduktion
Beachte:
Nach Reduktionen kann ein Ausdruck
mehr Typen haben also vorher
Beispiel:
if 1 > 0 then [] else [1]
:: [Integer]
arithmetische-Reduktion:
−→ if True then [] else [1]
:: [Integer]
Case-Reduktion:
−→ []
:: [a]
Grundlagen der Programmierung 2 (3A)
- 33 -
Herunterladen