Jump to content

Haskell/Solutions/Simple input and output

From Wikibooks, open books for an open world

← Back to Simple input and output

Back to the real world

[edit | edit source]
Exercises
Back in the Type Basics chapter, we mentioned that the type of the openWindow function had been simplified. What do you think its type should actually be?

Back in Type Basics, we said:

You need to open a new window which contains all the options that they can change. Let's look at the type signature for this function:

openWindow :: WindowTitle -> WindowSize -> Window

Opening a window, however, implies not just creating it but also drawing it on the screen. The result, therefore, has to have an IO type, just like putStrLn has. The real signature should be:

openWindow :: WindowTitle -> WindowSize -> IO Window

A real example of an openWindow function with such a signature (except for slightly different names) can be found in the HGL package.

Sequencing actions with do

[edit | edit source]
Exercises

Write a program which asks the user for the base and height of a right angled triangle, calculates its area and prints it to the screen. The interaction should look something like:

The base?
3.3
The height?
5.4
The area of that triangle is 8.91
Hint: you can use the function read to convert user strings like "3.3" into numbers like 3.3 and function show to convert a number into string.
main = do
  putStrLn "The base?"
  base <- getLine
  putStrLn "The height?"
  height <- getLine
  putStrLn ("The area of that triangle is " ++ show (0.5 * read base * read height))

Note that the return type for read is inferred from the type of the expression it is in. 0.5*read("10.0") evaluates to 5.0, as expected. read("10.0") results in an error. In such cases a numeric type must be specified: read "10.0" ::Double, for example.

Controlling Actions

[edit | edit source]
Exercises

Write a program that asks the user for his or her name. If the name is one of Simon, John or Phil, tell the user that you think Haskell is a great programming language. If the name is Koen, tell them that you think debugging Haskell is fun (Koen Classen is one of the people who works on Haskell debugging); otherwise, tell the user that you don't know who he or she is.

(As far as syntax goes there are a few different ways to do it; write at least a version using if / then / else.)

With if-statements:

main = do
  putStrLn "Hello, what is your name?"
  name <- getLine
  if name == "Simon" || name == "John" || name == "Phil"
     then putStrLn "I think Haskell is a great programming language."
     else if name == "Koen"
             then putStrLn "I think debugging Haskell is fun."
             else putStrLn "Sorry, I don't know you."

An alternative using a where block:

main = do
  putStrLn "Hello, what is your name?"
  name <- getLine
  putStrLn (message name)
    where
    greatlanguage   = "I think Haskell is a great programming language."
    message "Simon" = greatlanguage
    message "John"  = greatlanguage
    message "Phil"  = greatlanguage
    message "Koen"  = "I think debugging Haskell is fun."
    message _       = "Sorry, I don't know you."

Actions under the microscope

[edit | edit source]
Exercises
  1. Why does the unsweet version of the let binding require an extra do keyword?
  2. Do you always need the extra do?
  3. (extra credit) Curiously, let without in is exactly how we wrote things when we were playing with the interpreter at the beginning of this book. Why can you omit the in keyword in the interpreter, when you'd have to put it in when typing up a source file?
  1. A let name = value in thing binding has the same type as thing. Because we want the binding to be an IO action, the thing needs to be an IO action, so we need a do keyword.
  2. No, not always. Just as in "normal" code, you can omit the do keyword if there's only one IO action following it.
  3. The GHCi interpreter is like one big do-block with some extra magic, so that it converts normal expressions to IO-actions. As in any do-block, you can omit the in keyword.