再帰的にディレクトリをたどる

いわゆる find。forM ははじめて使った。ただこの実装だと、遅延評価の影響でメモリを馬鹿食いする。次回はこれの改善かな。

しかし例外 API をはじめてまともに使ったけども、とても使いやすいとは言えないな。\e を \_ として評価しないようにしても、型があいまいだと GHC にゴネられる。まぁ型レベルの話は評価するしないには関係ないのだろうけどさ。

import System.Directory (doesDirectoryExist, getDirectoryContents)
import System.FilePath ((</>))
import Control.Monad (forM)
import Control.Exception (catch, evaluate, SomeException)
import System.Environment (getArgs)

import Prelude hiding (catch)

find :: FilePath -> IO [FilePath]
find p = do isDir <- doesDirectoryExist p
            if isDir
              then find' p
              else return [p]
  where find' dir = do names <- getDirectoryContents dir
                       let names' = filter (`notElem` [".", ".."]) names
                       paths <- forM names'
                                     (\name -> find (dir </> name))
                       return (concat paths)

main = mapM_ putStrLn =<< find =<< head' =<< getArgs
  where head' xs = evaluate (head xs)
                   `catch`
                   (\e -> return (e::SomeException) >> return ".")