P74 - 不用 do 记法编写 IO
IO monad without do notation
官方模块:
Problems.P74核心函数:askGoldbach
← P73 S 表达式 | P75 Maybe Monad →
题目描述
从输入句柄读取一个偶数,调用 P40 分解,再把 n=a+b 写到输出句柄。要求不用 do,直接使用 (>>=) 和 (>>)。
实现
方法一:»= 绑定风格
1import System.IO (Handle, hGetLine, hPutStr, hPutStrLn)
2
3askGoldbach :: Handle -> Handle -> IO ()
4askGoldbach input output =
5 hGetLine input >>= \text ->
6 let n = read text :: Integer
7 (a,b) = goldbach n
8 in hPutStr output (show n ++ "=")
9 >> hPutStr output (show a ++ "+")
10 >> hPutStrLn output (show b)
(>>=) 把读取到的字符串交给后续函数;(>>) 只关心动作顺序,忽略前一个动作的 () 结果。
方法二:纯格式化后一次输出
1askGoldbach :: Handle -> Handle -> IO ()
2askGoldbach input output =
3 hGetLine input >>=
4 hPutStrLn output . format . (read :: String -> Integer)
5
6format :: Integer -> String
7format n = show n ++ "=" ++ show a ++ "+" ++ show b
8 where
9 (a, b) = goldbach n
这个版本把哥德巴赫分解和字符串拼接留在纯函数 format 中,IO 部分只做一次读取和一次写入。两种方法都遵守“不使用 do”的限制。
方法对比
| 方法 | IO 动作组织 |
|---|---|
| 多次顺序写入 | 用 (>>) 串联三个输出动作 |
| 一次格式化输出 | 纯函数生成整行,只执行一次写入 |
测试
使用内容为 104 的输入句柄时,输出为:
1104=3+101
return 在这里不是命令式语言的“返回语句”,而是把普通值放入某个 Monad 的函数。