I wrote this program that recursively prints all the files and directories starting at the current directory:import Data.Tree (Tree (..))import System.Directory (doesDirectoryExist, getCurrentDirectory, getDirectoryContents)main :: IO ()main = do  currentDirectory <- getCurrentDirectory  tree <- tree currentDirectory .  printTree 0 treeprintTree :: Int -> Tree FilePath -> IO ()printTree indent tree = do  putStrLn $ (replicate indent ' ' ++ rootLabel tree)  mapM_ (printTree $ indent + 2) (subForest tree)treeHelper :: FilePath -> IO [Tree FilePath]treeHelper path =  let filter' = filter (`notElem` [., ..]) in  do    contents <- getDirectoryContents path    trees <- mapM (tree path) (filter' contents)    return treestree :: FilePath -> FilePath -> IO (Tree FilePath)tree parent path =  let fullPath = (parent ++ / ++ path) in  do    isDirectory <- doesDirectoryExist fullPath    case isDirectory of      False -> return $ Node path []      True -> treeHelper fullPath >>= (return . Node (path ++ /))If you run it, it might print something like this:./  dist/    build/      autogen/        cabal_macros.h        Paths_Tree.hs      tree/        tree        tree-tmp/          Main.hi          Main.o    package.conf.inplace    setup-config  Setup.lhs  tree.cabal  Tree.hsI think this is pretty nifty. It's a toy program, so I purposefully left out stuff like error checking and symlink handling and etc. How would you improve this program? Am I duplicating functionality available in a library? Are there places where the code could be tighter? Is my Haskell style not up to snuff?
Recursive directory tree printer
haskell;file system
You can also use unfoldTree (or unfoldTreeM here) to build Data.Tree:import Control.Monadimport System.Directoryimport System.FilePathimport Data.TreedirTree :: FilePath -> IO (Tree FilePath)dirTree root = unfoldTreeM step (root,root)    where step (f,c) = do            fs <- getDirectoryContents f            ds <- filterM doesDirectoryExist fs            return (c, [(f </> d, d) | d <- ds, d /= . && d /= ..])main :: IO ()main = do  t <- dirTree .  putStrLn $ drawTree tUpdate: As Bjrn Lindqvist correctly noted in his edit suggestion, my use of doesDirectoryExist doesn't work here (it uses directory names instead of directory paths).The correct version of dirTree would be:dirTree :: FilePath -> IO (Tree FilePath)dirTree root = unfoldTreeM step (root,root)    where step (p, c) = do            isDirectory <- doesDirectoryExist p            fs <- if isDirectory then getDirectoryContents p else return []            return (c, [(p </> f, f) | f <- fs, f `notElem` [., ..]])