I'm learning Haskell, and my goal today is to write a function sizeOf :: FilePath -> IO Integer
(calculate the size of a file or folder), with the logic
path
is a file, System.Directory.getFileSize path
path
is a directory, get a list of its contents, recursively run this function on them, and sum
the resultsreturn 0
Here's how I'd implement it in Ruby, to illustrate (Ruby notes: map
's argument is the equivalent of \d -> size_of d
, reduce :+
is foldl (+) 0
, any function ending ?
returns a bool, returns are implicit):
def size_of path
if File.file? path
File.size path
elsif File.directory? path
Dir.glob(path + '/*').map { |d| size_of d }.reduce :+
end
end
Here's my crack at it in Haskell:
sizeOf :: FilePath -> IO Integer
sizeOf path =
do
isFile <- doesFileExist path
if isFile then
getFileSize path
else do
isDir <- doesDirectoryExist path
if isDir then
sum $ map sizeOf $ listDirectory path
else
return 0
I know where my problem is. sum $ map sizeOf $ listDirectory path
, where listDirectory path
returns an IO [FilePath]
and not a FilePath
. But... I can't really imagine any solution solving this. <$>
instead of $
was the first thing that came to mind, since <$>
I understood to be something that let a function of a -> b
become a Context a -> Context b
. But... I guess IO isn't like that?
I spent about two hours puzzling over the logic there. I tried it on other examples. Here's a relevant discovery that threw me: if double = (*) 2
, then map double [1,2,3] == [2,4,6]
, but map double <$> [return 1, return 2, return 3] == [[2],[4],[6]]
... it wraps them in a list. I think that's what happening to me but I'm way out of my depth.
You'd need
sum <$> (listDirectory path >>= mapM sizeOf)
Explanation:
sum
over an IO [Integer]
is ok, so we need to get such a thing.listDirectory path
gives us IO [FilePath]
, so we need to pass each file path to sizeOf
. This is what >>=
together with mapM
does.map
alone would give us [IO Integer]
that is why we need mapM
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With