Typen, Typberechnung und Typcheck

Werbung
Haskell, Typen, und Typberechnung
Grundlagen der Programmierung 3 A
Ziele:
Typen, Typberechnung und Typcheck
Prof. Dr Manfred Schmidt-Schauß
•
Haskells Typisierung
•
Typisierungs-Regeln
•
Typ-Berechnung
•
Zutaten zu: Milners Typcheck
Sommersemester 2013
1
Grundlagen der Programmierung 2 (Typen-A)
Typisierung in Haskell
Typisierung: Begriffe (andere Programmiersprachen)
Monomorphe Alle Objekte, Funktionen haben einen
Typisierung
eindeutigen Typ
Typvariablen gibt es nicht
Konsequenz: pro Typ der Listen-Argumente braucht man eine extra
Längenfunktionen
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 (Typen-A)
– 2/37 –
– 3/37 –
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 (Typen-A)
– 4/37 –
Überladung
Überladung und Konversion in Haskell
Haskell:
Manche Programmiersprachen nutzen automatische (dynamische)
Typkonversion:
Z.B. bei Verwendung der arithmetischen Operatoren
und Überladung von +, ∗, . . .
für Integer, Double, Rational, . . .
Grundlagen der Programmierung 2 (Typen-A)
Prelude> :m Data.Ratio ←Prelude Ratio> pi+2%3
<interactive>:1:0:
No instance for (Floating (Ratio t))
.. .. ..
Prelude Ratio> pi + (fromRational (2%3)) ←3.8082593202564596
it :: Double
– 5/37 –
Typisierung, Begriffe
polymorph:
keine Typkonversion
eingegebene Zahlkonstanten sind überladen
eine eingegebene 8 wird vom Compiler als
(fromInteger 8) eingefügt
Grundlagen der Programmierung 2 (Typen-A)
Syntax von Typen in Haskell (ohne Typklassen)
Ein Ausdruck kann viele Typen haben (vielgestaltig, polymorph).
parametrisch Die (i.a. unendliche) Menge der Typen entspricht einem
polymorph:
schematischen Typausdruck
hTypi
::= hBasistypi | (hTypi) | hTypvariablei
| hTypkonstruktorn i{hTypi}n
(n = Stelligkeit)
Beispiel
Schema:
[a]->Int
Instanzen:
[Int]->Int,
Grundlagen der Programmierung 2 (Typen-A)
– 6/37 –
hBasistypi ::= Int | Integer | Float | Rational | Char
[Char]->Int,
[[Char]]->Int
– 7/37 –
Grundlagen der Programmierung 2 (Typen-A)
– 8/37 –
Syntax von Typen
Bemerkungen und Wiederholung
spezielle syntaktische Konventionen für Tupel und Listen.
Typkonstruktoren können benutzerdefiniert sein (z.B. Baum a)
Vordefinierte
Typkonstruktoren:
Liste
Tupel
Funktionen
Beispiel:
[·]
(.,...,.)
· →·
(Stelligkeit 2, Infix)
Konvention zu Funktionstypen mit →
a → b → c → d bedeutet: a → (b → (c → d)).
Grundlagen der Programmierung 2 (Typen-A)
Interpretation der Typen
Paar von Int und Char
[Int]
Liste von Ints
Typangabe
•
•
•
– 9/37 –
(Int, Char)
t :: τ
Basistypen nennt man elementare Typen
Grundtyp: Typ ohne Typvariablen (auch monomorph)
polymorph wenn der Typ Typvariablen enthält.
Grundlagen der Programmierung 2 (Typen-A)
– 10/37 –
Komposition
Beispiel: Komposition von Funktionen:
komp::(a -> b) -> (c -> a) -> c -> b
komp f g x = f (g x)
length :: [a] ->
Interpretation:
Int
Für alle Typen typ ist length eine Funktion,
die vom Typ [typ] → Int ist.
In Haskell ist komp vordefiniert und wird als .“ geschrieben:
”
Beispielaufruf:
*Main> suche_nullstelle (sin . quadrat) 1 4 0.00000001
←-
1.772453852929175
(sin . quadrat) entspricht sin(x2 )
und quadrat . sin entspricht (sin(x))2 .
Grundlagen der Programmierung 2 (Typen-A)
– 11/37 –
Grundlagen der Programmierung 2 (Typen-A)
– 12/37 –
Typ der Komposition
Typregeln
Erklärung zum Typ von komp, wobei {a,b,c} Typvariablen sind.
Ausdruck: f ‘komp‘ g bzw. f . g
(a->b) ->
(τ1 -> τ2 )
(c->a) ->
Typ
Typ
Typ
Typ
c->b
(τ3 -> τ1 )
τ3
τ2
(τ3 -> τ2 )
x :: τ3
g
/
τ1
von (.)
von f
von g
des Arguments x
der Komposition f . g
Typ des Resultats
der Komposition f (g x)
Typ von (f . g)
f
/
Anwendung von Funktionsausdruck auf Argument
s :: σ → τ , t :: σ
(s t) :: ?
Beispiele:
quadrat :: Int → Int ,
(quadrat 2) :: ?
+ :: Int → (Int → Int)
(1 +) :: ?
τ2
Grundlagen der Programmierung 2 (Typen-A)
2 :: Int
,
1 :: Int
,
2:: Int
((1 +) 2) :: ?
– 13/37 –
Typregel Anwendung“: mehrere Argumente
”
Grundlagen der Programmierung 2 (Typen-A)
– 14/37 –
Anwendungsregel für polymorphe Typen
Ziel: Anwendung der Typregel für z.B. length oder map
s :: σ1 → σ2 . . . → σn → τ , t1 :: σ1 , . . . , tn :: σn
(s t1 . . . tn ) :: τ
Neuer Begriff: γ ist eine Typsubstitution
wenn sie Typen für Typvariablen einsetzt
γ(τ ) nennt man Instanz von τ
Beispiele
+ :: Int → Int → Int, 1 :: Int , 2 :: Int
(+ 1 2) :: Int
Beispiel
Typsubstitution:
Instanz:
+ :: Int → Int → Int
(1 + 2) :: Int
Grundlagen der Programmierung 2 (Typen-A)
Wie berechnet man Typen von Ausdrücken?
– 15/37 –
Grundlagen der Programmierung 2 (Typen-A)
γ = {a 7→ Char, b 7→ Float}
γ([a] → Int) = [Char] → Int
– 16/37 –
Anwendungsregel für polymorphe Typen
Beispiel zur polymorphen Anwendungsregel
Typ von (map quadrat) ?
s :: σ → τ, t :: ρ und γ(σ) = γ(ρ)
(s t) :: γ(τ )
map :: (a → b) → ([a] → [b])
Berechnet den Typ von (s t) wenn Typen von s, t schon bekannt
sind
Instanziiere mit:
ergibt:
γ = {a 7→ Int, b 7→ Int}
map :: (Int → Int) → ([Int] → [Int])
Regelanwendung ergibt:
Hierbei ist zu beachten:
die Typvariablen in ρ müssen vorher umbenannt werden,
so dass σ und ρ keine gemeinsamen Typvariablen haben.
Grundlagen der Programmierung 2 (Typen-A)
map :: (Int → Int) → ([Int] → [Int]), quadrat :: (Int → Int)
(map quadrat) :: [Int] → [Int]
– 17/37 –
Polymorphe Regel für n Argumente
– 18/37 –
Wie berechnet man die Typsubstitutionen?
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:
Grundlagen der Programmierung 2 (Typen-A)
Unifikation:
Berechnung der allgemeinsten Typsubstitution
im Typberechnungsprogramm bzw Typchecker
Unifikation wird benutzt im Typchecker von Haskell!
verwende möglichst allgemeines γ
(kann berechnet werden; s.u.)
Grundlagen der Programmierung 2 (Typen-A)
– 19/37 –
Grundlagen der Programmierung 2 (Typen-A)
– 20/37 –
polymorphe Typen; Unifikation
Unifikation: Regelbasierter Algorithmus
Man braucht 4 Regeln, die auf (E; G) operieren:
.
t :: ρ und γ ist allgemeinster Unifikator von σ = ρ
(s t) :: γ(τ )
s :: σ → τ ,
Hierbei ist zu beachten:
die Typvariablen in ρ müssen vorher umbenannt werden.
Grundlagen der Programmierung 2 (Typen-A)
E:
G:
Menge von Typgleichungen,
Lösung; mit Komponenten der Form x 7→ t.
Beachte; x sind Typvariablen, t sind Typen, f, g sind
Typkonstruktoren
– 21/37 –
Unifikation: Die Regeln
Grundlagen der Programmierung 2 (Typen-A)
– 22/37 –
Unifikation: Regelbasierter Algorithmus
Start mit G = ∅; E
•
•
•
•
.
G; {x = x} ∪ E
G; E
.
G; {t = x} ∪ E
Wenn t keine Variable ist
.
G; {x = t} ∪ E
.
G; {x = t} ∪ E
Wenn x nicht in t
G[t/x] ∪ {x 7→ t}; E[t/x]
.
G; {(f s1 . . . sn ) = (f t1 . . . tn )} ∪ E
.
.
G; {s1 = t1 , . . . , sn = tn )} ∪ E
Ersetzung:
Effekt:
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
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 (Typen-A)
– 23/37 –
Grundlagen der Programmierung 2 (Typen-A)
– 24/37 –
Beispiel mit Typvariablen
Beispiel mit Typvariablen
Berechne Typ von (map id)
map::
id::
(a → b)
a0 → a0
→ [a] → [b]
map :: (a → b) → ([a] → [b]), id :: a0 → a0
(map id) :: γ([a] → [b])
.
Regelanwendung benötigt Lösung von (a → b) = (a0 → a0 ):
G
∅;
∅;
{a 7→ a0 };
{a 7→ a0 , b 7→ a0 };
{a 7→ a0 , b 7→ a0 };
E
.
{(a → b) = (a0 → a0 )}
. 0 . 0
{a = a , b = a }
.
{b = a0 }
∅
Grundlagen der Programmierung 2 (Typen-A)
Einsetzung der Lösung γ = {a 7→ a0 , b 7→ a0 } ergibt
(map id) :: ([a0 ] → [a0 ]).
– 25/37 –
Beispiel (foldr (:) []) :: ??
Grundlagen der Programmierung 2 (Typen-A)
foldl :: (a -> b -> a) -> a -> [b] -> a
(:) :: a -> [a] -> [a]
([]) :: [a]
E
.
.
{a → b → b) = c → [c] → [c], b = [d]}
.
{a → [d] → [d]) = c → [c] → [c]}
.
.
.
{a = c, [d] = [c], [d] = [c]}
.
.
{[d] = [c], [d] = [c]}
.
.
{d = c, [d] = [c]}
.
{[c] = [c]}
.
{c = c}
{}
(foldr (:) [])::[c] → [c]
– 26/37 –
Beispiel. Linksfaltung: (foldl (:) [])?
foldr :: (a -> b -> b) -> b -> [a] -> b
(:) :: a -> [a] -> [a]
([]) :: [a]
G
∅
{b 7→ [d]}
{b 7→ [d]}
{b 7→ [d], a 7→ c}
{b 7→ [d], a 7→ c}
{b 7→ [c], a 7→ c, d 7→ c}
{b 7→ [c], a 7→ c, d 7→ c}
{b 7→ [c], a 7→ c, d 7→ c}
Grundlagen der Programmierung 2 (Typen-A)
= γ([a] → b)
– 27/37 –
G
∅
{a 7→ [d]}
{a 7→ [d]}
.
{a 7→ [d], b = [c]}
.
{a 7→ [d], b = [c]}
.
.
{a 7→ [d], b = [[d]], c = [d]}
.
.
{a 7→ [d], b = [[d]], c = [d]}
nicht lösbar
Grundlagen der Programmierung 2 (Typen-A)
E
.
.
{a → b → a) = c → [c] → [c], a = [d]}
.
{[d] → b → [d] = c → [c] → [c]}
.
.
.
{[d] = c, b = [c], [d] = [c]}
.
.
{[d] = c, [d] = [c]}
.
.
{c = [d], [d] = [c]}
.
{[d] = [[d]]}
.
{d = [d]}
– 28/37 –
Beispiel zu Typberechnung
Beispiele zu polymorpher Typberechnung
Typ von map length
map :: (a → b) → ([a] → [b]), length :: [a0 ] → Int
(map length) :: ?
Berechne Typ der Liste [1]:
1 : Int
.
Unifiziere (a → b) = [a0 ] → Int
G
∅;
∅;
{a 7→ [a0 ]};
{a 7→ [a0 ], b 7→ Int};
(:) :: a → [a] → [a]
1 : [] ::?
[] :: [b]
.
.
Anwendungsregel ergibt Gleichungen: {a = Int, [a] = [b]}
E
.
{(a → b) = ([a0 ] → Int)}
.
.
{a = [a0 ], b = Int}
.
{b = Int}
∅
Lösung: γ = {a 7→ Int}
Typ (1 : []) :: [Int]
Somit: (map length) :: γ([a] → [b]) = [[a0 ]] → [Int]
Grundlagen der Programmierung 2 (Typen-A)
– 29/37 –
Beispiel zu Typfehler
[1, ’a’] hat keinen Typ:
• 1 : ( ’a’ : [])
• 1 :: Integer, [] :: [b], ’a’ :: Char
• (1 :) :: [Integer] → [Integer] und
(’a’:[]) :: [Char].
– 30/37 –
Beispiel zu Typfehler im Interpreter
Prelude> [1,’a’] ←-
(Typen der Konstanten.)
Kein Typ als Resultat, denn:
.
[Integer] = [Char] ist nicht lösbar.
Grundlagen der Programmierung 2 (Typen-A)
Grundlagen der Programmierung 2 (Typen-A)
– 31/37 –
<interactive>:1:1:
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
In the expression: [1, ’a’]
In the definition of ‘it’: it = [1, ’a’]
Grundlagen der Programmierung 2 (Typen-A)
– 32/37 –
Typ eines Ausdrucks
Typisierung von Funktionen und Ausdrücken
Problematik:
Typ von (map quadrat [1,2,3,4]) :
• map::
(a → b) → [a] → [b]
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)
•
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 (Typen-A)
– 33/37 –
Typisierung von Funktionen, Milner
Grundlagen der Programmierung 2 (Typen-A)
– 34/37 –
Typisierung und Reduktion
Beachte:
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.
Nach Reduktionen kann ein Ausdruck
mehr Typen (bzw. einen allgemeineren Typ) haben
als vor der Reduktion
Beispiel:
if 1 > 0 then [] else [1]
Allgemeine Aussage zu starken Typsystemen
Es gibt keine dynamischen Typfehler,
wenn das Programm statisch korrekt getypt ist
Grundlagen der Programmierung 2 (Typen-A)
schlechte worst-case Komplexität:
in seltenen Fällen exponentieller Zeitbedarf
Liefert in seltenen Fällen nicht
die allgemeinsten möglichen polymorphen Typen
– 35/37 –
:: [Integer]
arithmetische-Reduktion:
−→ if True then [] else [1]
:: [Integer]
Case-Reduktion:
−→ []
:: [a]
Grundlagen der Programmierung 2 (Typen-A)
– 36/37 –
Typisierung und Reduktion
weiteres Beispiel:
(if 1 > 0 then foldr else foldl) ::
(a -> a -> a) -> a -> [a] -> a
Reduktion ergibt als Resultat:
foldr:: (a -> b -> b) -> b -> [a] -> b
der Typ ist allgemeiner geworden!
Grundlagen der Programmierung 2 (Typen-A)
– 37/37 –
Herunterladen