could you please help me with Turtle library. I want to write simple program, that calculates disk space usage. Here is the code:
getFileSize :: FilePath -> IO Size
getFileSize f = do
status <- stat f
return $ fileSize status
main = sh $ do
let sizes = fmap getFileSize $ find (suffix ".hs") "."
so now I have sizes
bind of type Shell (IO Size)
. But I can't just sum it, with sum
fold, cause there is IO Size
in there. If it was something like [IO Size]
I could pull IO
monad out of there by using sequence
to transform it to IO [Size]
. But I can't do this with Shell
monad since it is not Traversable
. So I wrote something like this
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))
First I folded Shell (IO Size)
to [IO Size]
and then to IO [Size]
to sum list afterwards.
But I wonder if there is more canonical or elegant solution to this, because here I created two lists to accomplish my task. And I throught that Shell
monad is for manipulating entities in constant space. Maybe there is some fold
to make IO (Shell Size)
from Shell (IO Size)
?
Thanks.
You have an IO
action, and you really want a Shell
action. The usual way to handle that is with the liftIO
method, which is available because Shell
is an instance of MonadIO
.
file <- find (suffix ".hs") "."
size <- liftIO $ getFileSize file
or even
size <- liftIO . getFileSize =<< find (suffix ".hs") "."
Fortunately, the Turtle
package itself offers some size functions you can use directly with MonadIO
instances like Shell
in Turtle.Prelude
so you don't need to use liftIO
yourself.
Now you actually have to sum these up, but you can do that with fold
and sum
.
I would recommend that you avoid breaking open the Shell
type itself. That should be reserved for adding totally new functionality to the API. That certainly isn't necessary in this case.