Learn You a Haskell for Great Good 读书笔记 9

9. More IO

IO操作可以直接读取流,也就是说 getLine不只是从termimal拿键盘输入,也可以直接将文件作为流输入,如

1
capslocker < haiku.txt
getContents

迟加载,只有用到他了他才去读, 他会一直读取, 直到碰到EOF或其他停止记号。

interact
1
interact :: (String -> String) -> IO ()

读取输入,经过f变换,输出。

读写文件

1
2
3
4
5
6
import System.IO
main = do
handle <- openFile "girlfriend.txt" ReadMode
contents <- hGetContents handle
putStr contents
hClose handle
1
2
3
openFile :: FilePath -> IOMode -> IO Handle
type FilePath = String
data IOMode = ReadMode | WriteMode | AppendMode | ReadWriteMode
withFile
1
withFile :: FilePath -> IOMode -> (Handle -> IO a) -> IO a

就是上面写法的简化, 结束或异常时自动帮你关闭handle。有点jdk7 try with resouces的意思。

bracket
1
bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c

带java finally操作的IO行为

第一个函数在结束或碰到异常时如何关闭资源,第二函数是具体的操作

1
2
3
4
withFile :: FilePath -> IOMode -> (Handle -> IO a) -> IO a 
withFile name mode f = bracket (openFile name mode)
(\handle -> hClose handle)
(\handle -> f handle)

还有一个bracketOnError 只在异常时跑第一个函数

readFile appendFile writeFile removeFile renameFile

就是省去了中间的handle,不多讲

getArgs getProgName

获取命令行参数,获取程序名。import System.Environment

随机数

1
2
3
4
5
6
7
random :: (RandomGen g, Random a) => g -> (a, g)
ghci> random (mkStdGen 949488) :: (Float, StdGen)
(0.8938442,1597344447 1655838864)
ghci> random (mkStdGen 949488) :: (Bool, StdGen)
(False,1485632275 40692)
ghci> random (mkStdGen 949488) :: (Integer, StdGen)
(1691547873,1597344447 1655838864)

一般随机数将前一个生成的值作为后一个值的Gen来用,保持一致随机

ByteString
1
2
import qualified Data.ByteString.Lazy as B 
import qualified Data.ByteString as S

S是strict版的,读入前必须告诉它要读多少个单位的byte。

B是lazy版的,与getContents不同的是,每次会读一个chunck的内容。一个chunck64KB,看CPU L2Cache。