Haskell Turtle脱离Shell Monad

时间:2018-07-24 08:08:52

标签: haskell haskell-turtle

请帮助我使用Turtle库。 我想编写一个简单的程序来计算磁盘空间使用率。 这是代码:

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]之类的东西,我可以通过使用IOsequence转换为IO [Size]来将其移出。但是我不能使用Shell单子执行此操作,因为它不是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是用于在恒定空间中操纵实体的。也许有一些fold是用IO (Shell Size)来制作Shell (IO Size)的?

谢谢。

2 个答案:

答案 0 :(得分:0)

实际上,我已经通过使用辅助转换成功地摆脱了uname -a

IO

但是现在我想知道有没有更简单的解决方案...

答案 1 :(得分:0)

您有一个IO动作,而您确实想要一个Shell动作。处理该问题的常用方法是使用liftIO方法,因为ShellMonadIO的实例,所以该方法可用。

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

甚至

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

幸运的是,Turtle包本身提供了一些大小函数,可以直接与MonadIO in Turtle.Prelude之类的Shell实例使用,因此您无需使用{{1 }}自己。

现在您实际上必须对它们进行总结,但是您可以使用liftIOfold来做到这一点。

我建议您避免自行打开sum类型。应该保留该功能,以便为API添加全新的功能。在这种情况下,那当然不是必需的。