我正在尝试使用 Haskell 进行目录结构的递归下降。我只想根据需要(懒惰地)检索子目录和文件。
我编写了以下代码,但是当我运行它时,跟踪显示在第一个文件之前访问了所有目录:
module Main where
import Control.Monad ( forM, forM_, liftM )
import Debug.Trace ( trace )
import System.Directory ( doesDirectoryExist, getDirectoryContents )
import System.Environment ( getArgs )
import System.FilePath ( (</>) )
-- From Real World Haskell, p. 214
getRecursiveContents :: FilePath -> IO [FilePath]
getRecursiveContents topPath = do
names <- getDirectoryContents topPath
let
properNames =
filter (`notElem` [".", ".."]) $
trace ("Processing " ++ topPath) names
paths <- forM properNames $ \name -> do
let path = topPath </> name
isDirectory <- doesDirectoryExist path
if isDirectory
then getRecursiveContents path
else return [path]
return (concat paths)
main :: IO ()
main = do
[path] <- getArgs
files <- getRecursiveContents path
forM_ files $ \file -> putStrLn $ "Found file " ++ file
如何将文件处理与下降交错进行?问题是files <- getRecursiveContents path
操作在以下操作之前执行forM_
in main
?
这正是迭代器/协程旨在解决的问题。
你可以轻松地做到这一点pipes
。我对你做的唯一改变getRecursiveContents
是为了让它成为Producer
of FilePath
和到respond
与文件名而不是返回它。这让下游立即处理文件名,而不是等待getRecursiveContents
完全的。
module Main where
import Control.Monad ( forM_, liftM )
import Control.Proxy
import System.Directory ( doesDirectoryExist, getDirectoryContents )
import System.Environment ( getArgs )
import System.FilePath ( (</>) )
getRecursiveContents :: (Proxy p) => FilePath -> () -> Producer p FilePath IO ()
getRecursiveContents topPath () = runIdentityP $ do
names <- lift $ getDirectoryContents topPath
let properNames = filter (`notElem` [".", ".."]) names
forM_ properNames $ \name -> do
let path = topPath </> name
isDirectory <- lift $ doesDirectoryExist path
if isDirectory
then getRecursiveContents path ()
else respond path
main :: IO ()
main = do
[path] <- getArgs
runProxy $
getRecursiveContents path
>-> useD (\file -> putStrLn $ "Found file " ++ file)
这会在遍历树时立即打印出每个文件,并且不需要惰性IO
。更改文件名的操作也很容易,因为您所要做的就是切换出文件名useD
阶段与您的实际文件处理逻辑。
要了解更多信息pipes
,我强烈推荐你阅读Control.Proxy.教程.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)