Search code examples
haskellhaskell-pipes

Catching exceptions in monad transformers


I'm using haskell-pipes to recursively traverse a directory and print the files. How do I handle exceptions from the Producer, which is a monad transformer? bracket and handle do not work in this case.

import Control.Exception (handle, SomeException(..))
import Control.Monad (unless)
import System.FilePath.Posix ((</>))
import Pipes
import qualified Pipes.Prelude as P
import System.Posix.Directory (DirStream, openDirStream, closeDirStream, readDirStream)
import System.Posix.Files (getFileStatus, isDirectory)

produceFiles :: DirStream -> Producer FilePath IO ()
produceFiles ds = do
  path <- lift $ readDirStream ds
  yield path
  unless (path == "") $ produceFiles ds

getDC :: FilePath -> Producer FilePath IO ()
getDC top = do
  {-
    lift $ handle (\(SomeException e) -> putStrLn (show e)) $ do
    ds <- openDirStream top
    -- DOESN'T WORK: produceFiles ds
    -- I would have to "delift" the above somehow.
    closeDirStream ds
  -}
  ds <- lift $ openDirStream top
  produceFiles ds
  lift $ closeDirStream ds

getDC' :: FilePath -> Producer FilePath IO ()
getDC' top = getDC top >-> P.filter (`notElem` [".", ".."]) >-> P.map (top</>)

getDCR :: FilePath -> Producer FilePath IO ()
getDCR top = for (getDC' top) $ \f -> do
  st <- lift $ getFileStatus f
  if isDirectory st && f /= top
  then getDCR f
  else yield f

test top = runEffect $ for (getDCR top) (lift . putStrLn)

main = test "/usr/share"

Solution

  • You can import bracket, handle and other exception handling facilities from Pipes.Safe.