跳轉到內容

另一個 Haskell 教程/Io/解決方案

來自華夏公益教科書,開放的書籍,為開放的世界
Haskell
另一個 Haskell 教程
前言
介紹
入門
語言基礎 (解決方案)
型別基礎 (解決方案)
IO (解決方案)
模組 (解決方案)
高階語言 (解決方案)
高階型別 (解決方案)
單子 (解決方案)
高階 IO
遞迴
複雜度

現實世界中的解決方案

[編輯 | 編輯原始碼]

使用if,我們得到類似的東西

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

注意我們不需要重複doif內部,因為這些只是一個動作命令。

我們也可以更聰明一點,使用elem命令,它內置於 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."

當然,我們不必將所有putStrLns 放入if語句中。我們可以改為寫

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.")

使用case,我們得到類似的東西

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

在這種情況下,實際上並沒有更簡潔。

一個檔案讀取程式

[編輯 | 編輯原始碼]

程式碼可能看起來像這樣

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

這裡唯一有趣的是對bracket的呼叫,它確保程式可以繼續執行,無論是否出現錯誤;以及writeLoop函式。注意我們需要將由openFile(透過bracket)返回的控制代碼傳遞給此函式,以便它知道將輸入寫入哪裡。

或者,我們可以使用readFilewriteFile來製作一個不使用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)
華夏公益教科書