Kurzübersicht über Haskell

Werbung
Kurzübersicht über Haskell
Grundtypen und Funktionen
Grundtypen sind Int für Ganzzahlen und Bool für die Wahrheitswerte True und False.
Die Exponentiation über Int wird als x^n geschrieben. Konjunktion bzw. Disjunktion
über Bool lauten && bzw. ||, wie in C. Sie werten ihre Argumente von links nach rechts
aus, d.h. es gilt
x && y
x || y
=
=
if x then y
else False
if x then True else y
Der Typ der Funktionen mit Argumenten vom Typ a und Ergebnissen vom Typ b ist
a -> b. Daß eine Funktion f diesen Typ hat, wird durch f :: a -> b ausgedrückt.
Für eine Funktion f :: a -> b und einen Argumentausdruck e :: a bezeichnet der
Ausdruck f E die Anwendung von f auf E (wenigstens ein Zwischeraum als Trennzeichen ist nötig). Funktionen mit mehreren Argumenten werden meistens in gestufter
(kaskadierter) Form f x1 x2 ... xn verwendet. In diesem Fall hat die Funktion f den
höherstufigen Typ
f :: t1 -> (t2 -> ... (tn -> t) ...)
oder, abgekürzt,
f :: t1 -> t2 -> ... tn -> t
(der Pfeil -> bindet nach rechts, wohingegen Funktionsanwendung nach links bindet).
Funktionen werden definiert durch Gleichungen f x = E oder als (anonyme) Funktionen \x -> E. So ist \x -> x+1 die Nachfolgerfunktion.
Zweistellige Funktionen f :: a -> b -> c können auch als Infix-Operatoren in der
Form x ‘f‘ y verwendet werden; dies ist äquivalent zu der gewöhnlichen Anwendung
f x y. Z.B. kann man statt div x y auch x ‘div‘ y schreiben. Achtung: Hier darf
nicht der gewöhnliche Apostroph ’ verwendet werden; es muß der accent grave ‘ sein
(es empfiehlt sich nach dessen Eingabe gleich die Leertaste zu drücken, da sonst u.U.
der accent über das nachfolgende Zeichen rutscht, statt davor zu stehen).
Übergibt man einem zweistelligen Operator ? nur eines seiner Argumente, so erhält
man eine Restfunktion oder einen Operatorabschnitt der Form
(x ?)
(? y)
=
=
\y -> x ? y
\x -> x ? y
Beispiel. (+1) und (1+) sind jeweils wieder die Nachfolgerfunktion.
Fallunterscheidung und Zusicherungen
Haskell bietet mehrere Möglichkeiten der Fallunterscheidung, darunter das gewöhnliche
if then else. Um Kaskaden von ifs zu vermeiden, kann eine Funktion im Stil einer
mathematischen Fallunterscheidung definiert werden. Die Notation lautet
f x
| C1
...
| Cn
=
E1
=
En
Ergebnis ist der Wert des ersten Ausdrucks Ei, für den das zugehörige Ci den Wert
True hat. Gibt es kein solches Ci, ist das Ergebnis undefiniert. Zur Vermeidung solcher
Partialitäten verwendet man die vordefinierte Konstante otherwise = True und einen
Schlußfall
| otherwise
=
En+1
Eine weitere Möglichkeit für Fallunterscheidungen bieten Muster (Patterns). Mehrere
Definitionsgleichungen legen das Verhalten der betreffenden Funktion für Argumente
unterschiedlicher Gestalt (etwa leere/nichtleere Liste) fest. Die Gleichungen werden in
der Reihenfolge der textuellen Aufschreibung versucht; die erste, deren Muster auf das
aktuelle Argument paßt, wird angewendet. Paßt kein Muster, ist die Funktion für diese
Argument undefiniert.
Beispiel. Durch die Gleichungen
f 0 = 5
f 1 = 7
wird die Funktion f :: Int -> Int nur für die Argumentwerte 0 und 1 definiert.
Listen
Der Typ der Listen mit Elements vom Typ a ist [a]. Die Liste mit Elementen x1,...,xn
schreibt sich [x1,...,xn]; speziell ist [] die leere Liste. Konkatenation wird mit dem
Infixoperator ++ notiert. Das Vornanfügen eines Elements an eine Liste leistet der Operator :
x:xs = [x] ++ xs
Die Funktion length liefert die Länge, d.h. die Elementzahl einer Liste. Das ite Element
der Liste xs wird durch xs!!i selektiert (wobei die Numerierung mit 0 beginnt).
Eine Liste kann mit den Funktionen
take, drop :: [a] -> Int -> [a]
in zwei Teile aufgespalten werden. Für eine nicht-negative Ganzzahl k besteht die Liste
take k xs aus den ersten k Elementen von xs wenn k <= length xs, und aus ganz
xs wenn k > length xs. Für negative k ist der Wert des Ausdrucks take k xs undefiniert. Die Liste drop k xs entstht durch Streichen des Anteils take k xs am Anfang
von xs. Daher gilt (für k >= 0) stets
take k xs ++ drop k xs = xs
Ein sehr nützliches Sprachmittel ist die Listenkomprehension in der Form
[ f x | x <- L, p x]
Dabie ist L ein listenwertiger Ausdruck, f eine Funktion auf den Listenelementen und
p eine Bool-wertige Funktion. Das Symbol <- kann als links gerichteter Pfeil oder als
eckiges Enthaltenseinszeichen ∈ (gesprochen “aus”) gedeutet werden. In der letzteren
Sichtweise stellt die Listenkomprehension das Listenanalogon zur gewöhlichen Mengenkomprehension {f x | x ∈ S ∧ p x} dar. Der Wert von [ f x | x <- L, p x ] ist
wieder eine Liste, die wie folgt entsteht:
• Die Elemente der Liste L werden von links nach rechts durchmustert.
• Für jedes Element x wird die Bedingung p geprüft.
• Ist p x = True, wird f x in die Ergebnisliste aufgenommen.
• Andernfalls wird x ignoriert.
Spezialfälle der Listenkomprehension sind Allanwendung
map f xs = [ f x | x <- L ]
und Filtern mit einem Prädikat
filter p xs = [p x | x <- xs ]
Die Liste [m,m+1,...,n] von Ganzzahlen kann kurz als [m..n] notiert werden. Wird
die rechte Schranke n weggelassen, bedeutet der Ausdruck die unendliche Liste [m,
m+1, ... ].
Eine weitere nützliche Funktion auf nichtleeren Listen ist das Verknüpfen ihrer Elemente
mit einem zweistelligen Operator f :: a -> a -> a:
foldr1 f [x1,...,xn]
=
f x1 (f x2 ... (f
xn-1 xn)...)
Die Funktion foldr1 selbst hat den Typ (a -> a -> a) -> [a] -> a.
Die Variante foldr von foldr1 kann auch leere Listen bearbeiten; sie verwendet ein
zusätzliches Argument e, das den Wert für leere Listen spezifiziert. Die Definitionsgleichungen lauten
foldr f e [] = e
foldr f e [x] ++ xs = f x (foldr f e xs)
Als Beispiel diene die vordefinierte Funktion
sum s = foldr (+) 0 s
Mittels foldr kann man auch All- und Existenzquantor für Listen definieren. Für ein
Prädikat p :: a -> Bool hat man
all
p xs
exist p xs
=
=
foldr (&&) True (filter p xs)
foldr (||) False (filter p xs)
Damit hat all p xs den Wert True gdw p x für alle x in xs den Wert True hat.
Herunterladen