Working with functions
1 2 3 4 5 6 7 | sum :: [Int] -> Int
sum [] = 0
sum (x:xs) = x + sum xs
product :: [Int] -> Int
product [] = 1
product (x:xs) = x * product xs
|
Note the similarities in the two examples. Both functions combine the elements of the list with a binary operation. We can abstract out the similarities into a higher-order function.
We abstract out the binary operation as well as the default value into a function called aggregate, shown below:
1 2 3 4 | aggregate :: (Int -> Int -> Int) -> Int -> [Int] -> Int
aggregate combine default [] = default
aggregate combine default (x:xs) =
combine x (aggregate combine default xs)
|
Now we can redefine sum and product as:
1 2 | sum = aggregate (+) 0
product = aggregate (*) 1
|
Higher order functions allow us to abstract out common patterns and allow us to define powerful, re-usable functions.
The aggregate function is still highly specialized. The Eta standard library provides many general, useful, higher-order functions:
map :: (a -> b) -> [a] -> [b]
map (* 2) [1..5] == [2,4,6,8,10]
map transforms a list by taking a function that converts each element. Note that map preserves the original structure (doesn't delete or add elements), and each element is operated on independently.
filter :: (a -> Bool) -> [a] -> [a]
filter (> 3) [1..5] == [4,5]
filter takes a list and generates a new list keeping the elements that satisfy the predicate that is supplied.