2016-12-31 76 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