Haskell, Typen, und Objektorientierung

Werbung
Haskell, Typen, und Objektorientierung
ZIELE dieses Kapitels
Haskells Typisierung
Milners Polymorpher Typcheck
Haskells Typklassen
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 1
Typisierung in Haskell
Haskell hat eine starke, statische Typisierung.
•
•
jeder Ausdruck muss einen Typ haben
Typchecker berechnet Typen
und prüft Typen zur Compilezeit
•
die Theorie sagt:
Es gibt keine Typfehler zur Laufzeit
d.h. kein dynamischer Typcheck nötig.
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 2
Typisierung: Begriffe (andere
Programmiersprachen)
dynamische
Typisierung
passiert zur Laufzeit.
Datenobjekte haben einen Typ zur Laufzeit.
bei falschem Aufruf: Laufzeit-Typfehler.
schwache,
statische
Typisierung
Typcheck zur Kompilierzeit
Aber man kann Typcheck umgehen
deshalb: dynamischer Typcheck notwendig.
Laufzeit Typfehler sind möglich
Konstanten, Variablen (Bezeichner), Prozeduren und Funktionen haben einen im Programm
festgelegten Typ.
Typisch: Typen können zur Laufzeit per Programmbefehl abgefragt werden
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 3
Typisierung: Begriffe (andere
Programmiersprachen)
Monomorphe
Typisierung
Alle Objekte, Funktionen haben einen
eindeutigen Typ
Typvariablen sind verboten
Konsequenz: verschiedene Längenfunktionen für Listen von unterschiedlichem Typ
Polymorphe
Typisierung
Funktion arbeitet auf mehreren Daten-Typen
Typvariablen: Mittel zur Schematisierung.
parametrischer Polymorphismus.
Eine einzige Längenfunktion für alle Listen reicht aus
Ist auch in Java 5 für generische Typen anwendbar
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 4
Typisierung, Begriffe
polymorph:
Ein Ausdruck kann viele Typen haben (vielgestaltig,
polymorph).
Die (teilweise unendliche) Menge der Typen entspricht
einem schematischen Typausdruck
[α]->Int ist das Schema
Instanzen sind z.B.
[Int]->Int, [Char]->Int,
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 5
[[Char]]->Int
Syntax von Typen in Haskell (ohne Typklassen)
hTypi
::= hBasistypi | (hTypi) | hTypvariablei
| hTypkonstruktorni{hTypi}n
(n = Stelligkeit)
hBasistypi ::= Int | Integer | Float | Rational | Char
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 6
Syntax von Typen
Typkonstruktoren können benutzerdefiniert sein (z.B. Baum α)
Vordefinierte
Liste
Typkonstruktoren: Tupel
Funktionen
[·]
(.,...,.)
· → · (Stelligkeit 2, Infix)
Konvention zu Funktionstypen mit →
a→b→c→d
P raktische Inf ormatik
2, SS
bedeutet:
2005, F olien Kap.3,
(27. M ai2005)
a → (b → (c → d)).
Seite 7
Bemerkungen und Wiederholung
spezielle syntaktische Konventionen für Tupel und Listen.
Beispiel:
(Int, Char)
[Int]
Typangabe
•
•
•
t :: τ
Basistypen nennt man elementare Typen
Grundtyp: Typ ohne Typvariablen (auch monomorph)
polymorph wenn der Typ Typvariablen enthält.
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 8
Beispiele
[1,2,3]
::
[Int]
map
::
(α → β) → [α] → [β]
(:)
::
α → [α] → [α]
length
::
[α] → Int
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 9
Interpretation der Typen
length :: [α] → Int
∀α.length :: [α] → Int
logische Formel:
Interpretation:
Für alle Typen α ist length eine Funktion, die vom
Typ [α] → Int ist.
Logisch gilt dann:
∀x.x :: [α] ⇒ (length x) :: Int
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 10
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
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 11
, 2 :: Int
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
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 12
Erweiterung der Anwendungsregel auf
polymorphe Typen
Ziel: Anwendung der Typregel für length oder map
Die Funktion γ ist eine Typsubstitution
wenn sie Typen für Typvariablen einsetzt
γ(τ ) nennt man Instanz von τ
Beispiel
Typsubstitution:
Instanz:
P raktische Inf ormatik
2, SS
γ = {α 7→ Char, β 7→ Float}
γ([α] → Int) = [Char] → Int
2005, F olien Kap.3,
(27. M ai2005)
Seite 13
Erweiterung der Anwendungsregel auf
polymorphe Typen
s : σ → τ,
t : ρ und γ(σ) = γ(ρ)
(s t) :: γ(τ )
Hierbei: die Typvariablen in ρ müssen vorher umbenannt werden.
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 14
Beispiel zur polymorphen Anwendungsregel
Typ von (map quadrat) ?
map :: (α → β) → [α] → [β]
Instanziiere mit:
ergibt:
{α 7→ Int, β 7→ Int}
map :: (Int → Int) → [Int] → [Int]
Regelanwendung ergibt:
map : (Int → Int) → [Int] → [Int], quadrat :: (Int → Int)
(map quadrat) :: [Int] → [Int]
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 15
Polymorphe Anwendungsregel für n Argumente
s :: σ1 → σ2 . . . → σn → τ,
(s
t1 : ρ1, . . . , tn : ρn und ∀i : γ(σi) = γ(ρi)
t1 . . . tn) :: γ(τ )
Die Typvariablen in ρ1, . . . , ρn müssen vorher umbenannt werden.
Beachte verwende möglichst allgemeines γ
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 16
Beispiel mit Typvariablen
id :: α → α.
id x = x
Berechne Typ von (map id)
map::
id::
(α → β)
α0 → α0
→ [α] → [β]
Regelanwendung:
map : (α → β) → ([α] → [β]), id :: α0 → α0
(map id) :: γ([α] → [β])
d.h. (map id) :: ([α] → [α]).
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 17
Berechnung von Typsubstitutionen, die Typen
gleichmachen
Gegeben:
δi, ρi, i = 1, . . . , n
Gesucht:
γ mit ∀i : γ(δi) = γ(ρi).
Die Berechnung mit den folgenden Regeln nennt man auch Unifikation.
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 18
Unifikation durch Transformation der
Gleichungen
Notation: σ =γ τ statt γ(σ) = γ(τ )
Sei G eine Multimenge von Gleichungen, T C ein Typkonstruktor, α
eine Typvariable, σ, τ (polymorphe) Typen.
Regeln zur Umformung von Gleichungssystemen:
(Dekomposition)
(T C σ1 . . . σm) =γ (T C τ1 . . . τm), G
σ1 =γ τ1, . . . , σm =γ τn, G
Wenn die Typkonstruktoren rechts und links verschieden sind, dann
kann man die Berechnung abbrechen; es kann keine Lösung geben.
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 19
Unifikation durch Transformation der
Gleichungen: Regeln
(Ersetzung)
α =γ σ, G
α =γ σ, G[σ/α]
G[σ/α] bedeutet:
Ersetze alle Vorkommen der Typvariablen α durch den Typ σ.
Hierbei:
Grund:
P raktische Inf ormatik
σ darf α nicht enthalten
Es gibt keine Lösung
Vorsicht: sonst Nichtterminierung
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 20
Unifikation durch Transformation der
Gleichungen: Regeln
(Vereinfachung)
α =γ α, G
G
σ =γ τ, G
(Vertauschung)
τ =γ σ, G
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 21
Unifikation durch Transformation der
Gleichungen: Resultat
Berechnung ist erfolgreich beendet, wenn das Gleichungssystem von
der Form ist:
α1 =γ τ1, . . . , αk =γ τk
wobei αi Typvariablen sind,
und die αi in keinem τj auftreten.
Die gesuchte Typsubstitution ist ablesbar als
γ = {α1 7→ τ1, . . . , αk 7→ τk }
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 22
Beispiel map id nochmal; Variante 1
Typsubstitutionen unterschiedlich, je nach Regelanwendung:
map :: (α → β) → [α] → [β], id :: α0 → α0
(map id) :: γ([α] → [β])
Berechnen von γ:
α → β =γ α 0 → α 0
α =γ α 0 , β =γ α 0
Das ergibt: γ = {α 7→ α0, β 7→ α0}
und (map id) :: [α0] → [α0]
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 23
Beispiel map id Variante 2
Berechnung von γ mit vertauschten Regelanwendungen:
α → β =γ α 0 → α 0
α =γ α 0 , β =γ α 0
α0 =γ α, β =γ α0
α0 =γ α, β =γ α
Das ergibt γ = {α0 7→ α, β 7→ α}
und (map id) :: [α] → [α]
Wegen All-Quantifizierung sind die Typen (bis auf Umbenennung)
identisch
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 24
Typsubstitutionen: Allgemeinere
Definition
Sei V eine Menge von Typvariablen. und γ, γ 0 zwei Typsubstitutionen.
Dann ist γ allgemeiner als γ 0,
wenn es eine weitere Typsubstitution δ gibt,
so dass ∀x ∈ V : δ(γ(x)) = γ 0(x)
Es gilt: Unifikation berechnet allgemeinste Typsubstitutionen
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 25
Beispiel zu Typsubstitutionen
γ = {α1 →
7 (α2, β2)}
γ 0 = {α1 →
7 (Int, Int)}
γ ist allgemeiner als γ 0:
Nehme δ = {α2 7→ Int, β2 7→ Int}.
Dann ist δ(γ(α1)) = (Int, Int) = γ 0(α1).
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 26
Beispiel zu polymorpher Typberechnung
Berechne Typ der Liste [1]:
• [1] = 1 : []
• 1 :: Int und [] :: [β]
(Typen der Konstanten)
• (:) :: α → [α] → [α]
• Anwendungsregel mit γ = {α 7→ Int} ergibt:
(1 :) :: [Int] → [Int]
• Anwendungsregel mit γ2 = {β 7→ Int} ergibt:
(1 : []) :: [Int]
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 27
Beispiel zu Typfehler
[1, 0a0] hat keinen Typ:
•
•
•
1 : (0a0 : [])
(voll geklammert)
1 :: Integer, [] :: [β], 0a0 :: Char
Typen der Konstanten.
(1 :) :: [Integer] → [Integer] und
’a’:[] :: [Char].
Kein Typ als Resultat, denn:
[Integer] und [Char] sind verschieden unter allen γ.
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 28
Beispiel zu Typfehler;Hugs Test
> [1,’a’]
ERROR - Illegal Haskell 98 class constraint in inferred type
*** Expression : [1,’a’]
*** Type
: Num Char => [Char]
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 29
Typ eines Ausdrucks
Typ von (map quadrat [1,2,3,4]) :
•
map::
(α → β) → [α] → [β]
•
quadrat::
Int → Integer, und [1, 2, 3, 4] :: [Integer].
•
γ=
{α 7→ Integer, β 7→ Integer}.
•
Das ergibt:
γ(α) = Integer, γ([α]) = [Integer], γ([β]) = [Integer].
•
Resultat:
γ([β]) = [Integer]
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 30
Typisierung von Funktionen, Milner
Problematik:
rekursiv definierte Funktionen
Lambda-Ausdrücke, let-Ausdrücke
Listen-Komprehensionen.
Typcheckalgorithmus von Robin Milner (in Haskell und ML)
Schnell,
liefert allgemeinste (Milner-)Typen
schlechte worst-case Komplexität:
in seltenen Fällen exponentieller Platzbedarf
Liefert in seltenen Fällen nicht die allgemeinsten möglichen polymorphen Typen
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 31
Typisierung von Funktionen, Milner
Satz zur Milner-Typisierung in Haskell:
Sei t ein getypter Haskell-Ausdruck, ohne freie Variablen (d.h.
geschlossen).
Dann wird die Auswertung des Ausdrucks t nicht mit einem Typfehler
abbrechen.
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 32
Typisierung rekursiv definierter Funktionen
length []
length (x:xs)
=
=
0
(1 + length xs)
der erhaltene Typ ist
Num a => [b] -> a
Das ist auch der Typ von
genericLength im Modul List
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 33
Typisierung rekursiv definierter Funktionen
Vorgehen bei der Berechnung des Typs einer rekursiven Funktion
f x_1 ... x_n = ...
•
•
•
•
•
Annahmen:f:: α x 1:: β1 . . . x n:: βn,
Resultat: βn+1,
Ergibt Typgleichung α = β1-> . . . ->βn->βn+1
bei Pattern verwende extra Gleichungen x i = p i
Typregeln zum Berechnen der Typen der Definitionsgleichung
Bei bekannten Funktionen: verwende umbenannten Typ.
Bei f: verwende α
Lösung von Typgleichungen mittels Unifikationsalgorithmus
Gleichsetzen der Typen der linken und rechten Seiten von
Definitionsgleichungen
Resultat: γ(β1-> . . . ->βn->βn+1)
wobei γ die insgesamt berechnete Typsubstitution ist.
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 34
Typisierung rekursiv definierter Funktionen (2)
[]
++
(x:xs) ++
P raktische Inf ormatik
ys
ys
2, SS
=
=
2005, F olien Kap.3,
ys
x: (xs++ys)
(27. M ai2005)
Seite 35
Typisierung rekursiv definierter Funktionen (2)
[]
++
(x:xs) ++
ys
ys
=
=
ys
x: (xs++ys)
Annahmen: x:xs:: β1, ys:: β2
[] ++ ys = ys
(x:xs)
(x:xs) ++ ys
(xs++ys)
x: (xs++ys)
α = β1 → β2 → β3
β1 = [α1], β3 = β2
x:: α2, xs:: α3, ergibt: α3 = [α2] = β1
[α1] = [α2], also α1 = α2
:: β2 keine neue Gleichung;
β2 = [α1]
Erst hier wird der Resultattyp eingeschränkt!
Ergebnis: ++:: [α1] → [α1] → [α1]
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 36
Typisierung und Reduktion, genauer
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.
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 37
Typisierung und Reduktion, genauer
((λx.t) s) −→ t[s/x]
Was ist der Typ von t[s/x]?
Beh:
((λx.t) s) :: τ impliziert t[s/x] :: τ
Argumentation:
Folgerung:
P raktische Inf ormatik
2, SS
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!
2005, F olien Kap.3,
(27. M ai2005)
Seite 38
Typisierung und Reduktion, genauer
Beachte: Nach Beta-Reduktion kann ein Ausdruck mehr Typen haben
Beispiel:
(((λx.(λy.x)) 1) u)
Beta-Reduktion:
−→ (λy.1) u
Beta-Reduktion:
−→ 1
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
u ungetypt. Deshalb ist der Ausdruck ungetypt.
ungetypt
getypt; vom Typ Integer
(27. M ai2005)
Seite 39
Bemerkungen zu anderen Programmiersprachen
Lisp und Scheme (strikte funktionale Programmiersprachen)
haben kein statisches Typsystem.
der Grund liegt in der Konzeption, z.B. der Booleschen Werte
In Lisp: Nil bedeutet auch False, alles andere gilt als True.
Auswertung:
1 = 0 → Nil,
1 = 1 −→ 1.
Weitere Schwierigkeit: Typeffekte von Zuweisungen
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 40
Bemerkungen zu anderen Programmiersprachen
Verwendung der arithmetischen Operatoren
Überladung von +, ∗, . . .
Manche Programmiersprachen nutzen automatische (dynamische)
Typkonversion
Haskell:
keine Typkonversion
eingegebene Zahlkonstanten sind überladen
1 wird vom Compiler als (fromInteger 1) eingefügt
Typkonversion von Hand einfügen:
Z.B. pi + 2%3 ergibt einen Typfehler,
pi + (fromRational (2%3))
3.80825932::Double
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 41
ergibt
Python und Typisierung
Python ist statisch ungetypt.
Vermutlich wäre ein monomorphes Typsystem für Python möglich
Man muss syntaktische Elemente hinzufügen
Schwierige Kombination:
Python erlaubt Lambda-Ausdrücke und Zuweisung
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 42
Java und Typisierung
Java 1.4 ist streng getypt. Das Typsystem ist monomorph.
die Java-Klassen entsprechen den elementaren Typen.
Zusätzlich gibt es einen Untertyp-Begriff für Klassen.
Die dynamischen Typfehler sind meist (cast)-Fehler.
Java 5 ist streng getypt. Das Typsystem ist polymorph.
Zusätzlich gibt es einen Untertyp-Begriff für Klassen.
Kompliziertere statische Typangaben nötig
Weniger dynamische Typfehler.
P raktische Inf ormatik
2, SS
2005, F olien Kap.3,
(27. M ai2005)
Seite 43
Herunterladen