Typen
Next:Typen von FunktionenUp:Grundlegende SprachelementePrevious:Lokale Definitionen
Typen
Ausdrücke bezeichnen Werte
(Auswertung eines Ausdrucks versucht, ihn auf seine einfachste äquivalente Form zu reduzieren, also z.B.
3 + 4 => 7
abs(-2) => 2
und jeder Wert hat einen Typ, der wie folgt angegeben werden kann:
3 :: Int
True :: Bool
abs :: Int -> Int
Solche Typdeklarationen kann der Programmierer explizit anschreiben, insbesondere bei der Einführung von Bezeichnern:
pi :: Float
pi = 3.14
area :: Float -> Float
area x = pi * x * x
Er muß es aber nicht !
Trotzdem hat Haskell ein statisches Typsystem (= Typ steht zur Compile-Zeit, also vor der Auswertung, fest): Haskell betreibt neben Syntaxanalyse noch Typ-Inferenz, d.h. erschließt den Typ von Ausdrücken aus Teilen und weist den Ausdruck als fehlerhaft zurück, falls kein vernünftiger Typ gefunden werden kann.
Empfehlung: verwende Typ deklarationen
- zur Dokumentation / Lesbarkeit
- gegen Fehler (Haskell vergleicht Typdeklarationen mit erschlossenem Typ)
Es gibt die üblichen Basistypen wie
Int, Float, Bool, Char
mit Elementen wie
3, 3.14, True, 'A'
und Operationen wie
+, *, .. , &&, ||, ..
und es gibt strukturierte Typen wie z.B. [Int] oder [Char] = Typen der Listen von Int- oder Char-Elemente mit Elementen wie [1,2,3], ['A', 'B', 'C'].
[] = leere Liste,
Operator ``:'' zum Anfügen eines Elements vorne:
'A':['B','C'] ist ['A','B','C']
und der Konkatenation ``++'':
['A'] ++ ['B','C']
ist das selbe wie oben.
Zusatz: [Char] ist dasselbe wie der Typ String, String-Elemente können wie üblich auch mit Anführungszeichen gebildet werden: "ABC"
Mehr über
Basistypen | $$ | Report, Literatur |
Listen | $$ | späteres Kapitel |
benutzerdefinierte Typen | $$ | späteres Kapitel |
Mit dem Hugs-Kommando ``:type'' kann man den Typ eines Ausdrucks erfragen:
> :type 'A'
'A' :: Char
> :type "hallo"
"hallo" :: String
Das Ergebnis sieht aber manchmal anders aus als erwartet:
> :type 3
3 :: Num a => a
> :type area
area :: Fractional a => a -> a
Ähnliches gilt für Meldungen bei Typfehlern!
und verweist auf einen weiteren wichtigen Aspekt von Haskells Typ-System:
- Polymorphismus
= ein Haskell-Typ kann mit anderen Typen parametrisiert sein.
- Beispiel:
-
Die Identitätfunktion ist für jeden Typ sinnvoll; man darf daher definieren
id x = x
was den Typ
id :: a -> a
mit Parameter ``a'' (Kleinbuchstaben!) ergibt, der für beliebige andere Typen steht, also möglich:
id 3, id 'A', id [1,2,3]
neben parametrischem oder universellem Polymorphismus gibt es auch noch
- Überladen (overloading, ad-hoc-Polymorphismus)
= das gewünschte Verhalten ist für mehrere, aber nicht alle Typen möglich und erfordert i.A. jeweils verschiedene Implementierungen.
Beispiele:
- Gleichheitsoperator ``==''
(``='' ist Definitionszeichen!)
und erfordert für Listen z.B. ganz andere Definition als für die diversen Basistypen.
- Zahlenbezeichner wie z.B. ``3'' stehen für verschiedene Zahlbereiche (Int, Float, Genauigkeit), ähnlich arithmetische Operatoren wie ``+''.
Der Typinferenzmechanismus ermittelt deshalb einen parametrisierten Typausdruck mit einer Einschränkung des Parameters: der erlaubte Typ muß zu einer Klasse gehören, die die im betrachteten Ausdruck vorkommenden Operationen usw. unterstützt.
- Beispiel:
-
> :type 3
3 :: Num a => a
- lies: 3 hat Typ a, wobei a ein numerischer Typ ist
> :type area
area :: Fractional a => a -> a
- lies: area ist eine Funktion vom Typ a->a, wobei a ein
- Typ für "reelle" Zahlen ist, also die in der Definition
- von "area" steckende Multiplikation mit 3.14 verkraftet
mehr zum Thema später!
Polymorphismus & Overloading nicht verwechseln mit den ebenso benannten Dingen in Ada!
- Gleichheitsoperator ``==''
Next:Typen von FunktionenUp:Grundlegende SprachelementePrevious:Lokale Definitionen Ronald Blaschke
1998-04-19