Please Buy now at Leanpub
Written and illustrated by GetContented.
Published on 2016-05-20.
This is one of the simplest horror games ever. The original idea was by Peter Halasz of http://becauseofgames.com who created it in the programming language C when he was learning how to program.
We’re going to use this little game to learn how to get some input from the user, to sequence chunks of IO code together, and also to see a way to make a program continue until the user wants to stop.
Here is the listing. We explain it below.
main :: IO () main = do putStrLn "You are in a fridge. What do you want to do?" putStrLn "1. Try to get out." putStrLn "2. Eat." putStrLn "3. Die." command <- getLine case command of "1" -> putStrLn "You try to get out. You fail. You die." "2" -> do putStrLn "You eat. You eat some more." putStrLn "Damn, this food is tasty!" putStrLn "You eat so much you die." "3" -> putStrLn "You die." _ -> putStrLn "Did not understand." putStrLn "Play again? write y if you do." playAgain <- getLine if playAgain == "y" then main else putStrLn "Thanks for playing."
This program uses a
do block, which is something we haven’t seen before. This allows you to join many actions together into one single action. There are two main things to know about
do blocks, which we’ll cover below.
Firstly, all of the actions in an
IO do block are executed in the order they’re written. That is, they’re sequenced together. Secondly, using “
<-”, you can connect an inner value from an
IO action on its right to a variable on its left. It’s worth noting that you can only use this
<- syntax within a
do block, though.
You’ll also notice that we have a
case expression. We can use any Haskell expressions we like in a
do block as long as they result in an action of the same type as the
do block’s type.
Anyway, let’s see these things in action with two tiny example programs, one for
do blocks combining and sequencing
IO actions, and one for gathering input from the user.
main :: IO () main = do putStrLn "Hello" putStrLn "There"
Ok, so this program will first print
Hello on the screen, then it will print
There on the next line. The do block takes one or more actions, and packs them into a single action. The type of that do block above is
IO (), just like
main, and in
IO, these actions will be sequenced one after the other as we’ve written them down the page.
And now, getting some input from the user:
main :: IO () main = do putStrLn "What is your name? " theName <- getLine putStrLn ("You said your name is " ++ theName)
Ok here we’re sequencing three actions together. We can get input from the user in Haskell with
getLine. When this program is run, once the first line has been output, it will wait for the user to put some text in and press return. Once they do that, it will have bound that text into the
getLine action, pulled that value out as
theName, and printed out the last line which includes that text the user entered!
If we look back at our original program, and look at the line
command <- getLine, you’ll see
<- is there to pull the
String from the
getLine action and set the variable “
command” to its value. The type of
IO String, which means it’s an
IO action that “contains” a
String when it’s executed. When we use
<-, we can think about it like it’s extracting the
String value from the action (note that this applies only when we’re in an
IO action, though).
Notice, also, that you can put
do blocks within
do blocks. This is called nesting. We’re doing this by having another
do block in the “
2” branch of the
This game has two sections. First it tells the user their options and asks for their input with
getLine, and then depending on what they wrote, it tells them what happened. Next, it asks if they want to play again, and if they do, it runs the whole thing again by calling
main. This is recursion of the whole program. The program is an
IO action, and
do blocks allow us to compose
IO actions, so it’s perfectly fine to have the whole program at the end recursively.
One last thing to note about
do blocks, though, is that they must always end with the same type as the whole
do block. So, becuase ours ends with an
if expression whose resultant type is
IO (), which is the type of the
main function itself, it will work just fine. We’ll see more examples of
do blocks in later chapters.
Homework is to go for a walk with a pad and pen and write a program to add up a few of the numbers on number plates of cars in your street (assuming there are lots of cars around, if not, pick something else where there are lots of numbers). Add them up using the
(+) function, and use either
show. Do this as many times as you need to so that you know how to do it without looking it up. You will probably need to do this in a few different sessions to fully anchor it in your memory. Also, write a function that prints out a greeting.
You’ll notice that we’re giving you lots of repeated homework with
show and the other basics. That’s because we want to make sure you can do it very well. Varied repetition, or practice, is the key to getting very good with a skill.
If you’ve enjoyed reading this, please consider purchasing a copy at Leanpub today
Please follow us, and check out our videos Follow @HappyLearnTutes
Also, Volume 2 is now in beta and being written! Show your support and register your interest at its Leanpub site.