Haskell Turtle выходит из Shell Monad
Не могли бы вы помочь мне с библиотекой черепахи. Я хочу написать простую программу, которая рассчитывает использование дискового пространства. Вот код:
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]
Я мог вытащить IO
монада оттуда с помощью sequence
превратить его в 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
монада для манипулирования сущностями в постоянном пространстве. Может быть, есть некоторые fold
делать IO (Shell Size)
от Shell (IO Size)
?
Благодарю.
2 ответа
У вас есть IO
действие, и вы действительно хотите Shell
действие. Обычный способ справиться с этим с liftIO
метод, который доступен потому, что Shell
это пример MonadIO
,
file <- find (suffix ".hs") "."
size <- liftIO $ getFileSize file
или даже
size <- liftIO . getFileSize =<< find (suffix ".hs") "."
К счастью, Turtle
Сам пакет предлагает некоторые функции размера, которые вы можете использовать непосредственно с MonadIO
примеры как Shell
вTurtle.Prelude
так что вам не нужно использовать liftIO
сам.
Теперь вы должны суммировать их, но вы можете сделать это с fold
а также sum
,
Я бы порекомендовал вам не взламывать Shell
набери сам. Это должно быть зарезервировано для добавления совершенно новой функциональности в API. Это, конечно, не нужно в этом случае.
На самом деле мне удалось избавиться от 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))
Но теперь мне интересно, есть ли более простое решение этой задачи...