Yet Another Haskell Tutorial/Io/Solutions
The RealWorld Solution[edit]
Actions[edit]
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 putStrLn
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.
The IO Library[edit]
A File Reading Program[edit]
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)