I was discussing some code on Reddit, and it made me curious about how this would be implemented in io-streams. Consider the following code which traverses a directory structure and prints out all of the filenames:
import Control.Exception (bracket) import qualified Data.Foldable as F import Data.Streaming.Filesystem (closeDirStream, openDirStream, readDirStream) import System.Environment (getArgs) import System.FilePath ((</>)) printFiles :: FilePath -> IO () printFiles dir = bracket (openDirStream dir) closeDirStream loop where loop ds = do mfp <- readDirStream ds F.forM_ mfp $ \fp' -> do let fp = dir </> fp' ftype <- getFileType fp case ftype of FTFile -> putStrLn fp FTFileSym -> putStrLn fp FTDirectory -> printFiles fp _ -> return () loop ds main :: IO () main = getArgs >>= mapM_ printFiles
Instead of simply printing the files, suppose we wanted to create some kind of streaming filepath representation. I know how this would work in enumerator, conduit, and pipes. However, since the intermediate steps require acquisition of a scarce resource (the
DirStream), I'm not sure what the implementation would be for io-streams. Can someone provide an example of how that would be done?
For comparison, here's the conduit implementation, which is made possible via
MonadResource. And here's how the conduit code would be used to implemented the same file printing program as above:
import Control.Monad.IO.Class (liftIO) import Control.Monad.Trans.Resource (runResourceT) import Data.Conduit (($$)) import Data.Conduit.Filesystem (sourceDirectoryDeep) import qualified Data.Conduit.List as CL import System.Environment (getArgs) main :: IO () main = getArgs >>= runResourceT . mapM_ eachRoot where -- False means don't traverse dir symlinks eachRoot root = sourceDirectoryDeep False root $$ CL.mapM_ (liftIO . putStrLn)