Haskell Turtle 滚出 Shell Monad

Haskell Turtle get out of Shell Monad

你能帮我 Turtle 图书馆吗? 我想编写简单的程序,计算磁盘 space 使用情况。 这是代码:

getFileSize :: FilePath -> IO Size
getFileSize f = do
  status <- stat f
  return $ fileSize status

main = sh $ do
  let sizes = fmap getFileSize $ find (suffix ".hs") "."

所以现在我有 sizes 类型 Shell (IO Size) 的绑定。但我不能简单地用 sum 倍加起来,因为那里有 IO Size。如果它是类似 [IO Size] 的东西,我可以通过使用 sequence 将其转换为 IO [Size] 来从那里拉出 IO monad。但是我不能用 Shell monad 来做到这一点,因为它不是 Traversable。所以我写了这样的东西

import qualified Control.Foldl as F

main = sh $ do
  let sizes = fmap getFileSize $ find (suffix ".hs") "."
  lst <- fold sizes F.list
  let cont = sequence lst
  sz <- liftIO $ cont
  liftIO $ putStrLn (show (sum sz))  

首先,我将 Shell (IO Size) 折叠到 [IO Size],然后折叠到 IO [Size],然后对列表进行求和。 但我想知道是否有更规范或更优雅的解决方案,因为在这里我创建了两个列表来完成我的任务。我认为 Shell monad 用于以常量 space 操纵实体。也许有一些 foldShell (IO Size) 变成 IO (Shell Size)?

谢谢。

实际上,我在这里通过使用辅助转换

设法摆脱了 IO
sio :: Shell (IO a) -> Shell a
sio s = Shell (\(FoldShell step begin done) ->
                let step' x a = do
                      a' <- a
                      step x a'
                in
                  _foldShell s (FoldShell step' begin done))

但现在我想知道是否有更简单的解决方案来完成此任务...

您有一个 IO 动作,并且您确实想要一个 Shell 动作。通常的处理方法是使用 liftIO 方法,该方法可用是因为 ShellMonadIO.

的一个实例
file <- find (suffix ".hs") "."
size <- liftIO $ getFileSize file

甚至

size <- liftIO . getFileSize =<< find (suffix ".hs") "."

幸运的是,Turtle 包本身提供了一些大小函数,您可以直接使用 MonadIO 实例,例如 Shell in Turtle.Prelude,因此您不需要使用 liftIO你自己。

现在你实际上必须总结这些,但你可以用 foldsum 来做。

我建议您避免破坏 Shell 类型本身。这应该保留用于向 API 添加全新的功能。在这种情况下当然没有必要。