module L04A where -- Examples from Lecture 4A -- 2010-11-17 import Prelude hiding () -- might hide some defs import Test.QuickCheck import Text.Show.Functions -- needed to test higher-order functions import Data.Char(isSpace,toUpper) -- useful character tests and conversions import Data.List(sort,group,groupBy) -- handy list functions not in Prelude ------------------------------------------ -- map -- filter -- The foldr pattern -- sum, product, concatenate sum' [] = 0 sum' (x:xs) = x + sum' xs product' [] = 1 product' (x:xs) = x * product' xs concat' [] = [] concat' (xs:xss) = xs ++ concat' xss foldr' f b [] = b foldr' f b (x:xs) = x `f` foldr' f b xs -- xs ++ ys = foldr (:) ys xs -- Side note: operators and functions q1 ys = foldr (:) ys [] -- identity on lists q2 xs ys = foldr (:) ys xs -- xs ++ ys q3 xs = foldr snoc [] xs where snoc y ys = ys ++ [y] q3' xs = foldr (\y ys -> ys ++ [y]) [] xs shout :: [String] -> [String] shout xss = map (map toUpper) xss -- (\s -> map toUpper s) -- where sh s = map toUpper s -- unlines unlines' xs = foldr (\xs ys -> xs ++ "\n" ++ ys) [] xs ------------------------------------ -- Another useful pattern. -- e.g. takeLine takeLine [] = [] takeLine (x:xs) | x /= '\n' = x:takeLine xs | otherwise = [] takeWord [] = [] takeWord (x:xs) | not(isSpace x) = x : takeWord xs | otherwise = [] takeWhile' p [] = [] takeWhile' p (x:xs) | p x = x : takeWhile' p xs | otherwise = [] -- Side note: sections -- takeWhile & dropWhile ------------------------------------ -- Another example (lines) lines' [] = [] lines' xs = takeWhile (/= '\n') xs : lines' (drop 1 (dropWhile (/= '\n') xs)) -- Generalise: segments (not a standard function) -- words using isSpace segments p [] = [] segments p xs = takeWhile p xs : segments p (drop 1 (dropWhile p xs)) ------------------------------------- -- More ways to build functions: Partial application -- sum, revisited f :: Int -> Bool -> String -> String f i b s = take i (show (not b) ++ s) -- (slides: bracketing) -- Lecture 4A, 2010 got to here.... -- Fixity. How do you know when to skip brackets? -- $ ------------------------------------ -- Another way to build functions: function composition -- countWords :: String -> String -- count words in a string countWords = unlines . map (\(s,n) -> s ++ ": " ++ show n) . map (\s -> (head s,length s)) . groupBy (==) . sort . words prop_mapmap f g x = (map f . map g) x == map (f . g) x -- groupBy (group)