TDA 555
DIT 440
HT 2019

# Introduction to Functional Programming Lab 4B

## Lab Assignment 4B: Famous

### Goal & Purpose

In this assignment you will implement a small guessing game, where the computer tries to guess which famous person you are thinking about. Watch this short video (there is no audio) to find out how the game is supposed to work.

The game maintains some knowledge about famous people (in the form of a decision tree). When the computer fails to guess which famous persion you are thinking about, it asks you for some information that it can use to improve its knowledge. The accumulated knowledge is stored in a file, so that it is retained even if you stop the game and start it again.

Although this is a fairly small and simple the game, it will teach you something about working with IO as well as recursive data types. And, unlike the previous assignments, this time you write the complete program yourself, there are no ready-made modules for you to download, and no step-by-step instructions for how to structure the program, providing a different kind of challenge from the previous assignments.

Must be submitted before Friday, October 25 at midnight (2019).

The submission instructions are similar to those for Lab 4A.

### Requirements & Recommendations

Instead of a list of subtasks that need to be completed in the order given, in this assignment we just give you some overall requirement, recommendations and hints for implementing the game. Read them all before you start writing any code.

• You will need to have a data type (call it `QA`) to represent “Question-Answer” decision trees like the following:

The smallest trees just give the name of a person. Larger trees are built with a question together with two sub-trees, one for the yes answer and one for the no answer. You can assume that all questions are yes-no so you do not need to represent the “yes” and “no” explicitly.

• Add `deriving (Show, Read)`; The `show` function will be used when you store a decision tree into a file. The `Read` class will give you a function `read :: String -> QA` which will help you when you want to build instructions to read a decision tree back from that file.

• Use a representation of the decision tree pictured above as your default tree, to be used when there is no file (`famous.qa`).

#### Playing a round of the game

Once we have a decision tree (either from the file or using the default tree), we start playing a round of the game by walking down the tree, asking questions as we go along. Once you get to a person then the guess has been decided.

So suppose we have played the default decision tree as follows:
```Is she from Europe? yes
Is she a scientist? no
My guess: Is it Queen Elisabeth II? no
OK - you won this time.
```
At this point the game will continue (the text in bold face is typed by the player):
```Just curious: Who was your famous person? Theresa May
Give me a question for which the answer for "Theresa May" is "yes"
and the answer for "Queen Elisabeth II" is "no".
Is she a politician?
```

At this point the game should construct an extended decision tree, as pictured below:

We recommend that this process is implemented using a recursive function

``play :: QA -> IO QA``

Once `play` returns the new decision tree (which will be unchanged if the computer guessed the right answer) then it can be stored back into the file.

If we use `readFile :: FileName -> IO String` and the file does not exist then there will be an error and the program will crash. This is not what we want! Here you should use

``tryIOError :: IO a -> IO (Either IOError a)``

from standard module `System.IO.Error` Using `tryIOError (readFile ...)`, we turn an IO instruction that possibly generates an error into an IO instruction that never generates any error, but instead returns a value that tells us whether or not there was an error. Look at the documentation for the datatypes Either and IOError for more information.

Most operating systems do not write things directly on the screen when the program tells them to. Instead, they wait until a whole line is printed to the screen, and then they actually print it. This can be a nuisance when a question is printed on the screen, and the user has to type the answer on the same line (as we want in this game). To avoid the question not being printed on the screen, we tell the operating system to “flush” the output of the program, i.e. print everything on the screen that we want to print on the screen, not waiting for the end of the current line. A haskell instruction `hFlush stdout` will do this for us, so use it after using `putStr ...` to make sure things get printed right away. You will need to include module `System.IO` for this.

#### Program structure

Most of this program will be IO instructions, but that does not mean that you should not think about defining useful functions which you can reuse in several places, and which help to give your program some nice structure.

As a hint, think about defining a function

``question :: String -> IO String``

which asks a question and returns the answer typed by the user. Using this, you can define

``yesNoQuestion :: String -> IO Bool``

which asks a yes-no question (repeatedly if needed) until it gets either answer “yes” or “no”, and it returns `True` when the answer was yes, and `False` when the answer was no. This can be used in several places in your program.

#### Main function

The whole game should be defined as

``main :: IO ()``

Then you can run the game from the terminal by typing `runhaskell Famous` (which does the same as loading the file in `ghci` and typing `main`). You can also compile your program into a standalone executable file.

## Submission Instructions

You must submit using the Fire system in groups of 3.

You should only submit: your version of `Famous.hs`. Do not upload any other files.

Before you submit your code, spend some time on cleaning up your code; make it simpler, remove unneccessary things, etc. We will reject your solution if it is not clean. Clean code:

• Does not have long lines (< 78 characters)
• Has a consistent layout (avoid using TAB characters in your code)
• Has type signatures for all top-level functions that you are asked to write