我有一個Haskell中的目錄遍歷函式,但我希望它能忽略符號鏈接。 我想出了如何單獨過濾掉檔案,盡管有一個略顯不雅的輔助filterM。 但經過一些診斷,我意識到我沒能過濾符號鏈接的目錄。
我希望能夠這樣寫:
我希望能夠這樣寫:
我希望能夠這樣寫。
--從rootdir輕松回傳(正常)檔案。
getAllFiles :: FilePath -> IO [FilePath]
getAllFiles root = do
nodes <- pathWalkLazy root
--從每個節點獲取檔案路徑。
let files = [dir </> file | (dir, _, files) <- nodes,
file <- 檔案。
不是 ... pathIsSymbolicLink dir]。]
normalFiles <- filterM (liftM not . pathIsSymbolicLink) files
回傳 normalFiles
然而,我所嘗試的所有變化都得到了某種版本的 "無法將預期型別'Bool'與實際型別'IO Bool'相匹配 "的訊息(在理解中沒有過濾子句,它可以作業,但無法過濾這些鏈接的目錄)。
在線資源中以部分形式提示了我可能完全重構該函式的方法,但我非常確定,每一個這樣的變化都會遇到一些類似問題。 串列理解肯定是最直接的方法......如果我能夠以某種方式排除那些作為鏈接的目錄。
后續報道。不幸的是,ChrisB所提供的解決方案與我現有的版本表現(幾乎相同!)。 我定義了三個函式,并在一個測驗程式中運行它們:
-- XXX: debugging
files <- getAllFilesRaw rootdir
putStrLn ("getAllFilesRaw: "/span> show (length files))
files' <- getAllFilesNoSymFiles rootdir
putStrLn ("getAllFilesNoSymFiles: " show (length files'))
files'' <- getAllFilesNoSymDirs rootdir
putStrLn ("getAllFilesNoSymDirs: " show (length files'')
第一個是我的版本,洗掉了normalFiles過濾器。第二個是我的原始版本(去掉listcomp中的型別錯誤)。最后一個是ChrisB的建議。
運行這個,然后也是系統的find工具:
% find $CONDA_PREFIX -type f | wc -l
449667
% find -L $CONDA_PREFIX -type f| wc -l
501153
% haskell/find-dups $CONDA_PREFIX
getAllFilesRaw : 501153
getAllFilesNoSymFiles: 464553 getAllFilesNoSymFiles.
getAllFilesNoSymDirs: 464420
此外,這個問題之所以出現,是因為--為了我自己的自我教育,我已經用一堆語言實作了同樣的應用程式。Python;Golang;Rust;Julia;TypeScript;Bash,除了小毛病,還有Haskell;其他語言也在計劃之中。 這些程式實際上對檔案做了更多的事情,但這并不是這個問題的重點。
。這個問題的重點是,所有其他語言報告的數字與系統find工具相同。 此外,具體的問題是像這樣的事情:
% ls -l /home/dmertz/miniconda3/pkgs/ncurses-6.2he6710b0_1/lib/terminfo
lrwxrwxrwx 1 dmertz dmertz 17 Apr 29 2020 /home/dmertz/miniconda3/pkgs/ncurses-6。 2-he6710b0_1/lib/terminfo -> ./share/terminfo
這里有大約16000個例子(目前在我的系統上),但在另一個版本的工具中看了一些,我特別看到所有其他語言都不包括那個符號鏈接目錄的內容。
uj5u.com熱心網友回復:
編輯:
- 我們現在不只是修復一個Bool / IO Bool的問題,而是要mach find的行為。
- 在看了檔案之后。 這似乎很難在PathWalk庫中合理地執行 所以我只是手工制作了它。 (按照評論中的要求,使用do-notation。)
import System.FilePath
import System.Director
getAllFiles' :: FilePath -> IO [FilePath]
getAllFiles' path = do
isSymlink <- pathIsSymbolicLink path
if isSymlink
--如果這是一個符號鏈接,回傳空串列。
-- 即使這是原始根。(與find的行為一致)
then return [] 。
else do
isFile <- doesFileExist路徑
if isFile
then return [path] -- 如果這是一個檔案,則回傳它。
elsedo
--如果它不是一個檔案,我們假定它是一個目錄。
dirContents <- listDirectory path
--在所有的子目錄上遞回地運行這個函式。
--并累積結果。
fmap concat $ mapM (getAllFiles' . (path </>)) dirContents
原始答案解決了IO Bool / Bool的問題
getAllFiles :: FilePath -> IO [FilePath]
getAllFiles root = pathWalkLazy root
--洗掉屬于符號鏈接的dirs。
>>= filterM ((dir, _, _) -> fmap not $ pathIsSymbolicLink dir)
--扁平化為檔案的串列。
>>= return . concat . map ((dir, _, files) -> map (f -> dir </> f) files)
--洗掉屬于符號鏈接的檔案。
>>= filterM (fmap not . pathIsSymbolicLink)
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/316975.html
標籤:
