在 monad 转换器中捕获异常

Catching exceptions in monad transformers

我正在使用 haskell-管道递归遍历目录并打印文件。如何处理作为 monad 转换器的 Producer 的异常? brackethandle 在这种情况下不起作用。

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"

您可以从 Pipes.Safe 导入 brackethandle 和其他异常处理工具。