Programmieren in Haskell

Werbung
Universität Bielefeld
Programmieren
in Haskell
Giegerich
Programmieren in Haskell
WS 2012/2013
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Robert Giegerich
Universität Bielefeld
AG Praktische Informatik
January 22, 2014
Das Haskell Typ-System
Universität Bielefeld
Programmieren
in Haskell
In allen Programmiersprachen sind die Typ-Konzepte ein
prägendes Element.
Das Haskell Typ-System hat zwei grundlegende Konzepte:
Giegerich
Typ-Systeme
TypPolymorphismus
Parametrischer Typ-Polymorphismus (bekannt)
Typ-Klassen
Typ-Klassen (teilweise bekannt, heute Neues dazu)
Typklassen
definieren
Andere Konzepte:
untypisierte Sprachen
monomorphe Typen
Overloading
Objektklassen und Vererbung
Strong typing, static typing
Unter “strong typing” (strenge Typisierung) in einer
Programmiersprache versteht man:
Alle Typen werden durch den Compiler überprüft
Typen, die der Compiler nicht prüfen kann, werdem zur
Laufzeit des Programms geprüft
Ein Programm kann daher keine unbemerkten Fehler
machen, die (auch) Typfehler sind
Unter “static typing” (statische Typen) versteht man
darüberhinaus:
Alle möglichen Typfehler können vom Compiler erkannt
werden
Typ-Sicherheit ist erreichbar ohne Effizienzverlust zur
Laufzeit
Universität Bielefeld
Programmieren
in Haskell
Giegerich
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Praktische Bedeutung des Typ-Systems
Fehler im Programmentwurf kann man grob unterteilen:
“Denkfehler”: Der Algorithmus löst das vorgegebene
Problem nicht
Universität Bielefeld
Programmieren
in Haskell
Giegerich
Typ-Systeme
“Codierfehler”: Die algorithmische Idee ist richtig, aber
ihre Formulierung im Programm ist fehlerhaft
TypPolymorphismus
Die meisten Codierfehler äußern sich als Typfehler – je
vollständiger, desto besser!!
Typklassen
definieren
"Die leichte Taube, indem sie im freien Fluge die
Luft teilt, deren Widerstand sie fühlt, könnte die
Vorstellung fassen, dass es ihr im luftleeren Raum
noch viel besser gelingen werde."
Immanuel Kant - Kritik der reinen Vernunft [1787]
Typ-Klassen
Monomorphe Typen
Universität Bielefeld
Programmieren
in Haskell
Giegerich
1
2
Monomorpher Typ: vollständig festgelegt, z.B. bei Konstanten
Typ-Systeme
True , Note ce (1/2) , " abraham " , Just " Justine "
TypBool , Musik ,
[ Char ]
Maybe String Polymorphismus
Typ-Klassen
Typklassen
definieren
1
2
3
Monomorpher Typ: vollständig festgelegt, z.B. durch
Deklaration
x :: Integer , y :: Bool , 42:: Integer
polynome :: [ Int ] -> Int
length ’ :: [ Char ] -> Int
Monomorphe Typen bieten Typsicherheit, sind aber unflexibel
Warum Typ-Polymorphismus?
1
Ziel: Typsicherheit + Wiederverwendbarkeit von Code
> length ::[ a ] -> Int
Universität Bielefeld
Programmieren
in Haskell
Giegerich
2
3
4
1
2
3
4
5
> length []
= 0
> length ( x : xs ) = 1 + length xs
Was ist der Typ?
length kann Listen jeden Typs verarbeiten,...
... weil die Länge der Liste vom Element-Typ unabhängig ist.
In der Anwendung auf ein Argument konkretisiert sich der Typ:
length :: String -> Int
length :: [ Int ] -> Int
length :: [ Bool ] -> Int
length :: [ String ] -> Int
length :: [[ String ]] -> Int -- und so weiter
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Typ-Parameter
1
2
3
4
Universität Bielefeld
Polymorpher Typ: Typ mit Typ-Parametern
x :: Tree a
y :: Maybe a
z ::[ a ]
length ::[ a ] -> Int
Programmieren
in Haskell
Giegerich
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
1
2
3
4
5
6
7
Eigentlich ist fast alles polymorph:
(++)::
[ a ] -> [ a ] -> [ a ]
concat :: [[ a ]] -> [ a ]
map ::
( a -> b ) -> [ a ] -> [ b ]
foldr ::
( a -> b -> b ) -> b -> [ a ] ->
foldr1 :: ( a -> a -> a ) -> a -> [ a ] ->
foldTree :: b -> ( a -> b ) ( b -> b -> b )
Tree a
Polymorphe Typen haben hohen Dokumentationswert!
b
a
->
-> b
Hierarchie polymorpher Tpen
Universität Bielefeld
Programmieren
in Haskell
1
Typen werden spezieller, wenn man für die Typ-Variablen
Typ-Ausdrücke einsetzt.
Der allgemeinste Typ ist einfach
a
Giegerich
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
1
1
Wir könennen ihn spezialisieren zu
Bool
String
Integer
Double
oder auch wieder polymorph zu
[a]
a -> b
Maybe a
Tree a
und wieder weiter zu ... (Tafel)
Gibt es zu jedem Typ auch eine Funktion, die diesen Typ hat?
Typ-Spezialisierung
1
2
In der Anwendung einer polymorphen Funktion spezialisiert sich
ihr Typ:
length " abraham "
length :: String -> Int
3
4
5
Universität Bielefeld
Programmieren
in Haskell
Giegerich
Typ-Systeme
TypPolymorphismus
Typ-Klassen
length [ " abraham " , " bebraham " , " cebraham " ]
length :: [ String ] -> Int
Typklassen
definieren
6
7
8
1
2
3
’a ’: " braham "
(:) :: Char -> [ Char ] -> Char
Was ist der Typ von foldTree in den Anwendungen
> foldTree ( Leaf 0) ( Leaf . length ) Br
>
( Br ( Leaf " Adam " ) ( Leaf " Eva " ))
> \ x -> foldTree ( Leaf 0) ( Leaf . length ) Br x
Typ-Inferenz
Universität Bielefeld
Programmieren
in Haskell
Typ-Inferenz heißt:
Der allgemeinste Typ jeden Ausdrucks, jeder Anwendung, jeder
Variablen läßt sich automatisch bestimmen.
Konsequenz:
Giegerich
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typ-Deklarationen sind nicht notwendig, sondern optional
Der allgemeinste Typ wird immer berechnet
Allgemeinster Typ > deklarierter Typ: Vom
Programmierer gewollte Typ-Einschränkung
Allgemeinster Typ < deklarierter Typ: Fehler!!
Obwohl optional, gibt man Typ-Deklarationen meistens an
(Kontrolle, Dokumentation)
Typklassen
definieren
Typ-Polymorphismus mit Typ-Klassen
Universität Bielefeld
Programmieren
in Haskell
Giegerich
Typklassen fassen polymorphe Typen zusammen, auf denen ein
geeminsamer Satz von Operationen implementiert ist.
In Typ-Deklarationen fungieren sie als Typ-Kontexte, die
Typ-Parameter einschränken:
Allgemeine Form von Typ-Ausdrücken
1
2
expr :: type
expr :: typecontext = > type
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Typ-Deklarationen
Universität Bielefeld
Programmieren
in Haskell
Allgemeine Form von Typ-Deklarationen
1
2
vars :: type
vars :: typecontext = > type
mit vars = var1 , . . . , varn , n > 0
vari müssen im selben scope definiert sein
Example
1
sort :: ( Ord a ) = > [ a ] -> [ a ]
Der Typcontext schränkt den Typ-Parameter a ein
NB: Was kann man vom Typ her über die berechnete Funktion
erschließen?
Giegerich
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Typklassen
Universität Bielefeld
Programmieren
in Haskell
Haskell-Klassen:
In Haskell sind Typen in Klassen organisiert
Giegerich
Typ-Systeme
Jede Typklasse ist durch eine Menge von (nur)
deklarierten Funktionen charakterisiert
TypPolymorphismus
Die Klassenfunktionen werden auch Methoden genannt
Typklassen
definieren
Typen können Mitglieder, d.h. Instanzen von Klassen
werden
Instanzen müssen die Methoden der Klasse implementieren
Klassen können Default-Implementierungen enthalten
Durch die Defaults sind Eigenschaften der Methoden
ausgedrückt
Typ-Klassen
Typklassen mit syntaktischem Zucker
Universität Bielefeld
Programmieren
in Haskell
Giegerich
Typ-Systeme
Mit manchen (vordefinierten) Typklassen ist spezielle Notation
assoziiert:
Enum: Aufzählungen wie in [1, 3 ..], [’A’ .. ’Z’]
Monad: Do-Notation für >>= , >>
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Unterschied Klassenmethode – polymorphe
Funktion
Universität Bielefeld
Programmieren
in Haskell
Giegerich
Eine polymorphe Funktion ist nur einmal implementiert.
Sie hat einen allgemeinsten Typ und ist auf alle Typen
anwendbar, die Spezialisierungen davon sind.
Typ-Systeme
Eine Klassenmethode hat viele Implementierungen, eine
für jeden Typ, der Mitglied der Klasse ist.
Typklassen
definieren
Was man damit erreicht, nennt man in anderen Sprachen
"Overloading":
verschiedene Funktionen stehen hinter dem gleichen
Funktionsnamen, je nach Argumenttyp wird eine ausgewählt.
TypPolymorphismus
Typ-Klassen
Vordefinierte Typklassen
Universität Bielefeld
Programmieren
in Haskell
Quelle:
Giegerich
http://
Typ-Systeme
commons.
TypPolymorphismus
wikimedia.
Typ-Klassen
org/wiki/
File:
Classes.
png, modifizierte
Version
aus dem
Haskell 98
Report
Typklassen
definieren
Details zu Typklassen
Universität Bielefeld
Programmieren
in Haskell
Giegerich
Eq Überprüfung auf Gleichheit. In der Klasse Eq sind die
Operationen == und /= definiert.
Instanzen z.B.: Int, Float, Double, String
Ord Ordnungsrelation. In der Klasse Ord sind die Operationen
<,>,<=,>= definiert.
Instanzen z.B.: Int, Float, Double, String
Num Umfasst die numerischen Typen, z.B. Int, Float, Double
Operationen: +,-,*
Show Werte eines Typs, der Instanz der Klasse Show ist, lassen
sich ausgeben mit show x
instanzen z.B.: Int, Float, Double, String
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Klassenhierarchie
Universität Bielefeld
Programmieren
in Haskell
Giegerich
Typ-Systeme
Neue Klassen können gegebene Klassen erweitern.
Eigenschaften der Klassenhierarchie
Klassen-Erweiterung ist additiv - Methoden kommen hinzu.
Erweiterung der Typklasse verkleinert die Menge der
Instanzen.
Beispiel: Komplexe Zahlen - wo würde man sie in die
vordefinierte Hierarchie einbauen?
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Definition
1
2
3
4
class Classname Typevar where
decl1 :: type11 -> ... -> type1r_1
...
decln :: typen1 -> ... -> type1r_n
7
8
9
10
11
12
15
16
Giegerich
Typ-Systeme
Typ-Klassen
def ault_func_de f1
Typklassen
def ault_func_de f2
definieren
...
class Superclass_C on te xt = > Classname Typevar where
decl1 :: type11 -> ... -> type1r_1
...
decln :: typen1 -> ... -> typenr_n
13
14
Programmieren
in Haskell
TypPolymorphismus
5
6
Universität Bielefeld
def ault_func_de f1
def ault_func_de f2
...
Beispiel: EQ
Universität Bielefeld
Programmieren
in Haskell
Giegerich
1
2
In Worten: Ein Typ a ist Instanz der Klasse Eq, wenn auf ihm
die Operationen == und /= implementiert sind.
class Eq a where
(==) , (/=) :: a -> a -> Bool
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
3
4
5
6
-- Minimal complete definition : (==) or (/=)
x == y
= not ( x /= y )
x /= y
= not ( x == y )
Quelle: /usr/lib/hugs/packages/hugsbase/Hugs/Prelude.hs
Beispiel: Ord (eine Erweiterung von Eq)
1
2
3
4
Universität Bielefeld
c l a s s ( Eq a ) => Ord a where
compare
: : a −> a −> O r d e r i n g
( <) , ( <=) , ( >=) , (>)
: : a −> a −> Bool
max , min
: : a −> a −> a
Programmieren
in Haskell
Giegerich
Typ-Systeme
5
6
7
8
9
10
Typ−− M i n i m a l c o m p l e t e d e f i n i t i o n : (<=) o r compare
Polymorphismus
−− u s i n g compare can be more e f f i c i e n t f o r c o m p l e x tTyp-Klassen
ypes
compare x y | x==y
= EQ
Typklassen
| x<=y
= LT
definieren
| o t h e r w i s e = GT
11
12
13
14
15
x
x
x
x
<=
<
>=
>
y
y
y
y
=
=
=
=
compare
compare
compare
compare
=
=
=
=
y
x
x
y
16
17
max x y
18
19
20
min x y
|
|
|
|
x <= y
otherwise
x <= y
otherwise
x
x
x
x
y
y
y
y
/=
==
/=
==
GT
LT
LT
GT
Beispiel: Ord
Universität Bielefeld
Programmieren
in Haskell
Giegerich
Typ-Systeme
In Worten: Ein Typ a ist Instanz der Klasse Ord, wenn er
Instanz der Klasse Eq ist, und
auf ihm die weiteren Operationen <, >, <=, >= und
max, min, compare implementiert sind.
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Rolle der Defaults
Universität Bielefeld
Programmieren
in Haskell
Giegerich
In der Klassendefinition werden “Default”-Gleichungen für die
Klassen-Methoden angegeben
Die Methoden können einander gegenseitig definieren, ...
... die Instanz muss dann nur einen Teil implementieren
Die Gleichungen sollten von den Implementierungen erfüllt
werden,...
... was aber nicht geprüft werden kann
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Beispiel: Monad
Universität Bielefeld
Programmieren
in Haskell
Giegerich
Vordefinierte Typklasse:
1
2
3
4
(Achtung: m ist eine Variable für einen einstelligen Typ-Konstruktor!)
Typ-Systeme
infixl 1 > >= , >>
class Monad m where
( > >=) :: m a
-> ( a -> m b ) -> m b
return :: a
-> m a
TypPolymorphismus
5
6
7
( > >)
fail
:: m a
-> m b
:: String -> m a
-> m b
6
7
8
m >> k
fail s
= m > >= \ _ -> k
= error s
-- default
-- default
Typ-Klassen
Typklassen
definieren
Monad-Laws
Universität Bielefeld
Programmieren
in Haskell
Giegerich
1
return gibt nur sein Argument zurück und führt keine
weiteren Berechnungen durch:
m >>= return = m
return x >>= f = f x
2
>>= ist assoziativ:
(m >>= f) >>= g = m >>= (\x -> (f x >>= g))
analog zur Komposition von Funktionen
(m . f ) . g
= m . (f . g)
Dies sind allgemeine Gesetze für Monaden; sie können nicht als
Defaults definiert werden.
Sie werden ebensowenig überprüft wie die Defaults.
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Beispiel: Enum
1
2
3
4
5
6
7
8
c l a s s Enum a where
succ , pred
toEnum
fromEnum
enumFrom
enumFromThen
enumFromTo
enumFromThenTo
Universität Bielefeld
Programmieren
in Haskell
::
::
::
::
::
::
::
a −> a
I n t −> a
a −> I n t
a −> [ a ]
a −> a −> [ a ]
a −> a −> [ a ]
a −> a −> a −> [ a ]
Giegerich
Typ-Systeme
−−
−−
−−
−−
Typ-
[ n . . ] Polymorphismus
[ n ,m . .Typ-Klassen
]
[ n . . m]
Typklassen
[ n , n ’ .definieren
. m]
9
10
11
12
13
14
15
16
−− M i n i m a l c o m p l e t e d e f i n i t i o n : toEnum , fromEnum
succ
= toEnum . (1+)
. fromEnum
pred
= toEnum . s u b t r a c t 1 . fromEnum
enumFrom x
= map toEnum [ fromEnum x . . ]
enumFromTo x y
= map toEnum [ fromEnum x . . fromEnum
enumFromThen x y
= map toEnum [ fromEnum x , fromEnum y
enumFromThenTo x y z = map toEnum [ fromEnum x , fromEnum y
Quelle: /usr/lib/hugs/packages/hugsbase/Hugs/Prelude.hs
Weitere Typklassen
Universität Bielefeld
Programmieren
in Haskell
Vordefiniert:
Giegerich
Es gibt viele weitere vordefinierte Typklassen
Typ-Systeme
Hugs gibt Auskunft per :info XX über Methoden von XX
TypPolymorphismus
... und Instanzen (!) ...
Typ-Klassen
... aber nicht über Defaults
Typklassen
definieren
zum Beispiel: Eq, Show, Ix, ...
Selbstdefiniert:
Eigene Typklassen durch neue Klassendefinitionen
Eigene Instanzen durch Instanz-Deklarationen
Beispiel: class (Eq a) => Group a where ...
Vereinigung von Typklassen
Universität Bielefeld
Programmieren
in Haskell
Giegerich
Typ-Systeme
1
2
Vereinigung von Typklassen geschieht durch ihre gemeinsame
Angabe als Typkontext:
> class ( Real a , Fractional a ) = > RealFrac a
>
where { }
Damit hat die Klasse RealFrac alle Methoden von Real und
Fractional (und keine neuen).
Das wahre RealFrac fügt noch eigene Methoden hinzu.
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Instanzen
Universität Bielefeld
Programmieren
in Haskell
Giegerich
1
2
3
4
5
6
7
8
instance Classname Type where
def1
...
defn
instance Context = > Classname Type where
def1
...
defn
Typ wird zur Instanz der Klasse erklärt (explizit!)
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Beispiel (Prelude)
Universität Bielefeld
Programmieren
in Haskell
Giegerich
Typ-Systeme
1
2
instance Eq Char where
c == c ’
= fromEnum c == fromEnum c ’
Typ-Klassen
3
4
5
TypPolymorphismus
instance Ord Char where
c <= c ’
= fromEnum c <= fromEnum c ’
Quelle: Haskell Report
Hier wird benutzt, dass die anderen Funktionen der Typklasse
über Defaults definiert sind.
Typklassen
definieren
Listen-Beispiel
1
2
-- data [ a ] = a : [ a ] |
-[]
5
6
Programmieren
in Haskell
Giegerich
Typ-Systeme
3
4
Universität Bielefeld
instance Monad [] where
( > >=) l f
= concat ( map f l )
return x
= [x]
Die anderen Monaden-Funktionen haben Defaults
do
x <- [1 ,2]
-- ein Fall von >>
y <- [3 ,4]
-- ein Fall von >>
return ( x * y )
= > [3 ,4 ,6 ,8]
Analog zu folgender Listenbeschreibung:
[ x * y | x <- [1 ,2] , y <- [3 ,4] ]
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Derived Instances
Universität Bielefeld
Bei der Deklaration von einem Algebraischen Datentyp können
mit deriving Instanzen automatisch erzeugt werden:
Programmieren
in Haskell
Giegerich
Typ-Systeme
Definition
TypPolymorphismus
Typ-Klassen
data T a1 . . . am = C1 t11 . . . t1n1
...
Cr tr 1 . . . trnr
deriving (k1 , . . . , ku )
aus dem Prelude geht das für:
Eq, Ord, Enum, Show, . . .
|
|
Typklassen
definieren
Derived Instances
Universität Bielefeld
Programmieren
in Haskell
Giegerich
Typ-Systeme
TypPolymorphismus
wenn eine Typklasse eine Superklasse hat, muss der
Datentyp schon Mitglied dieser Instanz sein
die automatische Instanziierung mit deriving bringt nicht
immer, was man haben will
Typ-Klassen
Typklassen
definieren
Beispiel: Rationale Zahlen
Universität Bielefeld
Programmieren
in Haskell
Giegerich
1
> data Rat = Rat Int Int
Typ-Systeme
Der Bruch 67/18 wird durch Rat 67 18 dargestellt.
Die gleiche Zahl hat viele verschiedene Darstellungen: z.B.
67/18 = 8241/2214.
1
2
1
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Daher ist die folgende Definition von (==) auf Rat falsch (diese
Definition würde mit deriving (Eq) erzeugt werden):
> instance Eq ( Rat ) where
>
Rat x y == Rat x ’ y ’ = x == x ’ && y == y ’
Richtige Definition:
>
Rat x y == Rat x ’ y ’ = x *y ’ == x ’* y
Rat-Zahlen als Instanz von Eq
Universität Bielefeld
Programmieren
in Haskell
1
2
1
2
3
4
1
> instance Eq Rat where
Giegerich
>
Rat x y == Rat x ’ y ’ = x *y ’ == x ,* y
Typ-Systeme
Unschön. Bei jedem Gleichheitstest werden zwei
TypPolymorphismus
Multiplikationen durchgeführt.
Typ-Klassen
Ausweg: “smarter Konstruktor”
Typklassen
> rat :: Int -> Int -> Rat
definieren
> rat x y = norm ( x * signum y ) ( abs y ) where
>
norm x y = Rat ( x ‘div ‘ d ) ( y ‘div ‘ d ) where
>
d = gcd x y
Wenn wir davon ausgehen, daß Elemente vom Typ Rat immer
normiert sind, dann kann doch die Standarddefinition von ==
verwendet werden.
>
Rat x y == Rat x ’ y ’ = x == x ’ && y == y ’
Konsequenzen
Universität Bielefeld
Programmieren
in Haskell
Design-Entscheidung:
Giegerich
Die erste Lösung erfordert zwei Multiplikationen pro
Vergleich
Typ-Systeme
Bei der Lösung mit smart Konstruktor und effizientem
Vergleich muss nach jeder Operation auf rationalen Zahlen
normalisiert werden.
Typ-Klassen
Dies ist Mehraufwand, spart aber ggf. Platz, weil Zähler
und Nenner weniger stark wachsen
Rat als ADT erlaubt das Experimentieren mit beiden Lösungen.
Der ADT für die smart-Konstruktor-Lösung würde nicht Rat,
sondern nur rat exportieren.
TypPolymorphismus
Typklassen
definieren
Erweiterte Zahltypen: Inf n
Universität Bielefeld
Programmieren
in Haskell
Giegerich
Typ-Systeme
1
Weiteres Beispiel:
TypPolymorphismus
Zahltyp Inf n erweitert Zahltyp n um +∞ und −∞
> data Inf n = Fin n | Inf Bool deriving ( Eq )Typ-Klassen
Typklassen
definieren
1
Danach integriert in Ord, Show, Num.
> instance ( Ord n ) = > Ord ( Inf n ) where ...
Siehe Skript.
Typklasse Sequenzen
Universität Bielefeld
Programmieren
in Haskell
Giegerich
Sequentielle Daten kann man unterschiedlich darstellen
als Listen
als HolyLists
als Bäume
als Arrays
und als alle die obigen mit Zusatz-Informationen
Auf allen Sequenz-Typen will man einen gemeinsamen Satz von
Operatioenn haben, ggf. je nach Darstellung mit
unterschiedlicher Effizienz
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Deklaration der Methoden
Universität Bielefeld
Programmieren
in Haskell
1
2
3
4
5
6
7
8
9
10
11
12
> class Sequence s where
>
empty :: s a
>
single :: a -> s a
>
isEmpty , isSingle :: s a -> Bool
>
( <|) :: a -> s a -> s a
>
(| >) :: s a -> a -> s a
>
hd
:: s a -> a
>
tl
:: s a -> s a
>
( < >) :: s a -> s a -> s a
>
len :: s a -> Int
>
fromList :: [ a ] -> s a
>
toList
:: s a -> [ a ]
Giegerich
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Default-Definitionen
Universität Bielefeld
Programmieren
in Haskell
1
2
3
4
5
6
7
8
9
>
>
>
>
>
>
>
>
>
single a
isSingle
a <| s =
s |> a =
x <> y =
len
=
inc x
fromList
toList
Giegerich
= a <| empty
s = not ( isEmpty s ) && isEmpty Typ-Systeme
( tl s )
Typsingle a <> s
Polymorphismus
s <> single a
Typ-Klassen
foldrS ( <|) y x
Typklassen
definieren
foldrS inc 0 where
y = y +1
= foldr ( <|) empty
= foldrS (:) []
keine Defaults für empty, isEmpty, hd, tl
zirkuläre Defaults für <|, |>, <>
Abgeleitete Funktionen
Universität Bielefeld
Programmieren
in Haskell
Giegerich
1
2
3
>
>
>
Typ-Systeme
foldrS (*) e s
Typ| isEmpty s = e
Polymorphismus
| otherwise = hd s * foldrS (*) e ( tl Typ-Klassen
s)
Typklassen
definieren
Beachte: So kann man fold-Operationen definieren, wenn die
Konstruktoren des Datentyps gar nicht bekannt sind ...
... weil man die Selektoren (hier: hd, tl) benutzt.
Aber Vorsicht: für sie gibt es keine Defaults.
Listen als Instanz von Sequence
Universität Bielefeld
Programmieren
in Haskell
Giegerich
1
2
3
4
5
6
7
8
> instance Sequence [] where
>
empty = []
>
isEmpty = null
>
( <|) = (:)
>
hd = head
>
tl = tail
>
toList = id
>
fromList = id
Prüfe: Ist hier wirklich alles definiert?
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Bäume als Instanz von Sequence
Universität Bielefeld
Programmieren
in Haskell
1
2
3
4
5
6
Ein Fehlstart:
> instance Sequence Tree where
>
empty = Nil
>
isEmpty Nil = True
>
isEmpty t = False
>
( < >) = Br
>
etc .
Das erfüllt die Anforderungen, nicht denn wir erhalten
isEmpty (empty <> enpty) = False
Lösungsmöglichkeiten
smarte Konstruktoren
aufmerksame Funktionen
Die folgende Lösung ist eine Mischung daraus.
Giegerich
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Bäume als Instanz von Sequence
Universität Bielefeld
Programmieren
in Haskell
1
2
3
4
5
6
7
8
9
10
11
> instance Sequence Tree where
>
empty = Nil
>
isEmpty Nil = True
>
isEmpty ( Leaf _ ) = False
>
isEmpty ( Br l r ) =
>
isEmpty l && isEmpty r
-- aufmerksam
>
single = Leaf
>
isSingle Nil = False
>
isSingle ( Leaf _ ) = True
>
isSingle ( Br l r ) =
>
isSingle l /= isSingle r -- aufmerksam
isEmpty, isSingle achten darauf, was ggf. die
Unterbäume enthalten
Giegerich
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Bäume als Instanz von Sequence
Universität Bielefeld
Programmieren
in Haskell
Giegerich
12
13
14
15
16
17
18
19
>
>
>
>
>
>
>
>
hd ( Leaf a ) = a
hd ( Br l r )
| isEmpty l = hd r
| otherwise = hd l
tl ( Br Nil r ) = tl r
tl ( Br ( Leaf _ ) r ) = r
tl ( Br ( Br l ’ r ’) r ) =
tl ( Br l ’ ( Br r ’ r ))
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
-- Rechtsrotation
Das Ergebnis von tl ist ein tendentiell rechtsgekämmter
Baum
Bäume als Instanz von Sequence
Universität Bielefeld
Programmieren
in Haskell
Giegerich
20
21
22
23
24
25
26
27
>
>
>
>
>
>
>
>
( < >) = br where
-- smart Konstruktor
br Nil r
= r
br l
Nil = l
br l
r
= Br l r
toList = leaves
fromList [] = Nil
fromList [ a ] = Leaf a
fromList ( a : as ) = a <| fromList as
Der smart Konstruktor versucht, den aufmerksamen
Funktionen möglichst viel Arbeit zu ersparen.
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Generische Erweiterung
Universität Bielefeld
Programmieren
in Haskell
Giegerich
Typ-Systeme
Zum Abschluss noch eine beherzte Operation:
Wir erweiteren – gewissermaßen im Voraus – alle
Sequenz-Typen so, das die Sequenzlänge in O(1) berechnet
werden kann.
Dir Grundidee ist schon bekannt von Listen: Man verwendet
Paare (s, l) mit l = length(s).
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Typkonstruktor WithLen
Universität Bielefeld
Programmieren
in Haskell
Giegerich
Typ-Systeme
1
> data WithLen s a = Len ( s a ) Int
Die Variable s steht für einen (einstelligen)
Typkonstruktor!
Daher kann man rechts auch (s a) schreiben.
Wir machen nun ALLE mit WithLen erweiterten
Sequenz-Typen zu Sequenzen
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
WithLen s als Instanz von Sequence
Universität Bielefeld
Programmieren
in Haskell
3
4
5
6
7
8
9
> instance ( Sequence s ) = > Sequence ( WithLen sGiegerich
) whe
>
empty = Len empty 0
Typ-Systeme
>
single a = Len ( single a ) 1
TypPolymorphismus
>
isEmpty ( Len _ n ) = n == 0
Typ-Klassen
>
isSingle ( Len _ n ) = n == 1
Typklassen
definieren
>
a <| Len s n = Len ( a <| s ) ( n +1)
>
Len s n | > a = Len ( s | > a ) ( n +1)
Diese Instanz ergänzt alle Sequenz-Typen um die
Manipulation des Längenwertes
Die Klassenmethoden werden für WithLen s definiert ...
... und benutzen dabei die gleichen Methoden auf s.
WithLen s als Instanz von Sequence
Universität Bielefeld
Programmieren
in Haskell
11
12
13
14
15
16
>
>
>
>
>
>
hd ( Len s _ ) = hd s
tl ( Len s n ) = Len ( tl s ) (n -1)
Len s m <> Len t n = Len ( s <> t ) ( m + n )
len ( Len _ n ) = n
fromList x = Len ( fromList x ) ( length x )
toList ( Len s _ ) = toList s
len benutzt nun natürlich NICHT das len auf dem Typ s,
sondern die explizite Längeninformation
(len) arbeitet nun in O(1)
Im Ergebnis ist damit für JEDEN Sequenztyp s, den wir
einführen, automatisch ein Sequenztyp WithLen s verfügbar
Giegerich
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Fazit zum Haskell Typsystem
Universität Bielefeld
Programmieren
in Haskell
Giegerich
Zusammenfassung
Polymorphe Typen erlauben polymorphe Funktionen,
Typsicherheit und hohe Wiederverwendbarkeit
Typklassen erlauben gleichartige, aber verschieden
implementierte Funktion auf unterschiedlichen Typen ...
... mit Eigenschaften, die man schon im Voraus definieren
kann,
für deren Gültigkeit man aber selbst verantwortlich ist.
Typ-Systeme
TypPolymorphismus
Typ-Klassen
Typklassen
definieren
Herunterladen