如何在haskell中实现文件系统中的搜索?

时间:2016-12-31 01:28:07

标签: haskell concurrency

我对haskell并不陌生,但在现实世界中并没有使用它。

所以我想要做的是从一些文件夹开始查找所有git存储库。基本上我只是通过使用haskell并发功能来更快地尝试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]或类似的东西,但我有疑问。 如何同时生产?如何在遍历树时产生绝对路径?像这样的问题等等。

1 个答案:

答案 0 :(得分: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)