import GHC.Conc (pseq)
import System.Directory (removeFile, renameFile)
import System.IO
main :: IO ()
main = do
let fp = "handleCollision.txt"
h <- openFile fp ReadMode
l <- hGetLine h
(hClose h) `pseq` (func fp)
func :: FilePath -> IO ()
func fp = do
h <- openFile fp ReadMode
cont <- hGetContents h
chk <- openFile ('.':fp) WriteMode >>= (\h -> hPutStrLn h (unlines . map (map succ) $ lines cont) >> hClose h)
chk `pseq` (hClose h `pseq` removeFile fp)
renameFile ('.':fp) fp
在上面的代码中,调用main的结果是尝试删除fp引用的文件时出错。
***异常:DeleteFile“handleCollision.txt”:权限被拒绝(进程无法访问该文件,因为它正由另一个进程使用。)
如果我只调用'func“handleCollision.txt”',则不会发生错误。为什么main中的句柄似乎与func中fp的删除相冲突,尽管'hClose h'被视为严格而'func fp'被视为懒惰?
答案 0 :(得分:5)
您应该使用Control.Parallel.pseq
代替GHC.Conc.pseq
来实现可移植性。但是,它没有按照你的想法做到。
pseq
仅强制对WHNF进行评估。对于表达式(hClose h) :: IO ()
,WNHF就是 - IO
动作的表示。它不执行操作。
取出pseq
。更好的是,使用withFile
之类的方法来避免手动跟踪文件的打开和关闭。
main = do
let fp = "handleCollision.txt"
l <- withFile fp ReadMode hGetLine
func fp
func fp = do
cont <- readFile fp
writeFile ('.':fp) $ unlines $ map (map succ) $ lines cont
renameFile ('.':fp) fp