Exercises for Week 4: IO and Testing
Here are some exercises designed to help you practice programming with IO, test data generation, and properties.
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.
0 (*). Basic IO
(Questions based on Thompson, Chapter 18).A. Write an IO program which will first read a positive
integer, say n
, and then reads n
integers and writes
their sum. The program should prompt appropriately for its inputs and
explain its output.
B. Write a program which repeatedly reads integers (one per line) until finding a zero value and outputs a sorted version of the inputs read. Which sorting algorithm is most appropriate in such a case?
C. Define the function
such thatrepeat :: IO Bool -> IO () -> IO ()
repeat test op
has the effect of
repeating op
until the condition test
is True
.
1 (*). Properties of the lookup Function
Consider the following standard Haskell function, that looks up an element in a list of pairs (table):Define a propertylookup :: Eq a => a -> [(a,b)] -> Maybe b lookup x [] = Nothing lookup x ((x',y):xys) | x == x' = Just y | otherwise = lookup x xys
prop_LookNothing
that expresses that if the look function
delivers Nothing
,
then the thing we were looking for was not in the table.
Also define a property prop_LookJust
that expresses that if the
look function delivers a result Just
y,
then the pair (x,y) should have been in the table.
Also write a property prop_Look
that combines
prop_LookNothing
and prop_Just
into one property.
2. Properties of the prefixOf function
Consider the following Haskell function (known asisPrefixOf
in the Data.List module), that checks if a list is a prefix of another list:
prefixOf :: Eq a => [a] -> [a] -> Bool prefixOf [] _ = True prefixOf _ [] = False prefixOf (x:xs) (y:ys) = x == y && prefixOf xs ys
Define a property prop_prefixOfSelf
that expresses that taking any number of elements (using take
) from a string s
gives a list which is a prefix of s
.
Can you come up with a similar property for isSuffixOf
(which checks if a list is a suffix of another list)?
An alternative implementation of prefixOf
could be
prefixOf_alt :: Eq a => [a] -> [a] -> Bool prefixOf_alt xs ys = take (length ys) xs == ys
Rather than actually using this definition, try to use this definition as a property. I.e. write a property of prefixOf
that uses take
, length
and ==
as above.
Do you think this is a good property for testing prefixOf
? Think about whether the property is mostly true or mostly false.
3 (*). The Number Guessing Game
In this exercise, you are going to implement the "number guessing game" in Haskell.
Here is an example of how this might work:
Main>The text thatgame
Think of a number between 1 and 100! Is it 50?higher
Is it 75?lower
Is it 62?lower
Is it 56?yes
Great, I won!
looks like this
is what the user types in. The other text is produced by your program.
Implement a function
That plays one instance of this game.game :: IO ()
You might need the following functions:
Before you start programming, think of a good guessing strategy for the computer that minimizes the number of guesses!getLine :: IO String -- reads a line of user input putStrLn :: String -> IO () -- outputs one line of text
4. A Backup Script
The library module System.Directory
provides functions
for working with files and directories.
Use these functions to write a program that
- creates a new directory called "backup",
- copies all the files in the current directory into the backup directory.
Hints: One way to find out what functions
a module contains is so use the :browse
command in GHCi.
Prelude>:module System.Directory
Prelude System.Directory>:browse
... createDirectory :: FilePath -> IO () doesDirectoryExist :: FilePath -> IO Bool ...
This gives you the names and types of the functions, but you probably still need to consult the documentation to find out how to use them. Here's the link to the documentation of the modules included with the latest version of GHC:
You will also perhaps need to perform all of a list of actions. You may find the function
useful for this. (The actual type of sequence is more general, but for now it is easier to think of it as having this more specific type).sequence ::[IO a] -> IO [a]