`forever`:如何将信息转发到下一次迭代?

Tob*_*ann 7 monads haskell loops

有一个线程在队列中等待新输入以保护它到文件系统.它还会创建备份副本.该SSCCE看起来是这样的:

import Control.Concurrent
import Control.Concurrent.STM
import Control.Monad
import Data.Time.Clock.POSIX

main :: IO ()
main = do
    contentQueue <- atomically $ newTQueue
    _ <- forkIO $ saveThreadFunc contentQueue
    forever $ do
        line <- getLine
        atomically $ writeTQueue contentQueue line

saveThreadFunc :: TQueue String -> IO ()
saveThreadFunc queue = forever $ do
    newLine <- atomically $ readTQueue queue
    now <- round `fmap` getPOSIXTime :: IO Int
    writeFile "content.txt" newLine
    -- todo: Backup no more than once every 86400 seconds (24 hours).
    backupContent now newLine

backupContent :: Int -> String -> IO ()
backupContent t = writeFile $ "content.backup." ++ show t
Run Code Online (Sandbox Code Playgroud)

现在,如果备份不会每24小时写一次以上就会很棒.在命令式编程中,我可能会int lastBackupTime在"永久循环"中使用一个mutable saveThreadFunc.如何在Haskell中实现相同的效果?

Tom*_*lis 8

怎么样Control.Monad.Loops.iterateM_?这有点整洁,因为它避免了明确的递归.

iterateM_ :: Monad m => (a -> m a) -> a -> m b

saveThreadFunc :: TQueue String -> Int -> IO ()
saveThreadFunc queue = iterateM_ $ \lastBackupTime -> do
  newLine <- atomically $ readTQueue queue
  now <- round `fmap` getPOSIXTime :: IO Int
  writeFile "content.txt" newLine
  let makeNewBackup = now >= lastBackupTime + 86400
  when makeNewBackup (backupContent now newLine)
  return (if makeNewBackup then now else lastBackupTime)
Run Code Online (Sandbox Code Playgroud)