| Copyright | © Frank Jung 2020 |
|---|---|
| License | GPL-3 |
| Safe Haskell | Safe-Inferred |
| Language | Haskell2010 |
CountEntries
Description
Function variations of counting directory entries from
Chapter 18, Monad Transformers, Real World Haskell by Bryan O'Sullivan, Don Stewart, and John Goerzen.
The original version in the book is countEntriesTrad which here is called
countEntries0.
The Monad Transformer version which in the book is countEntries is
countEntries2 in this code.
The other versions countEntries1 and countEntries3 are my variations of
this code.
GHCi Session
To test these functions in GHCi you need the following packages:
:m + Control.Monad :m + System.Directory :m + System.FilePath
Resources
This is a really good introduction to Monad Transformers, Monday Morning Haskell: Monad Transformers.
Synopsis
- countEntries0 :: FilePath -> IO [(FilePath, Int)]
- countEntries1 :: FilePath -> IO [(FilePath, Int)]
- countEntries2 :: FilePath -> IO [(FilePath, Int)]
- countEntries3 :: FilePath -> IO [(FilePath, Int)]
Documentation
countEntries0 :: FilePath -> IO [(FilePath, Int)] Source #
Count entries in directories for given path.
This is the standard version from "Real World Haskell".
>>>p = "public"
>>>:t listDirectory plistDirectory p :: IO [FilePath]
>>>countEntries0 p[("public",25),("public/src",16)]
countEntries1 :: FilePath -> IO [(FilePath, Int)] Source #
Count entries for a list of paths. (My version.)
Example
What the function returns is a list of tuples of directory and count of entries in that directory:
>>>countEntries1 "public"[("public",25),("public/src",16)]
Explanation
The function composes a number of different system calls. But the
process is simple but clunky using traditional methods. The process will
be much simplified once when Monad Transformers are used in
countEntries2.
>>>p = "public"
Get contents of path ... and filter to report directories only:
>>>(getDirectoryContents p) >>= filterM (\n -> doesDirectoryExist (p </> n))["..","src","."]
List directory ignores current and parent directories:
>>>listDirectory p >>= filterM (\n -> doesDirectoryExist (p </> n))["src"]
Some ways to count number of entries in the path:
>>>ps <- listDirectory p
>>>length ps25
Same as:
>>>listDirectory p >>= return . length25
Which is equivalent to:
>>>liftM length (listDirectory p)25
Recurse into subdirectories:
>>>listDirectory p >>= filterM (\n -> doesDirectoryExist (p </> n)) >>= mapM_ print"src"
countEntries2 :: FilePath -> IO [(FilePath, Int)] Source #
My updated version to count entries in directories for given path.
This updated version of countEntries1 uses WriterT.
countEntries3 :: FilePath -> IO [(FilePath, Int)] Source #
Count entries in directories for given path.
My version using WriterT.
This function takes a FilePath argument and returns an IO action that,
when executed, returns a list of (FilePath, Int) pairs representing
the number of entries in each directory.
The implementation of countEntries3 uses the execWriterT function
from the Writer module to extract the final value
of the writer monad and discard the log. The writer monad is used to
accumulate a list of (FilePath, Int) pairs representing the number of
entries in each directory.
The countEntries3 function is defined in terms of a helper function
go that uses WriterT to accumulate the log of (FilePath, Int) pairs.
The go function first uses listDirectory to get the contents of the
directory specified by the FilePath argument.
It then uses tell to add a tuple of the directory path and the number
of entries in the directory to the log. Next, it uses filterM and
doesDirectoryExist to get a list of sub-directories in the directory.
Finally, it uses mapM_ to recurse into each sub-directory and
accumulate the log.
The countEntries3 function is defined using function composition,
where go is composed with execWriterT using the . operator. This
creates a new function that first applies go to its input, and then
applies execWriterT to the output of go.