Programmieren in Haskell Programmieren mit Listen Peter Steffen Universität Bielefeld Technische Fakultät 14.11.2008 1 Programmieren in Haskell Ein eigener Listen-Datentyp data List a = Nil | Cons a (List a) deriving (Show,Eq) Listen sind dann zum Beispiel: Nil :: List a Cons 1 (Cons 2 (Cons 3 Nil)) :: Num a => List a Cons "hallo" (Cons "welt" Nil) :: List [Char] 2 Programmieren in Haskell Spezifikation des Sortierproblems Gewünscht ist eine Funktion sortList :: Ord a => List a -> List a, so daß für jede Liste xs :: List a (mit Ord a), die Elemente von sortList xs geordnet sind, keine Elemente hinzukommen und keine verlorengehen. 3 Programmieren in Haskell Sortieren durch Einfügen isortList :: Ord a => List a -> List a isortList Nil = Nil isortList (Cons x xs) = insertList x (isortList xs) where insertList insertList | x <= y | x > y x x = = Nil = Cons x Nil (Cons y ys) Cons x (Cons y ys) Cons y (insertList x ys) Beispiel: sortList (Cons 1 (Cons 4 (Cons 2 Nil))) => Cons 1 (Cons 2 (Cons 4 Nil)) 4 Programmieren in Haskell Sortieren durch Einfügen isortList :: Ord a => List a -> List a isortList Nil = Nil isortList (Cons x xs) = insertList x (isortList xs) where insertList insertList | x <= y | x > y x x = = Nil = Cons x Nil (Cons y ys) Cons x (Cons y ys) Cons y (insertList x ys) Beispiel: sortList (Cons 1 (Cons 4 (Cons 2 Nil))) => Cons 1 (Cons 2 (Cons 4 Nil)) 4 Programmieren in Haskell Kopf und Restliste headList :: List a -> a headList Nil = error "headList not defined for empty lists" headList (Cons x xs) = x tailList :: List a -> List a tailList Nil = error "tailList not defined for empty lists" tailList (Cons x xs) = xs 5 Programmieren in Haskell Länge, Summe und Produkt lengthList :: Num a => List b -> a lengthList Nil = 0 lengthList (Cons x xs) = 1 + lengthList xs sumList :: Num a => List a -> a sumList Nil = 0 sumList (Cons x xs) = x + sumList xs productList :: Num a => List a -> a productList Nil = 1 productList (Cons x xs) = x * productList xs 6 Programmieren in Haskell Länge, Summe und Produkt lengthList :: Num a => List b -> a lengthList Nil = 0 lengthList (Cons x xs) = 1 + lengthList xs sumList :: Num a => List a -> a sumList Nil = 0 sumList (Cons x xs) = x + sumList xs productList :: Num a => List a -> a productList Nil = 1 productList (Cons x xs) = x * productList xs 6 Programmieren in Haskell Länge, Summe und Produkt lengthList :: Num a => List b -> a lengthList Nil = 0 lengthList (Cons x xs) = 1 + lengthList xs sumList :: Num a => List a -> a sumList Nil = 0 sumList (Cons x xs) = x + sumList xs productList :: Num a => List a -> a productList Nil = 1 productList (Cons x xs) = x * productList xs 6 Programmieren in Haskell Aufzählungen enumFromToList :: (Enum a, Ord a) => a -> a -> List a enumFromToList a b | a > b = Nil | a == b = Cons a Nil | a < b = Cons a (enumFromToList (succ a) b) Beispiele: enumFromToList 1 5 => Cons 1 (Cons 2 (Cons 3 (Cons 4 (Cons 5 Nil)))) enumFromToList 5 4 => Nil enumFromToList ’a’ ’d’ => Cons ’a’ (Cons ’b’ (Cons ’c’ (Cons ’d’ Nil))) 7 Programmieren in Haskell Aufzählungen enumFromToList :: (Enum a, Ord a) => a -> a -> List a enumFromToList a b | a > b = Nil | a == b = Cons a Nil | a < b = Cons a (enumFromToList (succ a) b) Beispiele: enumFromToList 1 5 => Cons 1 (Cons 2 (Cons 3 (Cons 4 (Cons 5 Nil)))) enumFromToList 5 4 => Nil enumFromToList ’a’ ’d’ => Cons ’a’ (Cons ’b’ (Cons ’c’ (Cons ’d’ Nil))) 7 Programmieren in Haskell Fakultät factorialList :: Integral a => a -> a factorialList n | n < 0 = error "factorialList not defined for negative values" | otherwise = productList (enumFromToList 1 n) Beispiele: factorialList 4 => 24, factorialList 0 => 1 Alternative Definition ohne Listen: factorial :: factorial n | n < 0 = | n == 0 = | n > 0 = 8 Integral a => a -> a error "factorial not defined for negative values" 1 n * factorial (n-1) Programmieren in Haskell Fakultät factorialList :: Integral a => a -> a factorialList n | n < 0 = error "factorialList not defined for negative values" | otherwise = productList (enumFromToList 1 n) Beispiele: factorialList 4 => 24, factorialList 0 => 1 Alternative Definition ohne Listen: factorial :: factorial n | n < 0 = | n == 0 = | n > 0 = 8 Integral a => a -> a error "factorial not defined for negative values" 1 n * factorial (n-1) Programmieren in Haskell Fakultät factorialList :: Integral a => a -> a factorialList n | n < 0 = error "factorialList not defined for negative values" | otherwise = productList (enumFromToList 1 n) Beispiele: factorialList 4 => 24, factorialList 0 => 1 Alternative Definition ohne Listen: factorial :: factorial n | n < 0 = | n == 0 = | n > 0 = 8 Integral a => a -> a error "factorial not defined for negative values" 1 n * factorial (n-1) Programmieren in Haskell Append appendList :: List a -> List a -> List a appendList Nil ys = ys appendList (Cons x xs) ys = Cons x (appendList xs ys) Beispiel: appendList (enumFromToList 1 5) (enumFromToList 6 10) == enumFromToList 1 10 => True 9 Programmieren in Haskell Append appendList :: List a -> List a -> List a appendList Nil ys = ys appendList (Cons x xs) ys = Cons x (appendList xs ys) Beispiel: appendList (enumFromToList 1 5) (enumFromToList 6 10) == enumFromToList 1 10 => True 9 Programmieren in Haskell Reverse reverseListSlow :: List a -> List a reverseListSlow Nil = Nil reverseListSlow (Cons x xs) = appendList (reverseListSlow xs) (Cons x Nil) Beispiel: reverseListSlow (enumFromToList 1 3) => Cons 3 (Cons 2 (Cons 1 Nil)) 10 Programmieren in Haskell Reverse reverseListSlow :: List a -> List a reverseListSlow Nil = Nil reverseListSlow (Cons x xs) = appendList (reverseListSlow xs) (Cons x Nil) Beispiel: reverseListSlow (enumFromToList 1 3) => Cons 3 (Cons 2 (Cons 1 Nil)) 10 Programmieren in Haskell Take takeList takeList | n < takeList takeList | n == | n > 11 :: Integral a => a -> List b -> List b n xs 0 = error "takeList not defined for negative values" n Nil = Nil n (Cons x xs) 0 = Nil 0 = Cons x (takeList (n-1) xs) Programmieren in Haskell Beispiele: takeList 3 (enumFromToList 1 10) => Cons 1 (Cons 2 (Cons 3 Nil)) takeList 3 (enumFromToList 1 2) => Cons 1 (Cons 2 Nil) takeList 0 (enumFromToList 1 10) => Nil takeList (-5) (enumFromToList 1 10) => Program error: takeList not defined for negative values 12 Programmieren in Haskell Drop dropList dropList | n < dropList dropList | n == | n > :: Integral a => a -> List b -> List b n xs 0 = error "dropList not defined for negative values" n Nil = Nil n (Cons x xs) 0 = (Cons x xs) 0 = dropList (n-1) xs Beispiele: dropList 3 (enumFromToList 1 10) => Cons 4 (Cons 5 (Cons 6 (Cons 7 (Cons 8 (Cons 9 (Cons 10 Nil)))))) dropList 10 (enumFromToList 1 5) => Nil 13 Programmieren in Haskell Drop dropList dropList | n < dropList dropList | n == | n > :: Integral a => a -> List b -> List b n xs 0 = error "dropList not defined for negative values" n Nil = Nil n (Cons x xs) 0 = (Cons x xs) 0 = dropList (n-1) xs Beispiele: dropList 3 (enumFromToList 1 10) => Cons 4 (Cons 5 (Cons 6 (Cons 7 (Cons 8 (Cons 9 (Cons 10 Nil)))))) dropList 10 (enumFromToList 1 5) => Nil 13 Programmieren in Haskell Map mapList :: (a -> b) -> List a -> List b mapList f Nil = Nil mapList f (Cons x xs) = Cons (f x) (mapList f xs) Beispiel: mapList (+1) (enumFromToList 1 4) Cons 2 (Cons 3 (Cons 4 (Cons 5 Nil))) 14 Programmieren in Haskell Map mapList :: (a -> b) -> List a -> List b mapList f Nil = Nil mapList f (Cons x xs) = Cons (f x) (mapList f xs) Beispiel: mapList (+1) (enumFromToList 1 4) Cons 2 (Cons 3 (Cons 4 (Cons 5 Nil))) 14 Programmieren in Haskell Filter filterList :: (a -> Bool) -> List a -> List a filterList p Nil = Nil filterList p (Cons x xs) | p x = Cons x (filterList p xs) | otherwise = filterList p xs Beispiel: filterList (>5) (enumFromToList 1 10) => Cons 6 (Cons 7 (Cons 8 (Cons 9 (Cons 10 Nil)))) 15 Programmieren in Haskell Filter filterList :: (a -> Bool) -> List a -> List a filterList p Nil = Nil filterList p (Cons x xs) | p x = Cons x (filterList p xs) | otherwise = filterList p xs Beispiel: filterList (>5) (enumFromToList 1 10) => Cons 6 (Cons 7 (Cons 8 (Cons 9 (Cons 10 Nil)))) 15 Programmieren in Haskell Filter-Beispiel oddList :: Integral a => List a -> List a oddList = filterList odd where odd x = x ‘mod‘ 2 /= 0 Beispiel: oddList (enumFromToList 1 10) => Cons 1 (Cons 3 (Cons 5 (Cons 7 (Cons 9 Nil)))) Alternative ohne filterList oddListBoring oddListBoring oddListBoring | x ‘mod‘ 2 | otherwise 16 :: Integral a => List a -> List a Nil = Nil (Cons x xs) /= 0 = Cons x (oddListBoring xs) = oddListBoring xs Programmieren in Haskell Filter-Beispiel oddList :: Integral a => List a -> List a oddList = filterList odd where odd x = x ‘mod‘ 2 /= 0 Beispiel: oddList (enumFromToList 1 10) => Cons 1 (Cons 3 (Cons 5 (Cons 7 (Cons 9 Nil)))) Alternative ohne filterList oddListBoring oddListBoring oddListBoring | x ‘mod‘ 2 | otherwise 16 :: Integral a => List a -> List a Nil = Nil (Cons x xs) /= 0 = Cons x (oddListBoring xs) = oddListBoring xs Programmieren in Haskell Concat concatList :: List (List a) -> List a concatList Nil = Nil concatList (Cons xs xss) = appendList xs (concatList xss) Beispiel: concatList (Cons (enumFromToList 1 3) (Cons (enumFromToList 4 5) Nil => Cons 1 (Cons 2 (Cons 3 (Cons 4 (Cons 5 Nil)))) 17 Programmieren in Haskell Concat concatList :: List (List a) -> List a concatList Nil = Nil concatList (Cons xs xss) = appendList xs (concatList xss) Beispiel: concatList (Cons (enumFromToList 1 3) (Cons (enumFromToList 4 5) Nil => Cons 1 (Cons 2 (Cons 3 (Cons 4 (Cons 5 Nil)))) 17 Programmieren in Haskell