我编写了一个 Haskell 模块来按广度优先顺序列出目录的所有内容。下面是源代码。
module DirElements (dirElem) where
import System.Directory (getDirectoryContents, doesDirectoryExist)
import System.FilePath ((</>))
dirElem :: FilePath -> IO [[FilePath]]
dirElem dirPath = iterateM (not.null) (concatMapM getDirectoryContents') [dirPath] >>= return.tail
getDirectoryContents' :: FilePath -> IO [FilePath]
getDirectoryContents' dirPath = do
isDir <- do doesDirectoryExist dirPath
if isDir then dirContent else return [] where
dirContent = do
contents <- getDirectoryContents dirPath
return.(map (dirPath</>)).tail.tail $ contents
iterateM :: (Monad m) => (a -> Bool) -> (a -> m a) -> a -> m [a]
iterateM fb f x = do --Notice: Due to the the implementation of >>=, iterateM can't be writen like iterate which gives a infinite list and have type of iterateM :: (Monad m) => (a -> Bool) -> (a -> m a) -> a -> m [a]
if fb x
then do
tail <- do {fx <- f x; iterateM fb f fx}
return (x:tail)
else return []
concatMapM :: Monad m => (a -> m[b]) -> [a] -> m[b]
concatMapM f list = mapM f list >>= return.concat
它工作正常,但是当在大目录上执行时,它会“暂停”一段时间,并弹出所有结果。
经过研究,我发现这是同样的问题sequence $ map return [1..]::[[Int]]
see 为什么 Haskell 序列函数不能惰性或为什么递归单子函数不能惰性 https://stackoverflow.com/questions/14494648/why-the-haskell-sequence-function-cant-be-lazy-or-why-recursive-monadic-function
这种情况每隔一段时间就会出现一次,答案最终是使用像库这样的迭代器。最近最常建议的是Proxy http://hackage.haskell.org/package/pipes图书馆。
- Haskell 中目录的流式递归下降 https://stackoverflow.com/questions/14259229/streaming-recursive-descent-of-a-directory-in-haskell/14261710#14261710
- 较旧的管道解决方案已过时且非迭代解决方案目录树的广度优先遍历并不懒惰 https://stackoverflow.com/questions/12610810/breadth-first-traversal-of-directory-tree-is-not-lazy
我以前见过 Conduit 解决方案和一些优雅的单子解决方案,但我现在找不到它们。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)