TDA 452
DIT 143
HT 2018

# Functional Programming 2018 Exercises for Week 4

## Exercises for Week 4: IO, Test Data and Properties

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

`repeat :: IO Bool -> IO () -> IO ()`
such that `repeat test op` has the effect of repeating `op` until the condition `test` is `True`.

### 1 (*). Properties of the Look Function

Consider the following standard Haskell function, that looks up an element in a list of pairs (table):
```lookup :: Eq a => a -> [(a,b)] -> Maybe b
lookup x []           = Nothing
lookup x ((x',y):xys)
| x == x'         = Just y
| otherwise       = lookup x xys```
Define a property `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.

Give an implementation of the following functions:
```sequence :: Monad m => [m a] -> m [a]
mapM     :: Monad m => (a->m b) -> [a] -> m [a]
onlyIf   :: Monad m => Bool -> m () -> m ()
```
`sequence` takes a list of instructions resulting in a value of type a, and creates one big instruction that executes all of these, gathering all results into one result list. Example: the instructions
```sequence [ readFile file | file <- files ]
both reads the contents of all files in the list `files`, and produces the contents of each of the files.

`onlyIf` takes a boolean and an instruction, and creates an instruction that only executes the argument instruction if the boolean was `True`. If the boolean was `False`, nothing happens. For example,

`onlyIf failed tryAgain`
executes the instructions tryAgain only if the boolean `failed` is `True`.

Hint: You might find it easier to think of the above functions having type:

```sequence :: [IO a] -> IO [a]
mapM     :: (a->IO b) -> [a] -> IO [b]
onlyIf   :: Bool -> IO () -> IO ()
```

### 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> `game`
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!
```
The text that `looks like this` is what the user types in. The other text is produced by your program.

Implement a function

`game :: IO ()`
That plays one instance of this game.

You might need the following functions:

```getLine :: IO String         -- reads a line of user input
putStrLn :: String -> IO ()  -- outputs one line of text
```
Before you start programming, think of a good guessing strategy for the computer that minimizes the number of guesses!

### 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 perhaps also need to perform all of a list of actions. You may find the function `sequence` from exercise 2 useful for this.

### 5 (*). Generating Lists

Sometimes we want to generate lists of a certain length.

A. Write a generator

`listOf :: Integer -> Gen a -> Gen [a]`
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?

B. Now use `listOf` 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`:

```zip :: [a] -> [b] -> [(a,b)]
unzip :: [(a,b)] -> ([a],[b])
```
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?

### 6. Generating Ordered Lists

A.Write a function `ordered` that checks if a list is ordered; each element in the list should be smaller than or equal to the next element.

B. Write a generator that generates random lists of integers that are sorted (ordered). You are not allowed to make use of the function sort! (And not of the generator orderedList 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.