code / art / projects

A DirectoryTree Module and Some Examples

UPDATE: I’ve just released this as my first package on hackage. You can read more and write any comments here.

I just put together a library that provides a simple tree data structure to represent the structure of files and directories in the OS. It provides some simple IO functions like readDirectory (analogous to readFile) which “opens” a directory, returning a DirTree of Strings in the IO monad.

The nice thing is that by defining a simple instance for Traversable (and the default instances for Foldable and Functor that we get for free) we get a whole array of nice functions which we can apply to directory structures! For example, we can combine all the text in a directory of files with:

combineFiles :: FilePath -> IO [Char]
combineFiles d = do (_ :/ t) <- readDirectory d
                    return $ F.foldr1 (++) t

(the (_:/t) portion ignores the base directory returned). The DirTree type also includes a constructor for handling failures. Here is the type definition:

data DirTree a = Dir { name :: FileName,
                       contents :: [DirTree a] } --files + directories
               | File { name :: FileName,
                        file :: a }
               | Failed { name :: FileName,
                          err :: Exception }
               deriving (Show, Eq)

I have created a file with three examples:

  1. in the first we simulate the command darcs initialize to illustrate creating a directory of files by hand, and writing it to disk.

  2. second, we show combining several different directories from around the filesystem and assembling the into a new tree structure.

  3. lastly, we use our readDirectoryWith (with Data.ByteString.readFile), and our Foldable instance to hash all the files in a directory structure (with Thomas DuBuisson’s pureMD5 package) and compare it to the hash of a different directory to see if the contents match exactly

There are probably bugs, and there are many useful functions I can think of to add if people think this is useful. I would be interested in hearing your thoughts on the interface, on any functionality you would like added, and anything else!

You can get the module and examples.hs with:

$ darcs get