A few higher-order functions #
We introduce a few convenient higher-order functions.
In Haskell #
filter
#
The function
filterretains elements of a list that satisfy a certain condition.It can be defined as follows:
filter :: (a -> Bool) -> [a] -> [a] filter f xs = [x | x <- xs, f x]
Example. Let us first define an auxiliary function
eventhat maps anInttoTrueiff it is even:even :: Int -> Bool even x = x `mod` 2 == 0 -- `mod` is the "modulo" function, used here in infix formThen
filter even [1,4,5,4,6]evaluates to
[4,4,6].Equivalently, instead of defining the function
even, we could inline it (as an anonymous function) in the expression above, i.e. we could writefilter (\x -> x `mod` 2 == 0) [1,4,5,4,6]
Implement the function
retainIfEqual :: (Int -> Int) -> Int -> [Int] -> [Int]
such that
retainIfEqual f y xs
consists of each element x of xs for which f x is equal to y (in the same order as they appear in xs).
For instance,
retainIfEqual (^2) 4 [2,0,-2,-1,2]
should evaluate to
[2,-2,2]
retainIfEqual :: (Int -> Int) -> Int -> [Int] -> [Int]
retainIfEqual f y = filter (\x -> f x == y)
Reminder. Because
filteris curried, we can call it with its “first argument” only.The result is a function, which takes as input the list to be filtered.
Example.
filter evenis a function. It retains the even numbers of a list of integers.
In other words,
filter even [1,4,5,4,6]is syntactic sugar for
(filter even) [1,4,5,4,6]
Hint. A similar observation can be made for the functions
map,allandany, introduced below.
map
#
The function
mapapplies a function to each element of a list.It can be defined as follows:
map :: (a -> b) -> [a] -> [b] map f xs = [f x | x <- xs]
Examples.
map (+1) [1,4,5,4]evaluates to[2,5,6,5],map even [1,4,5,4]evaluates to[False,True,False,True], andmap (\x -> x `mod` 2 == 0) [1,4,5,4]is equivalent.
Implement the function
trimOdds :: [[Int]] -> [[Int]]
that discards odd numbers from each of the inner input lists.
For instance,
trimOdds [[1,2,6,3],[2,4],[3,3,8],[5,3]]
should evaluate to
[[2,6],[2,4],[8],[]]
trimOdds :: [[Int]] -> [[Int]]
trimOdds = map (filter even)
all and any
#
The functions
allandanyhave type(a -> Bool) -> [a] -> BoolThe expression
all f xsevaluates toTrueifff xevaluates toTruefor every elementxof the listxs.The expression
any f xsevaluates toTrueifff xevaluates toTruefor at least one elementxof the listxs.
Note. We will see how these two functions can be implemented in the section on linear recursion (fourth exercise).
Examples.
all even [4,4,2]evaluates toTrue
all even [1,4,5,4]evaluates toFalse
all even []evaluates toTrue
any even [1,4,5,2]evaluates toTrue
any even [1,3]evaluates toFalse
any even []evaluates toFalse
Implement the function
appearsIn :: (Eq a) => a -> [a] -> Bool
such that appearsIn x xs is True iff x appears in xs.
appearsIn :: (Eq a) => a -> [a] -> Bool
appearsIn x = any (x ==)
Implement the function
restrictTo :: (Eq a) => [a] -> [a] -> [a]
such that restrictTo xs ys consists of all elements of xs that appear in ys, in the same order as they appear in xs (and preserving duplicates).
restrictTo :: (Eq a) => [a] -> [a] -> [a]
-- reuse the function `appearsIn` defined in the previous exercise
restrictTo xs ys = filter (\x -> appearsIn x ys) xs
takeWhile
#
The function
takeWhilehas the same type has the functionfiltertakeWhile :: (a -> Bool) -> [a] -> [a]The list
takeWhile f xsis the longest prefixxs'ofxssuch thatall f xs'evaluates toTrue.We will see how it can be implemented in the section on linear recursion (last exercise).
Examples.
takeWhile even [4,2,2,1,5,2,6]evaluates to[4,2,2]takewhile even [1,3]evaluates to[]takewhile even [4,6,2]evaluates to[4,6,2]takewhile even []evaluates to[]
foldr and foldl
#
foldr
#
The function
foldraggregates the elements of a list.Intuitively,
foldr f z xs:
- aggregates the list
xswith the aggregation functionf, wherezis the default aggregation value (for the empty list).
Example.
foldr (+) 0 [1,2,3]evaluates to6.
In this example:
- the aggregation function is
+, and- the default value is
0.
Definition.
foldrcan be defined recursively as:foldr :: (a -> b -> b) -> b -> [a] -> b foldr _ z [] = z foldr f z (x : xs) = f x (foldr f z xs)
Terminology.
foldr(and its equivalent in other programming languages) is sometimes called a right‑associative fold, because it intuitively aggregates from right to left.
Examples.
foldr (+) 0 [1,2,3]evaluates to1 + (2 + (3 + 0)) = 6foldr (*) 1 [2,3,4]evaluates to2 * (3 * (4 * 1)) = 24foldr (&&) True [True,False]evaluates toTrue && (False && True)) = Falsefoldr (-) 0 [1,2,3]evaluates to1 - (2 - (3 - 0)) = 2
Consider the two functions below:
or :: [Bool] -> Bool
or = foldr (||) False
myFunction :: (a -> Bool) -> [a] -> Bool
myFunction f = or . (map f)
- Evaluate the following expressions:
myFunction (\x -> x > 2) [-2,0,2]myFunction (\x -> x > 2) [3,0,2]myFunction (\x -> x /= 5) [3,0]myFunction (\x -> x /= 5) [5]myFunction (\x -> x /= 5) []
What does the function myFunction do?
myFunction (\x -> x > 2) [-2,0,2]evaluates toFalsemyFunction (\x -> x > 2) [3,0,2]evaluates toTruemyFunction (\x -> x /= 5) [3,0]evaluates toTruemyFunction (\x -> x /= 5) [5]evaluates toTruemyFunction (\x -> x /= 5) []evaluates toFalse
- This function is equivalent to the function
anythat we have seen already.
foldl
#
The function
foldlis the left-associative fold.
Example.
foldl (+) 0 [1,2,3]evaluates to((0 + 1) + 2) + 3 = 6
Definition.
foldris defined as follows:foldl :: (b -> a -> b) -> b -> [a] -> b foldl f z [] = z foldl f z (x : xs) = foldl f (f z x) xs
Note. Observe that
foldlis tail recursive, whereasfoldris not.
Warning.
foldr fandfoldl fmay differ, for the same aggregation functionf.
Example.
foldr (-) 0 [1,2,3]evaluates to1 - (2 - (3 - 0)) = 2foldl (-) 0 [1,2,3]evaluates to((0 - 1) - 2) - 3 = - 6
find
#
The function
find :: (a -> Bool) -> [a] -> Maybe ais defined in the Haskell module
Data.List.We will see how
findcan be implemented (and the meaning ofMaybe a) in the section about the option type (second exercise).The expression
find f xsevaluates to:
Just xifxis the first value inxsfor whichfsisTrue, andNothingotherwise.
Examples.
find even [1,4,5,2,6,1]evaluates toJust 4find even [1,3]evaluates toNothingfind even []evaluates toNothing
flip
#
The function
flipintuitively swaps the arguments of a function with two arguments in curried form.
It can be defined as follows:
flip :: (a -> b -> c) -> b -> a -> c
flip f y x = f x y
Example.
-- Checks whether a list contains an element contains :: (Eq a) => [a] -> a -> Bool -- flip the function `appearsIn` defined in exercise above contains = flip appearsIn