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