Listen

[Back]    [AVL - Bäume]

Der Datentyp Liste in Haskell

Auf Grund der häufigen Verwendung des Datentyps Liste in funktionalen Sprachen wird für diesen Datentyp eine eigene Syntax verwendet. Eine Liste von Elementen hätte die Darstellung [a, b, c ..., z]. Elemente werden über den Infixoperator (:) vorn an eine Liste angefügt, so dass sich eine nichtleere Liste durch das Muster (x:xs) darstellen läßt.

Die dadurch definierten Selektoren wie head, tail und der Verkettungsoperator erlauben bereits die Arbeit auf dem Datentyp.

01 -- Selektoren
02 
03   kopf     :: [a] ->  a
04   schwanz  :: [a] -> [a]
05 
06   kopf (x:xs)    = x
07   schwanz (x:xs) = xs
08 
09   verkette :: [a] -> [a] -> [a]
10   verkette [] l2 = l2
11   verkette l1 l2 = (kopf l1): verkette (schwanz l1) l2 

Der Verkettungsoperator (im Prelude (++)) wird bereits rekursiv definiert. Erst wenn der rekursive Abstieg vollständig abgeschlossen ist (Terminationsbedingung), wird beim Aufstieg das Anfügen des Kopfes nacheinander ausgeführt. Noch klarer wird der Rekursionsmechanismus beim Umkehren einer Liste.

01   umkehren :: [a] -> [a] -> [a]
02 
03   umkehren []     = []
04   umkehren (x:xs) = umkehren xs ++ [x] 

Die Rekursion wird vollständig ausgeführt, ist normal rekursiv.

Soll der Wert der Funktion sich aus dem jeweiligen rekursiven Aufruf ermitteln, das Ergebnis nicht nach "oben" gereicht und dort beim rekursiven Aufstieg weiter bearbeitet, sondern sofort geliefert werden, verwendet man die sogenannte Akkumulatortechnik. Man spricht in diesem Fall von Endrekursion. Ein gängiges Beispiel ist das Berechnen der Länge einer Liste.

01 -- rekursiv
02 
03   laenge []      =  0
04   laenge (x:xs)  =  1 + laenge xs
05 
06 -- endrekursiv
07 
08   laenge1 []     =  0
09   laenge1 xs     =  hilfslaenge xs 0
10                               where hilfslaenge [] a     = a 
11                                     hilfslaenge (x:xs) a = hilfslaenge xs (a+1) 

Haskell stellt ebenfalls die Möglichkeit bereit, unendliche Listen zu erzeugen. Dabei werden Muster verwendet, die im praktischen Bereich Bedeutung haben.

[1..8]  liefert [1,2,3,4,5,6,7,8]
[1..]   erzeugt die unendliche Liste aller ganzen Zahlen ab 1 und
[1,3..] die aller ungeraden Zahlen 

Mit dieser Reglementierung ist es möglich Beschreibungen (list comprehension) für beliebig große Listen zu liefern. Die Liste der geraden Zahlen stellt sich danach wie folgt dar.

01   gerade = [x | x <- [1..], mod x 2 == 0]

Die Nähe zur Mengenschreibweise ist gewollt. Der Ergebnisterm besteht aus den x, die aus der unendlichen Menge ganzer Zahlen ([1..]) über die boolsche Bedingung (mod x 2 == 0) herausgefiltert werden. Dabei ist in diesem Beispiel (x <- [1..]) der Generator und (mod x 2 == 0) die Filterbedingung.
Ein sehr bekanntes und übersichtliches Beispiel zur Anwendung von Listenbeschreibungen stellt das Sieb des Erastosthenes dar. Dabei werden aus einer Liste von ganzen Zahlen beginnend bei der Zahl 2 alle Vielfachen der ersten Zahl gestrichen. Es entsteht eine gefilterte Liste, in der die geraden Zahlen gestrichen sind. Wenn es höhere nicht gestrichene Zahlen gibt, werden deren Vielfache gewählt und ebenso gestrichen. Übrig bleiben nach diesem Verfahren nur die Primzahlen.

Eine Anwendung der elementaren Listenfunktion take (siehe oben) liefert die gewünschte Anzahl.

01  primzahlen  = sieb [2..]
02 
03  sieb (k:xs) = k :sieb [n | n <-xs, mod n k /= 0]
04 
05  ergebnis    = take 100 primzahlen

 [Anwendungen zur Listenimplementierung] [TOP]