I wrote:
...a tool for recursing through directories... How about a built-in function that represents a directory tree as a lazy Data.Tree?
Bryan O'Sullivan wrote:
See System.FilePath.Find in http://hackage.haskell.org/cgi-bin/hackage-scripts/package/FileManip-0.2
Not a very good idea. Representing a directory structure as a tree makes people think they can manipulate it as if it were a tree, which leads to all kinds of nasty bugs when the real world bleeds through the holes in the abstraction.
You are right. Well, I didn't say what I meant by a "lazy Data.Tree" :). Your library is very nice. But - it suffers from the same problem. You use unsafe IO operations to build a "lazy" IO list, and we all know what grief that can lead to. Especially in this application, using that type of "laziness" is really unsafe. Any user must be explicitly aware of potential side effect complications, such as directory structure shifting under your feet as you work, possibly induced by your own traversal if you are not careful. (In my opinion, the documention for Python's os.walk http://docs.python.org/lib/os-file-dir.html#l2h-2715 gives a nice, clear description of what must be avoided during such a traversal.) So I think that what is needed here is something like the following. Based on my experience, this would be a really convenient API: data TraversalDirection = TopDown | BottomUp data Directory = Directory { dirPath :: FilePath, fileNames :: [FilePath], subdirNames :: [FilePath]} -- List all directories in the tree rooted at the given path traverseDirectories :: MonadIO m => TraversalDirection -> FilePath -> ListT m Directory -- List all non-directory files in the tree rooted at the given path traverseFiles :: MonadIO m => TraversalDirection -> FilePath -> ListT m FilePath traverseFiles = join . fmap (liftList . fileNames) . traverseDirectories -- List the paths to all subdirectories in the tree rooted at the given path traverseSubdirs :: MonadIO m => TraversalDirection -> FilePath -> ListT m FilePath traverseSubdirs = join . fmap (liftList . subdirNames) . traverseDirectories Here it is critical that ListT be taken from http://haskell.org/haskellwiki/ListT_done_right and not the broken implementation that comes with mtl. (Finally fixed in 6.8? Please?) You could plug the above into your machinery for "recursion predicates" and all the other nice stuff. -Yitz