2016-12-31 53 views
2

我并不是哈斯克尔的新手,但在现实世界中并没有太多用处。如何在haskell的文件系统中实现搜索?

所以我想要做的是从一些文件夹开始找到所有的git仓库。基本上我试图通过使用哈斯克尔并发功能来更快地完成这个工作find . -type d -exec test -e '{}/.git' ';' -print -prune

这就是我到目前为止。

import Control.Concurrent.Async 
import System.Directory (doesDirectoryExist) 
import System.FilePath ((</>)) 
import System.IO (FilePath) 


isGitRepo :: FilePath -> IO Bool 
isGitRepo p = doesDirectoryExist $ p </> ".git" 


main :: IO() 
main = putStrLn "hello" 

我发现这个lib具有这种功能mapConcurrently :: Traversable t => (a -> IO b) -> t a -> IO (t b) 这让我想,我需要的是产生懒树数据结构,将反映的文件夹结构。然后与isGitRepo同时过滤,并将其折叠到列表中并打印出来。 那么,我当然知道如何制作data FTree = Node String [FTree]或类似的东西,但我有问题。 如何同时生产?如何在遍历树时生成绝对路径?像那样的问题等等。

回答

2

这让我想到我需要的是产生能反映文件夹结构的懒数据结构。

我不确定你需要一个树形结构。你可能做一个中间这样的结构,但你可以没有一个管理。关键是你需要有O(1)追加(结合你的结果)。差异列表(如dlist)这样做。

如何同时生产?

您已经得到了:使用mapConcurrently

如何在遍历树时生成绝对路径?

listDirectory让你得到下一个可能的路段。您可以通过将每个段添加到现有路径来获取下一个路径(它们不会是绝对路径,除非现有路径是)。


这里是一个工作的功能:

import System.Directory (doesDirectoryExist, listDirectory) 
import System.FilePath ((</>), combine) 
import System.IO (FilePath) 
import Control.Concurrent.Async (mapConcurrently) 
import qualified Data.DList as DL 

-- | tries to find all git repos in the subtree rooted at the path 
findGitRepos :: FilePath -> IO (DL.DList FilePath) 
findGitRepos p = do 
    isNotDir <- not <$> doesDirectoryExist p 
    if isNotDir 
    then pure DL.empty    -- the path 'p' isn't a directory 
    else do 
     isGitDir <- doesDirectoryExist (p </> ".git") 
     if isGitDir 
     then pure (DL.singleton p) -- the folder is a git repo 
     else do     -- recurse to subfolders 
      subdirs <- listDirectory p 
      repos <- mapConcurrently findGitRepos (combine p `map` subdirs) 
      pure (DL.concat repos) 
+0

嘿!如果我想在可用时打印结果怎么办?有了这个版本,它只会在最后打印整个列表(比找到实际更快,这是好的,但仍然)。我可以使用渠道创建解决方案,但也许有更简单的方法? – user1685095

+0

@ user1685095我想一个频道可能是要走的路......或者,你可以使用一些预先构建的东西。快速搜索产生https://hackage.haskell.org/package/concurrent-output-1.7.8/docs/System-Console-Concurrent.html – Alec