I am studying Haskell, and today my task is to write the function sizeOf :: FilePath -> IO Integer (calculate the size of a file or folder), with logic
- If
path is a file, System.Directory.getFileSize path - If
path is a directory, get a list of its contents, recursively run this function on them, and sum results - If it is something other than a file or directory,
return 0
Here is how I could implement it in Ruby to illustrate (Ruby notes: map arguments are equivalent to \d -> size_of d , reduce :+ is foldl (+) 0 , any terminating function ? Returns bool, returns 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 is my crack on 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 IO [FilePath] , not a FilePath . But ... I can not imagine any solution to resolve this. <$> instead of $ was the first thing that came to mind, since <$> I realized that the function a -> b becomes Context a -> Context b . But ... I think this is not so?
I spent about two hours puzzling the logic. I tried this with other examples. Here is the corresponding 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]] ... he transfers them to the list. I think that what happens to me, but I came out of the depths.
source share