Exercises for Week 5: Higher-Order Functions and Test Data Generation
Here are some exercises designed to help you practice programming with higher-order functions and test data.Please prepare yourself for these exercises by printing them out, and also printing out the code samples and documentation that is referred to by links.
If you do not have time to do all these exercises, don't worry. The exercises are intended to provide enough work to keep the most experienced students busy. If you do all exercises marked with an (*) you have probably understood this week's material.
Some of the exercises below involve writing QuickCheck properties. The parts of those exercie that require you to run QuickCheck are obviously not so suited for doing in the group exercises. These parts you can do yourself at home, either before the exercise session (as preparation), or after.
Good luck!
1 (*). Exercises from chapter 9-10 of The Craft of Functional Programming
(*) Define the
length
function usingmap
andsum
.(*) What does
map (+1) (map (+1) xs)
do? Can you conclude anything in general about properties ofmap f (map g xs)
, wheref
andg
are arbitrary functions?Give the type of, and define the function
iter
so that
whereiter n f x = f (f (... (f x)))
f
occursn
times on the right-hand side of the equation. For instance, we should haveiter 3 f x = f (f (f x))
anditer 0 f x
should returnx
.What is the type and effect of the following function?
where\n -> iter n succ
succ
is the successor function, which increases a value by one:succ 33
34(*) How would you define the sum of the squares of the natural numbers 1 to
n
usingmap
andfoldr
?How does the function
behave?mystery xs = foldr (++) [] (map sing xs) where sing x = [x]
(*) If
id
is the polymorphic identity function, defined byid x = x
, explain the behavior of the expressions(id . f) (f . id) (id f)
Iff
is of typeInt -> Bool
, at what instance of its most general typea -> a
isid
used in each case?Define a function
composeList
which composes a list of functions into a single function. You should give the type ofcomposeList
, and explain why the function has this type. What is the effect of your function on an empty list of functions?(*) Define the function
which reverses the order in which its function argument takes its arguments.flip :: (a -> b -> c) -> (b -> a -> c)
The following example shows the effect of
flip
:flip div 3 100
33
Do not forget to write suitable QuickCheck properties checking that your definitions behave as expected.
(To QuickCheck properties that take function arguments, make sure to
import Text.Show.Functions
!)
2 (*). List Comprehensions and Higher-Order Functions
Can you rewrite the following list comprehensions using the higher-order functionsmap
and filter
? You might need the function
concat
too.
-
[ x+1 | x <- xs ]
-
[ x+y | x <- xs, y <-ys ]
-
[ x+2 | x <- xs, x > 3 ]
-
[ x+3 | (x,_) <- xys ]
-
[ x+4 | (x,y) <- xys, x+y < 5 ]
-
[ x+5 | Just x <- mxs ]
Can you do it the other way around? I.e. rewrite the following expressions as list comprehensions.
-
map (+3) xs
-
filter (>7) xs
-
concat (map (\x -> map (\y -> (x,y)) ys) xs)
-
filter (>3) (map (\(x,y) -> x+y) xys)
3 (*). Generating Lists
Sometimes we want to generate lists of a certain length.
A. Write a generator
such that listOf n g generates a list of n elements, where each element is generated by g. What property would you write to test that your generator behaves as it should?listOfLength :: Integer -> Gen a -> Gen [a]
B. Now use listOfLength
to write a generator that generates pairs of lists of the
same, random, length.
C.Take a look at the standard Haskell functions zip and unzip:
Write down two properties for these; one that says that zip is the inverse of unzip, and one that unzip is the inverse of zip. Note that unzip is not always the inverse of zip, so you need a condition! Could you make use of the generator you just defined?zip :: [a] -> [b] -> [(a,b)] unzip :: [(a,b)] -> ([a],[b])
Hint: make a datatype
and use your generator for part B. to make a generator for the above type. Then, make the above type an instance of Arbitrary. Finally, you can use it to write your property.data TwoSameLengthLists a = SameLength [a] [a]
Another possibility is to use the QuickCheck function
forAll
, which we might see later on in the course.
4. Generating Ordered Lists
Write a generator that generates random lists of integers that are sorted (ordered), without using of the function sort! (And not of the generatororderedList
from the lecture either...)
Hint: First generate a list of random, positive integers. Then, generate a first, random number in the list. Then, produce a list where the differences between each consecutive pair of elements is given by the list of positive integers.
Make sure to check that your generator generates ordered lists by writing a suitable property!