length :: [a] -> Integer length [] = 0 length (x : xs) = 1 + length xsWir können auch die Zahlen aus einer Liste summieren
sum :: [ Integer ] -> Integer sum [] = 0 sum (x : xs) = x + sum xsoder feststellen, ob alle Elemente einer booleschen Liste wahr sind
and :: [ Bool ] -> Bool and [] = True and (x : xs) = x && and xsAlle diese Funktionen folgen wieder einem gemeinsamen Schema. Es ist aber nicht so einfach wie ein map, da die elementweisen Rechnungen doch vom Ergebnis der bisherigen Rechungen abhängen.
f [x1, x2, ... xn ] = g x1 (g x2 (... (g xn x0) ...))Das Rekursionsschema heißt fold-right:
foldr foldr f x0 [] = x0 foldr f x0 (x : xs) = f x (foldr f x0 xs)und dann gilt
length = foldr ( \ x y -> 1 + y ) 0 sum = foldr (+) 0 and = foldr (&&) True
head :: [a] -> a head [] = error "head von leerer Liste" head (x : xs) = xAls fold sieht es so aus
head = foldr const (error "head von leerer Liste")Die nächste Funktion ist recht praktisch
filter :: (a -> Bool) -> [a] -> [a] filter p [] = [] filter p (x : xs) = if p x then x : filter p xs else filter p xsmit der äquivalenten Definition
filter p = foldr ( \ x ys -> if p x then x : ys else ys ) []Jetzt wirds interessant: wir wollen reverse als foldr schreiben. Wir hatten ja schon gesehen, daß die naive Implementierung zu lange dauert
reverse = foldr ( \ x ys -> ys ++ [x] ) []Der Trick ist, daß wir nicht die umgedrehte Liste erzeugen, sondern eine Funktion, die, wenn wir sie auf die leere Liste anwenden, die umgedrehte Liste ergibt. Wir suchen also
funreverse :: [a] -> ([a] -> [a]) funreverse xs [] == reverse xsFür funreverse können wir leicht eine Definition durch foldr angeben:
funreverse = foldr ( \ x f -> f . (x :) ) iddamit haben wir
reverse xs = foldr ( \ x f -> f . (x :) ) id xs []Wir können das noch ein bißchen verzaubern und noch einige Variablennamen entfernen
reverse = \ xs -> foldr ( \ x f -> f . (x :) ) id xs [] = \ xs -> flip (foldr ( \ x f -> f . (x :) ) id) [] xs = flip (foldr ( \ x f -> f . (x :) ) id ) [] = flip (foldr ( \ x f -> flip (.) (x :) f ) id) [] = flip (foldr ( \ x -> flip (.) (x :) ) id) []
take :: Int -> [a] -> [a] take 0 xs = [] take n (x : xs) = x : take (n-1) xsals foldr. Hinweis: definiere stattdessen "flip take".
Es gibt auch ein fold von links,
foldl g x0 [ x1, x2, ..., xn ] = g(g(g(g x0 x1) x2 ...) xnVervollständige die Definition
foldl g x0 [] = x0 foldl g x0 (x : xs) =und prüfe
reverse = foldl (flip (:)) []Stelle foldl durch foldr dar, und andersherum!