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.

Deadline

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.

“Question-Answer” Decision Trees

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:

Extended decision tree

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.

About IO

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.

About buffered output

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:

Feel free to use the hlint program to help with many of these issues and other haskell style issues. If a the suggestion from hlint looks like it assumes knowledge about things we haven't covered yet in the lectures, you can ignore it (or possibly include it in a comment in your code).

To the Fire System

Good Luck!

Change Log