17

Is there some recursive directory walker in Haskell so I could write something like

listing <- walkDir "/tmp"

I would not like to write my own. I can install some dependency from cabal but I want it to be cross platform (at least Linux and Windows).

Björn Lindqvist
  • 16,492
  • 13
  • 70
  • 103
Trismegistos
  • 3,745
  • 2
  • 20
  • 38
  • I wrote the [dir-tree](http://hackage.haskell.org/package/directory-tree) package which should allow a lazy `walkDir` to be defined pretty easily I would guess, e.g. with `toList` provided by the `Foldable` instance. – jberryman Nov 10 '12 at 03:35

4 Answers4

13

Here is one way to list all Haskell files in a directory tree, using directory-tree that is not in a hidden directory (whose name starts with '.'):

import Data.Traversable (traverse)
import System.Directory.Tree (
    AnchoredDirTree(..), DirTree(..),
    filterDir, readDirectoryWith
    )
import System.FilePath (takeExtension)

listFilesDirFiltered = do
    _:/tree <- readDirectoryWith return "C:\\devmy\\code"
    traverse print $ filterDir myPred tree
    return ()
  where myPred (Dir ('.':_) _) = False
        myPred (File n _) = takeExtension n == ".hs"
        myPred _ = True

main = listFilesDirFiltered

Works on both Windows and Linux.

Björn Lindqvist
  • 16,492
  • 13
  • 70
  • 103
  • It's just a constructor defined in the library: http://hackage.haskell.org/packages/archive/directory-tree/0.11.0/doc/html/System-Directory-Tree.html – Mateusz Kowalczyk Aug 12 '13 at 20:11
  • 1
    I like this library a little better than the accepted answer - it's simpler and has less dependencies, yet still just as powerful. It's also compatible with lens, yet doesn't depended on the (huge) lens library if you're not using it. Here's a link to the main hackage page: [directory-tree](http://hackage.haskell.org/package/directory-tree) [EDIT: but don't get me wrong; FilePather is also excellent] – Yitz Aug 19 '13 at 17:42
6

I have a recursive definition for traversing a directory using filepath package:

import Control.Monad
import System.Directory
import System.FilePath
import System.Posix.Files

-- | Traverse from 'top' directory and return all the files by
-- filtering out the 'exclude' predicate.
traverseDir :: FilePath -> (FilePath -> Bool) -> IO [FilePath]
traverseDir top exclude = do
  ds <- getDirectoryContents top
  paths <- forM (filter (not.exclude) ds) $ \d -> do
    let path = top </> d
    s <- getFileStatus path
    if isDirectory s
      then traverseDir path exclude
      else return [path]
  return (concat paths)
Stephane Rolland
  • 34,892
  • 31
  • 111
  • 159
aycanirican
  • 899
  • 8
  • 9
5

http://hackage.haskell.org/package/FilePather has that sort of recursive directory walking functionality.

singpolyma
  • 10,519
  • 3
  • 42
  • 69
2

The filemanip package provides powerful and elegant functions for that. For example it provides a fold function that will recursively call your function down a directory tree. As an example i used it here to recursively list files in a directory starting from the oldest

danza
  • 9,361
  • 7
  • 34
  • 41
  • 1
    @Trismegistos There are some examples [in the source code](http://hackage.haskell.org/package/filemanip-0.3.6.2/docs/src/System-FilePath-Find.html) but it's certainly true that Haskell libraries tend to be under-documented in terms of practical, tutorial advice. I often find I get more out of messing around in ghci than reading the docs. – Daniel Lyons Nov 03 '15 at 21:27