Funktionale Programmierung mit Haskell/ Typklassen
Die Standard-Typklassen
BearbeitenHier sind alle Typklassen aufgeführt, die auch von Bool
verwendet werden. Diese Typklassen werden mit dem Befehl deriving
(engl. ableiten) an die data
-Anweisung gebunden und geben dem Datentyp bestimmte Eigenschaften mit. Die Typklassen können mit :i
genauer untersucht werden.
Typklasse Show
BearbeitenShow
ermöglicht es, dass die type constructors wie Zwei
und As
ausgegeben werden können:
Prelude> data Wert = Zwei|Drei|Vier|Fuenf|Sechs|Siebe|Acht|Neun|Zehn|Bube|Dame|Koenig|As deriving (Show)
Prelude> show As
"As"
Jede Klasse des Moduls Prelude
muss vom Typ Show
sein, denn Prelude
wird vom Interpreter ghci verwendet, und im Interpreter müssen selbstverständlich alle Werte anzeigbar sein.
Typklasse Bounded
BearbeitenBounded
sorgt dafür, dass die Aufzählung einen unteren Wert (hier: Zwei
) und einen oberen Wert (hier As
) besitzt:
Prelude> data Wert = Zwei|Drei|Vier|Fuenf|Sechs|Siebe|Acht|Neun|Zehn|Bube|Dame|Koenig|As deriving (Show, Bounded)
Prelude> minBound :: Wert
Zwei
Prelude> maxBound :: Wert
As
Diese Ausgabe kann nur funktionieren, wenn die Datentypen auch von Show
abgeleitet werden. Sonst haben sie zwar Begrenzungen, aber sie können nicht angezeigt werden.
Die Datentypen Bool
, Int
und Char
haben übrigens auch Ober- und Untergrenzen, die auf diese Weise abgefragt werden können:
Prelude> minBound :: Bool
False
Prelude> maxBound :: Bool
True
Prelude> minBound :: Int
-2147483648
Prelude> maxBound :: Int
2147483647
Prelude> minBound :: Char
'\NUL'
Prelude> maxBound :: Char
'\1114111'
Prelude>
Für andere Datentypen wie Integer
, Float
oder Double
ist eine obere und untere Begrenzung nicht sinnvoll.
Typklasse Enum
BearbeitenDie Typklasse Enum
hilft, den Vorgänger (engl. predecessor) und den Nachfolger (engl. successor) einer Ausprägung anzuzeigen. Das klappt z.B. auch bei Bool
und Int
:
Prelude> data Wert = Zwei|Drei|Vier|Fuenf|Sechs|Siebe|Acht|Neun|Zehn|Bube|Dame|Koenig|As deriving (Show, Enum)
Prelude> succ Fuenf
Sechs
Prelude> pred As
Koenig
Prelude> [Zwei .. As] -- Mit Enum kann man auch solche Listen generieren
[Zwei,Drei,Vier,Fuenf,Sechs,Sieben,Acht,Neun,Zehn,Bube,Dame,Koenig,As]
Prelude> succ As -- Die As hat keinen Nachfolger
*** Exception: succ{Wert}: tried to take `succ' of last tag in enumeration
Prelude> succ False
True
Prelude> pred True
False
Prelude> pred 0
-1
Prelude> succ 0
1
Prelude>
Mit Enum
und list comprehension lässt sich auch schon ein Kartensatz generieren:
Prelude> data Wert = Zwei|Drei|Vier|Fuenf|Sechs|Sieben|Acht|Neun|Zehn|Bube|Dame|Koenig|As deriving (Show, Enum)
Prelude> data Farbe = Kreuz|Herz|Pik|Karo deriving (Show, Enum)
Prelude> [(x,y)|x<-[Kreuz .. Karo], y<-[Zwei .. As]]
[(Kreuz,Zwei),(Kreuz,Drei),(Kreuz,Vier),(Kreuz,Fuenf),(Kreuz,Sechs),(Kreuz,Sieben),
(Kreuz,Acht),(Kreuz,Neun),(Kreuz,Zehn),(Kreuz,Bube),(Kreuz,Dame),(Kreuz,Koenig),(Kreuz,As),
(Herz,Zwei),(Herz,Drei),(Herz,Vier),(Herz,Fuenf),(Herz,Sechs),(Herz,Sieben),(Herz,Acht),
(Herz,Neun),(Herz,Zehn),(Herz,Bube),(Herz,Dame),(Herz,Koenig),(Herz,As),(Pik,Zwei),
(Pik,Drei),(Pik,Vier),(Pik,Fuenf),(Pik,Sechs),(Pik,Sieben),(Pik,Acht),(Pik,Neun),(Pik,Zehn),
(Pik,Bube),(Pik,Dame),(Pik,Koenig),(Pik,As),(Karo,Zwei),(Karo,Drei),(Karo,Vier),
(Karo,Fuenf),(Karo,Sechs),(Karo,Sieben),(Karo,Acht),(Karo,Neun),(Karo,Zehn),(Karo,Bube),
(Karo,Dame),(Karo,Koenig),(Karo,As)]
Prelude> length [(x,y)|x<-[Kreuz .. Karo], y<-[Zwei .. As]] -- sind es wirklich 52 Karten?
52
Prelude>
Typklasse Eq
BearbeitenMit Eq
(engl equation, Ausgleich) können Ausprägungen auf Gleichheit und Ungleichheit verglichen werden:
Prelude> data Wert = Zwei|Drei|Vier|Fuenf|Sechs|Siebe|Acht|Neun|Zehn|Bube|Dame|Koenig|As deriving (Show, Eq)
Prelude> Zwei == Drei
False
Prelude> Zwei /= As -- das ist das Ungleichheits-Zeichen in Haskell
True
Prelude> Fuenf >= Zehn
<interactive>:10:7:
No instance for (Ord Wert) arising from a use of `>='
Possible fix: add an instance declaration for (Ord Wert)
In the expression: Fuenf >= Zehn
In an equation for `it': it = Fuenf >= Zehn
Am letzten Beispiel Fuenf >= Zehn
erkennt man, dass für Größer- und Kleiner-Vergleiche eine andere Typklasse zuständig ist.
Typklasse Ord
BearbeitenOrd
ist nur zusammen mit Eq
arbeitsfähig und hat die Aufgabe, Größer- oder Kleiner-Vergleich zu ermöglichen:
Prelude> data Wert = Zwei|Drei|Vier|Fuenf|Sechs|Siebe|Acht|Neun|Zehn|Bube|Dame|Koenig|As deriving (Show, Eq, Ord)
Prelude> Fuenf >= Zehn
False
Prelude> Fuenf < Zehn
True
Prelude> compare Bube As -- Vergleich auf Kleiner als
LT
Prelude> compare As Bube -- Vergleich auf Groesser als
GT
Prelude> compare Neun Neun -- Vergleich auf Gleichheit
EQ
Typklasse Read
BearbeitenDie Klasse Read
ist das Gegenstück von Show
und ermöglicht das Einlesen einer Ausprägung. Details hierzu werden im Kapitel I/O-Funktionen erklärt:
Prelude> data Wert = Zwei|Drei|Vier|Fuenf|Sechs|Siebe|Acht|Neun|Zehn|Bube|Dame|Koenig|As deriving (Show, Read)
Prelude> read "Dame" :: Wert
Dame
Prelude>
Hierarchie der Standard Haskell Klassen
BearbeitenDie Haskell Klassen stehen in folgender Hierarchie zueinander:
Die Klassen lassen sich im ghci mit :i
genauer untersuchen.
Die blauen Typklassen wurden bereits erklärt, aber Haskell kennt auch viele verschiedene Klassen für numerische Werte:
Num
ist die Oberklasse für jeden beiliebigen Zahlenwert. Jeder Zahlenwert kann angezeigt werden (daher die Ableitung vonShow
und jeder Zahlenwert kann mit jedem anderen Zahlenwert verglichen werden (Eq
).Integral
steht für die ganzen ZahlenInteger
undInt
. Diese Zahlen sind aufzählbar (d.h. man kann den Vorgänger und den Nachfolger bestimmen), daher besitzen sie als ÜberklasseEnum
.