Presentation on theme: "Haskell Chapter 5, Part I. Topics Higher Order Functions map, filter Infinite lists Get out a piece of paper… we’ll be doing lots of tracing."— Presentation transcript:
Haskell Chapter 5, Part I
Topics Higher Order Functions map, filter Infinite lists Get out a piece of paper… we’ll be doing lots of tracing
Higher Order Functions A function that can take functions as parameters OR A function that returns a function as result Think of calculus. What sort of operation takes a function and returns another function? Think of AI. What aspects of human behavior might you model with a higher order function?
First simple example - map Map (built in) takes a function and a list, applies function to every element in the list map' :: (a->b) -> [a] -> [b] map' _  =  map' f (x:xs) = f x : map' f xs Try: map' even [1,2,3,4,5] map ' square [1,2,3,4,5] (assumes square is defined) map' (++ "!") ["snap", "crackle", "pop"] map fst [(1,2), (3,5), (7,8)] Can you explain the type signature?
More mapping map (+3) [4,7,9] [x+3 | x <- [4,7,9]] -- equivalent, maybe less readable Nested maps map (map (^2)) [[1,2],[3,4],[5,6]] Trace this On paper: write result Think about how it works
Another simple example - filter Takes a predicate function and a list, returns a list of elements that satisfy that predicate filter' :: (a -> Bool) -> [a] -> [a] filter' _  =  filter' p (x:xs) | p x = x : filter' p xs | otherwise = filter' p xs Try filter' (>3) [1,2,6,3] filter (== 3) [1,2,4,5] Trace this
Sections What if you want to partially apply an infix function, such as +, -, /, *? Use parentheses: (+3) (subtract 4) needed; (-4) means negative 4, not subtraction (/10) (*5) (/10) 200
Quick exercise Create a simple map that cubes the numbers in a list, e.g., [1,2,3] => [1,8,27] Create a map that takes a nested list and removes the first element of each list, e.g., [[2,4,5],[5,6],[8,1,2]] => [[4,5],,[1,2]] Using `elem` and filter, write a function initials that takes a string and returns initials (assume only initials are caps), e.g., “Cyndi Ann Rader” => “CAR” Write a function named noEven that takes a nested list and returns a nested list of only the odd numbers. e.g., noEven [[1,2,3],[4,6]] => [[1,3],]
Infinite List Examples
More interesting examples largestDivisible :: Integral a => a -> a largestDivisible num = head (filter p [100000, ]) where p x = x `mod` num == 0 Goal: find the largest number under 100,000 that’s divisible by num Note the infinite list… since we use only the head, this will stop as soon as there’s an element Order of list is descending, so we get the largest What is p??? It’s a predicate function created in the where. Try it: largestDivisible 3829 => largestDivisible 113 => largestDivisible 3 => 99999
takeWhile takeWhile takes a predicate and a list, returns elements as long as the predicate is true sum (takeWhile (<10) [1..100]) takeWhile (/= ' ') "what day is it?" Find the sum of all odd squares < 10,000 need to create squares select only odd squares stop when square >= 10,000 sum (takeWhile (<10000) (filter odd (map (^2) [1..]))) OR sum (takeWhile (<10000) [m | m <- [n^2 | n <- [1..]], odd m]) Trace these – walk through first couple of steps
Thunks* Lists are lazy [1,2,3,4] is really 1:2:3:4: When first element is evaluated (e.g., by printing it), the rest of the list 2:3:4: is a promise of a list – known as a thunk A thunk is a deferred computation * from chapter 9
A fun problem Collatz sequence/chain Start with any natural number If the number is 1, stop If the number is even, divide it by 2 If the number is odd, multiply it by 3 and add 1 Repeat with the result number Example: start with 13 -> 40 -> 20 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1 Mathematicians theorize that for all starting numbers, the chain will finish at the number 1. Our goal: for all starting numbers between 1 and 100, how many have Collatz chains with length > 15? Think about: what kinds of problems are we solving here?
The code chain :: Integer -> [Integer] chain 1 =  chain n | even n = n : chain (n `div` 2) | odd n = n : chain (n*3 + 1) numLongChains :: Int numLongChains = length (filter isLong (map chain [1..100])) where isLong xs = length xs > 15 Discuss this
A curried example :t max => max :: Ord a => a -> a -> a equivalent to max :: (Ord a) => a -> (a -> a) max 4 5 === (max 4) 5 (max 4) returns a partially applied function Try: (max ((max 4) 5)) 3 Try: (max 4) 5 max 4 5 max 5 35 max 4 max 4 _ max max 5 _ 5 5
Can’t show a function *Main> (max 4) :88:1: No instance for (Show (a0 -> a0)) arising from a use of `print' Possible fix: add an instance declaration for (Show (a0 -> a0)) In a stmt of an interactive GHCi command: print it What?? (max 4) produced a function of type (a0 -> a0) But functions aren’t instances of Show, so GHCi doesn’t know how to display Compare to Scheme:
Another example multThree :: Int -> Int -> Int -> Int multThree x y z = x * y * z multThree => 135 ((multThree 3) 5) 9 multThree multThree 3 multThree 3 multThree * I’m not saying this is how it’s implemented… just a way to think about it…
multThree continued multThree :: Int -> Int -> Int -> Int multThree x y z = x * y * z multThree => 135 ((multThree 3) 5) 9 multThree :: Int -> (Int -> (Int -> Int)) – equivalent A. function takes Int, returns function of type (Int -> (Int ->Int)) B. that function takes an Int, returns function of type (Int -> Int) C. that function takes an Int, returns an Int multThree multThree 3 multThree 3 multThree A B C Discuss this
Take advantage of currying You can store a partially applied function: *Main> let multTwoWithNine = multThree 9 *Main> multTwoWithNine multThree 9 multThree 9 _ _ multTwoWithNine 2 (9) 2 _ 3 multTwoWithNine 9 2 _ 54
How could we use this? multThreeF.10 multThreeF 10 _ _ tenPctDiscount Write the code in Play and Share 4 tenPctDiscount What if you wanted a 20% discount? 25%?
Another Example multThree 2 multThree 2 doubleArea Write the code in Play and Share 4 doubleArea doubleArea
Play and Share Write a function doubleArea that takes a width and height and returns 2 * the area – making use of multThree (could clearly be done directly, but use multThree for curry practice). doubleArea 4 5 => 40 Write a function multThreeF that works with floating point values. (hint: use Num a as a class constraint) Write a function tenPctDiscount that takes two numbers and calculates a 10% discount (using your multThreeF, of course) tenPctDiscount 4 5 => 2.0 Write a function named pctDiscount that takes a floating point and returns a partially applied function. Usage: *Main> let sale = pctDiscount 0.5 *Main> sale 4 5 10.0 *Main> (pctDiscount 0.5) 4 5 10.0
More Play and Share Curried functions are convenient with map Write a function total that takes a discount % and two numbers stored in a list, and returns the discount amount total 0.1 [4,5] => 2.0 Write a function totalTenPct that returns a partially applied total function with discount set to 0.1 Try using this with map: map totalTenPct [[4,5],[8,10]] => [2.0, 8.0] Play with other uses of map, e.g., map (multThree 3 4) [5,6,7]