写入文件的好习惯

Good practice to write to a file

在我的程序的主要功能中,我调用了 timesRule,它是一个布尔值 return。在这个函数中,我想写入一个文件。但是,如果我理解正确的话,函数时间规则在写入文件时需要 return IO() 。 我应该如何构建代码以在函数中写入文件 returning 布尔值?

timesRule :: (MultiSet LocalType) -> Bool
timesRule sequent = do 
    let result = MultiSet.concatMap (\x -> if isPrl x then [checkTimes x, checkTimes2 x] else [x] ) sequent
    let file = "tmp/log.txt"
    let content = "TIMES rule: " ++  (show(MultiSet.toList result))
    let log = writeToFile file content
    prefixRule result

使用的函数:

import qualified System.IO.Strict as SIO

writeToFile :: FilePath -> String -> IO()
writeToFile file content = do 
    x <- SIO.readFile file
    writeFile file ("\n"++content)
    appendFile file x

正如@Robin Zigmond 指出的那样,比较明显的解决方案是将您的函数类型更改为 IO Bool

不过,除了调用 writeToFile 之外,您的语法还有一些问题。为了使您的函数 timesRule 具有给定的类型,它需要如下所示:

timesRule :: (MultiSet LocalType) -> Bool
timesRule sequent = -- there is no do here
    let 
        result = MultiSet.concatMap (\x -> if isPrl x then [checkTimes x, checkTimes2 x] else [x] ) sequent

        -- the following two lines are superfluous ...
        file = "tmp/log.txt"
        content = "TIMES rule: " ++  (show(MultiSet.toList result))

        -- ... because this still doesn't work
        log = writeToFile file content

        -- ... and what were you going to use `log` for, anyway?
    in  
        prefixRule result

将您的类型更改为 IO Bool 允许您使用 monadic do 语法。 Bool 本身既没有应用实例也没有 monad 实例,因此没有有意义的 do 语法。 (为了拥有一个应用程序或一个 monad 实例,您需要一个类型函数,如 MaybeIO,仅供参考):

timesRule :: (MultiSet LocalType) -> IO Bool
timesRule sequent = do
    let 
        result = MultiSet.concatMap (\x -> if isPrl x then [checkTimes x, checkTimes2 x] else [x] ) sequent

        file = "tmp/log.txt"
        content = "TIMES rule: " ++  (show(MultiSet.toList result))

    -- the syntax to get the value of type `a` out of `IO a` is this:
    log <- writeToFile file content

    -- the function to turn a value of type `a` into `IO a` is `pure`:
    pure (prefixRule result)

您仍然不使用 log,不妨更换

log <- writeToFile file content

writeToFile file content

鉴于 writeToFile 具有类型 ... -> IO (),() 发音为“unit”,log 的值为 () 因此 log 不包含任何有用的信息(可能)。


不太明显的解决方案是稍微重构您的代码并分离关注点。有时将函数写入文件 and return 一些布尔值确实有意义。在你的情况下,你可能想要一个 returns result 的函数,即将这一行变成一个函数:

MultiSet.concatMap (\x -> if isPrl x then [checkTimes x, checkTimes2 x] else [x] ) sequent

然后你已经有 prefixRule 给你 Bool 并且你有 writeFile。通过这种方式,您可以将纯代码(任何不具有类型 IO something 的代码)与具有 IO 副作用的代码分开。