The RealWorld Solution
Actions
Using if, we get something like:
main = do
hSetBuffering stdin LineBuffering
putStrLn "Please enter your name:"
name <- getLine
if name == "Simon" || name == "John" || name == "Phil"
then putStrLn "Haskell is great!"
else if name == "Koen"
then putStrLn "Debugging Haskell is fun!"
else putStrLn "I don't know who you are."
Note that we don't need to repeat the dos inside the ifs, since these are only one action commands.
We could also be a bit smarter and use the elem command which is
built in to the Prelude:
main = do
hSetBuffering stdin LineBuffering
putStrLn "Please enter your name:"
name <- getLine
if name `elem` ["Simon", "John", "Phil"]
then putStrLn "Haskell is great!"
else if name == "Koen"
then putStrLn "Debugging Haskell is fun!"
else putStrLn "I don't know who you are."
Of course, we needn't put all the putStrLns inside the if
statements. We could instead write:
main = do
hSetBuffering stdin LineBuffering
putStrLn "Please enter your name:"
name <- getLine
putStrLn
(if name `elem` ["Simon", "John", "Phil"]
then "Haskell is great!"
else if name == "Koen"
then "Debugging Haskell is fun!"
else "I don't know who you are.")
Using case, we get something like:
main = do
hSetBuffering stdin LineBuffering
putStrLn "Please enter your name:"
name <- getLine
case name of
"Simon" -> putStrLn "Haskell is great!"
"John" -> putStrLn "Haskell is great!"
"Phil" -> putStrLn "Haskell is great!"
"Koen" -> putStrLn "Debugging Haskell is fun!"
_ -> putStrLn "I don't know who you are."
Which, in this case, is actually not much cleaner.
The IO Library
A File Reading Program
The code might look something like:
module DoFile where
import IO
main = do
hSetBuffering stdin LineBuffering
putStrLn "Do you want to [read] a file, ...?"
cmd <- getLine
case cmd of
"quit" -> do putStrLn ("Goodbye!")
return ()
"read" -> do doRead; main
"write" -> do doWrite; main
_ -> do putStrLn
("I don't understand the command "
++ cmd ++ ".")
main
doRead = do
putStrLn "Enter a file name to read:"
fn <- getLine
bracket (openFile fn ReadMode) hClose
(\h -> do txt <- hGetContents h
putStrLn txt)
doWrite = do
putStrLn "Enter a file name to write:"
fn <- getLine
bracket (openFile fn WriteMode) hClose
(\h -> do putStrLn
"Enter text (dot on a line by itself to end):"
writeLoop h)
writeLoop h = do
l <- getLine
if l == "."
then return ()
else do hPutStrLn h l
writeLoop h
The only interesting things here are the calls to bracket, which
ensure the that the program lives on, regardless of whether there's a
failure or not; and the writeLoop function. Note that we need to
pass the handle returned by openFile (through bracket to
this function, so it knows where to write the input to).
Alternatively, we can make a version with readFile and writeFile that doesn't use bracket:
doRead = do
putStrLn "Enter a file name to read:"
fn <- getLine
txt <- readFile fn
putStr txt
doWrite = do
putStrLn "Enter a file name to write:"
fn <- getLine
txt <- getWriteLines
writeFile fn txt
getWriteLines = do
l <- getLine
if l == "."
then return ""
else do lines <- getWriteLines
return (line++"\n"++lines)
