module L4B where import Test.QuickCheck import Data.List import Data.Char(isSpace) -- Higher-Order Functions (Part 2) -- dave 2018-10-02 -- ** What are HOFs a -- ** Why do we need/want HOFs? ** ------------------------------------------ -- Taking similar definitions and -- making a function for the common -- programming pattern, e.g. -- combining elements of a list -- (e.g. sum, product, and, or) sum' [] = 0 sum' (n:ns) = n + sum' ns product' [] = 1 product' (n:ns) = n * product' ns product'' ns = foldr (*) 1 ns and' :: [Bool] -> Bool and' [] = True and' (b:bs) = b && and' bs and'' bs = foldr (&&) True bs foldr' f b [] = b foldr' f b (x:xs) = x `f` foldr' f b xs -- concat concat' xxs = foldr' (++) [] xxs -- Foldr op b (a:b:c:...) == a `op` (b `op` (... `op` b)...) -- foldl op z (a:b:c:...) == ((base `op` a) `op` b) ...) song2 :: String song2 = unlines [ "I got my head checked" , "By a jumbo jet" , "It wasn't easy" , "But nothing is" , "No" ] -- Example use of foldr: unlines (c.f. lines) -- How to feed HO Functions -- 1. Supply a named function unlines' ss = foldr joinLine "" ss where joinLine s1 s2 = s1 ++ "\n" ++ s2 -- 2. Build a function using *sections* -- example: remove negative numbers from a list nonNegatives ns = filter (>= 0) ns -- 3. Build a function using function composition -- example: remove spaces from a string -- isSpace removeSpaces s = filter (not . isSpace) s -- 4. Lambda expressions: anonymous functions -- example: unlines revisited -- unlines' ss = foldr (\s1 s2 -> s1 ++ "\n" ++ s2) "" ss -- where joinLine s1 s2 = s1 ++ "\n" ++ s2 -- f . g = \x -> f (g x) -- 5. Use Partial Application ------------------------------------- -- More ways to build functions: Partial application -- Slides -- Example: A not very useful function: rep :: Int -> (String -> (Char -> String)) rep n s c = concat (replicate n (s++[c])) repfyr :: String -> Char -> String repfyr = rep 4 fyrfallig :: Char -> String fyrfallig = repfyr "hurra" -- redundant brackets in the type help explain partial application: -- Eta reduction ----------------------------------------------------- -- use hlint to find this kind of thing (C-c C-v) ---------------------------------- -- What standard HOFs should I know about? -- hlint gives a few clues -- See the list you get on the exam: -- PreludeFunctions.pdf -- http://www.cse.chalmers.se/edu/year/2018/course/TDA555/Exam/PreludeFunctions.pdf -- Suggested exercises: define the following using all: -- allDigits :: [Int] -> Bool -- checks whether a list of numbers are all single digits (0 to 9) -- alphabetic :: String -> Bool -- checks that the string contains only alphabetic characters -- Example: isSmooth :: Double -> [Double] -> Bool -- isSmooth delta xs - no two successive numbers are more than delta apart -- prop_isSmooth = isSmooth 1 [0, 0.5, 1, 0] && not (isSmooth 2 [2,4,0]) --------------------------------------- -- Aside: -- Fixity. How do you know when to skip brackets? -- $ -- Example summary :: FilePath -> IO String summary f = do s <- readFile f return $ unlines $ take 3 $ lines s -- return . unlines . take 3 . lines $ s -- infixr 0 $ -- f $ x = f x