[ Seminarthemen SS 2001] ... [ Inhaltsverzeichnis ] ... [ CGI Library ]
antwort :: Int antwort = 42
fac :: Int -> Int
erläutern. Aufgabe von fac
ist es, die Fakultät einer beliebigen
ganzen Zahl zu berechnen und das Ergebnis (ebenfalls eine ganze Zahl) zurückzuliefern.
Typischerweise besteht der Rumpf aus dem Funktionsbezeichner, den Namen der formalen Parameter, einem Gleichheitszeichen und der Berechnungsvorschrift. Die Funktion inc berechnet den Nachfolger einer ganzen Zahl. Sie kann wie folgt definiert werden.
inc :: Int -> Int inc n = n + 1Die vollständige Definition der oben beschriebenen Funktion fac zeigt ein mächtiges Hilfsmittel von Haskell . Die Rede ist von Pattern Matching. Beim Pattern Matching werden die Parameter der Funktion ausgewertet, um in Abhängigkeit dieser Parameter alternative Berechnungsvorschriften aufzurufen. Wie bereits erwähnt ist die Rekursion wegen fehlender Schleifen ein integraler Bestandteil der funktionalen Programmierung. Am Beispiel der Funktion fac wird deutlich, warum Pattern Matching besonders für die Rekursion von großer Bedeutung ist.
fac :: Int -> Int fac 0 = 1 fac n = n * fac (n - 1)
Die Berechnung der Fakultät erfolgt durch die Multiplikation der angegebenen
Zahl n
mit der Fakultät von n-1
. Ist die Zahl n=0
,
wird durch Pattern Matching definitionsgemäß 1
zurückgegeben. Für
alle n>0
wird die rekursive Berechnungsvorschrift aufgerufen.
Mit Hilfe von Synonymen lassen sich Programme lesbarer machen und zusammengesetzte Datentypen erstellen. Beispielsweise ist wie bereits erwähnt ein String eine Liste von Char und eine Person kann als Tupel aus Name und Alter aufgefaßt werden. Die Deklaration eines Synonyms erfolt durch das Schlüsselwort type, dem Typnamen, einem Gleichheitszeichen und der Definition. Alle Typnamen in Haskell beginnen mit einem Großbuchstaben.
type String = [Char] type Person = (String, Int)
Alle algebraischen Datentypen lassen sich durch das Schlüsselwort data, dem Typnamen, einem Gleichheitszeichen und der Definition erzeugen.
Ein Auzählungstyp ist ein Typ mit festem Wertebereich wie zum Beispiel die Monate eines Jahres.
data Monat = Jan | Feb | Mar | Apr | Mai | Jun | Jul | Aug | Sep | Okt | Nov | DezEin Produkttyp kann mit einem Pascal Record verglichen werden. Beliebig viele Daten unterschiedlichen Typs können zu einem Produkttyp zusammengefaßt werden. Diese Typen lassen sich ausschließlich durch definierte Konstruktoren erzeugen. Ein Beispiel für einen Produkttyp ist:
type Name = String type Alter = Int data Person = Teilnehmer Name AlterEin Datum des Typs Person läßt sich ausschließlich durch den Konstruktoraufruf
erzeugen. Mit Hilfe von Produkttypen lassen sich auch Bäume und
andere rekursive Datenstrukturen wie zum Beispiel
data Expr = Lit Int | Add Expr Expr | Sub Expr Exprabbilden. Es gibt drei mögliche Ausprägungen des Typs Expr. Entweder handelt es sich um ein Blatt (einer Zahl) oder einen Knoten (entweder Add oder Sub). Erzeugt wird ein Rechnbaum für den Ausdruck (3-1)+2 durch:
Add (Sub (Lit 3) (Lit 1)) (Lit 2)
Sowohl die vordefinierten Typen als auch benutzerdefinierte Typen und Synonyme sind gültige formale Parameter und Rückgabewerte von Funktionen.
Ein großer Vorteil von Haskell gegenüber anderen Sprachen (in diesem Fall besonders
gegenüber C) liegt im Umgang mit Listen, denn sie sind in Haskell von zentraler
Bedeutung. ein Listentyp wird definiert durch das Einschließen eines Typs in
eckige Klammern. Alle Listenoperationen arbeiten unabhängig vom Typ der in der
Liste enthaltenen Werte.
length [1, 2, 3] ==> 3
length ['a', 'b', 'c'] ==> 3
length [Jan, Feb, Mar] ==> 3
length [a] -> Int
. Im Sprachumfang von Haskell
sind noch eine Reihe weiterer Listenoperationen vorgesehen. Kurz erwähnt seien
an dieser Stelle die später benutzen Funktionen :
(ein Element an
den Anfang einer Liste hängen), ++
(zwei Listen gleichen Typs zu
einer vereinen) und !!
(indizierter Zugriff auf ein Element einer
Liste.
Ausdruck | Ergebnis
|
---|---|
'W' : "ort" |
"Wort"
|
"Wo" ++ "rt" |
"Wort"
|
"Wort" !! 2 |
'r'
|
Die Funktion wendet eine ihr gegebene Funktion (mit der Signatur
) auf jedes Element der Liste des Typs
an und gibt
als Erbegnis eine Liste des Typs
zurück.
Zur Veranschaulichung hier ein einfaches Beispiel. Angenommen es existiert eine Funktion show,
show :: Int -> Stringdie eine Zahl in einen String umzuwandelt. Nun habe ich eine Liste von Zahlen
[1, 2, 3, 4, 42]und möchte diese in eine Liste von entsprechenden Strings
["1", "2", "3", "4", "42"]transorfmieren. In Haskell läßt sich diese Aufgabe kurz durch
map show [1, 2, 3, 4, 42]lösen. Die Funktion show wird auf jedes Element der Liste angewendet und das Resultat in einer Ergebnisliste gespeichert.
Die Ausgabe einer Funktion producer wird als Eingabe einer Funktion consument verwendet, wobei zu beachten ist, daß Funktion producer nur so lange ausgeführt wird, wie die Funktion consument Eingaben benötigt. Dies sei wiederum an einem kurzen praktischen Beispiel verdeutlicht.
queens :: Int -> [[Int]] ... firstQueen :: Int -> [Int] firstQueen n = (head.queens) nqueens berechnet alle möglichen Lösungen für das Damenproblem für n Damen. Die Liste von Ergebnissen wird zur Eingabe für die Listenfunktion
. Diese Funktion liefert das erste Element einer Liste. Da diese
Funktion ausgewertet werden kann bevor alle Ergebnisse aus
vorliegen,
bricht auch die Ausführung von
vorzeitig ab. Gerade bei großen n
spart diese Art der Auswertung erheblich Rechenzeit, da nur die erste Lösung gefunden
werden muß.
gefolgt
von der Parameterliste, einem
und der eigentlichen Definition. Hierzu
ein Beispiel:
map (\n -> n + 1) [1, 2, 3, 4]
Wie wir gesehen haben, wendet die Funktion map
eine ihr zu übergebende Funktion auf eine ihr zusätzlich zu übergebende Liste
an. In diesem Beispiel wird allerdings kein Funktionsbezeichner übergeben sondern
die Funktionsdefinition selbst. Die in Lambda Notation geschriebene Funktion
hat einen Parameter, zu dem sie 1 addiert.
[ Seminarthemen SS 2001] ... [ Inhaltsverzeichnis ] ... [ CGI Library ]