Yet Another Haskell Tutorial/Io/Solutions

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  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 s 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.

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 , which ensure the that the program lives on, regardless of whether there's a failure or not; and the  function. Note that we need to pass the handle returned by  (through   to this function, so it knows where to write the input to).

Alternatively, we can make a version with  and   that doesn't use  : 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)