9/05/2009
I’ve released my first package, up now on hackage (haddock docs should be generated soon). The module provides a simple data structure that mirrors a directory tree, and some useful functions for doing IO on directories of files. You can read more about it here.
It’s very likely there are some bugs, especially related to cross platform issues with file names and paths. The module is also fairly bare, so please send me any requests for functionality that I haven’t thought of, as well as any bugs you might find.
You can install it with:
$ cabal install directory-tree
And get the source with:
$ darcs get http://coder.bsimmons.name/code/DirectoryTree/
I hope this is useful to someone!
UPDATE: I’ve just released v0.9.0 of this package which has a number of sneaky changes and additions, most notably the inclusion of a readDirectoryWithL function that allows for lazy directory reading IO. This will let users work with a DirTree read from disk just as if it was a pure lazy data structure, while IO is done in the background as needed. No more exploding code! (hopefully)
30/04/2009
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] }
| File { name :: FileName,
file :: a }
| Failed { name :: FileName,
err :: Exception }
deriving (Show, Eq)
I have created a file with three examples:
- in the first we simulate the command
darcs initialize to illustrate creating a directory of files by hand, and writing it to disk.
- second, we show combining several different directories from around the filesystem and assembling the into a new tree structure.
- 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 http://coder.bsimmons.name/code/DirectoryTree/
8/04/2009
GHC has an extension to the list comprehensions syntax that replicates the functionality of zipWith, by allowing you to have two generators running in parallel. Turn on the extension in GHCi like so:
Prelude> :set -XParallelListComp
I use the extension below to generate an infinite list of random coordinates (scaled to a 1000×1000 grid) using two different Linear Congruential Generators running in parallel. It should be simple to modify the code below to actually run the generators concurrently using Data Parallel Haskell (although I haven’t had a chance to play with that yet).
randPoints :: (Integral i) => i -> [(i,i)]
randPoints s = drop 1 [ (scale x, scale y) | x <- g1 | y <- g2 ]
where
g1 = s : [ (g*22695477 + 1) `mod` 2^32 | g <- g1]
g2 = s : [ (g*1103515245 + 12345) `mod` 2^32 | g <- g2]
scale v = (v `mod` 1000) - 500
Then we can use another list comprehension, this time with boolean guards, to generate random points that lie within an outer circle (and outside an inner circle):
monteDonut = [p | p@(x,y) <- randPoints 42, let b= x^2+y^2, b< 500^2, b> 10000]
Finally from GHCi we can use the Gnuplot library to easily plot the points we generated:
*Main> :m + Graphics.Gnuplot.Simple
*Main> plotDots [Aspect(Ratio 1), XTicks Nothing, YTicks Nothing] (take 10000 monteDonut)
…and we get a nice Monte Carlo donut with sprinkles!: