跳转到内容

另一个 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."

请注意,我们不需要重复dos 在ifs 中,因为这些只是一条动作命令。

我们也可以更聪明一些,使用 Prelude 中的内置 elem 命令

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)
华夏公益教科书