我玩過Haskell,但只是玩過而已。 對于真正的不可變性的作業,我感到很困惑。
具體來說,我有以下函式(現在它主要是我扔進去的除錯東西)。
type BySize = Map Int [Finfo]
-- ...其他東西 ...
-- 走動目錄并回傳地圖
walkDir :: String -> BySize -> IO ([BySize] )
walkDir rootdir bySize = do.
let !bySizeHist = [bySize] 。
pathWalk rootdir (
oot dirs files -> do !
forM_ files $ (file -> do)
let !new=head bySizeHist
finfo <- do processPath(joinPath [root, file]) latest
let !new = addBySize (f_size finfo) finfo latest
let latest_size = Map.key latest
let new_size = Map.key new
let error = if latest == new
then
"錯誤,相同的地圖!"。
else
"地圖的更新是好的" (顯示 latest_size) (顯示 new_size)
putStrLn錯誤
let !bySizeHist = [new] bySizeHist
putStrLn (fname finfo) ))
回傳 bySizeHist
基本上,我的目標是得到一個Map,它的鍵是檔案大小,而Finfo(檔案資訊)data結構的串列是值。 我嘗試了很多不同的變化,這僅僅是最新的一個不起作用的變化。
我知道Maps是不可改變的,所以我希望能生成一個版本的串列,然后利用下游的最新版本。 但我認為maybe我應該使用State monad來代替。我實際上并不關心 Map 版本的歷史,我只是在摸索中嘗試。
函式addBySize本身就可以作業。 也就是說,給定大小和一個新的 Finfo 物件,它正確地回傳一個基于舊 Map 的新 Map,但是添加了一個新的鍵,或者用新的 Finfo 物件擴展了現有鍵映射到的串列。
問題是 "重新系結"bySizeHist的嘗試失敗了(我認為是因為在回圈中超出了范圍)。 因此,盡管我想在每次通過回圈時不斷地呼出一個不斷擴大的鍵串列,但我得到的結果卻是:
% haskell/find-dups haskell
Update of map is fine[] [6]
/home/dmertz/git/LanguagePractice/haskell/that
Update of map is fine[][3235]
/home/dmertz/git/LanguagePractice/haskell/sha1sum.hi
Update of map is fine[][8160]
/home/dmertz/git/LanguagePractice/haskell/sha1sum.o
Update of map is fine[] [241]
/home/dmertz/git/LanguagePractice/haskell/sha1sum.hs
Update of map is fine[][6]
即latest從來都不是真正意義上的Map的最新版本,但我總是在每個回圈中添加new,但總是添加到空的BySize Map。
下面提出的解決方案對我們有很大的幫助。 然而,我希望能排除符號鏈接。
我對getAllFiles進行了一些修改,以嘗試排除符號鏈接。 但我的方法未能排除屬于符號鏈接的目錄。 我嘗試了一些變化,但都不起作用。 我所擁有的版本只是部分地起了作用:
--從rootdir輕松回傳(正常)檔案。
getAllFiles :: FilePath -> IO [FilePath]
getAllFiles root = do
nodes <- pathWalkLazy root
--從每個節點獲取檔案路徑。
let files = [dir </> f | (dir, _, files) <- nodes, f <- files ]
normalFiles <- filterM (liftM not . pathIsSymbolicLink) files
回傳 normalFiles
uj5u.com熱心網友回復:
我會讓別人直接回答你的問題,但正確的方法可能是不要這樣做。 你想寫的程式是:
getBySize :: FilePath -> IO BySize
getBySize root = do
--首先,獲取所有的檔案。
files <- getAllFiles root
-- 將它們全部轉換為 finfos 。
finfos <- mapM getFinfo files
--得到一個尺寸/資訊對的串列。
let pairs = [(f_size finfo, finfo)| finfo <- finfos]
--將其轉換為一個地圖,允許重復的鍵。
回傳 $ fromListWithDuplicates 對
這是一種合理的、功能性的方法來完成你的目標。 你一次抓取所有的檔案名,并應用一些功能轉換(到Finfos,到對,到Map)。 不需要對可變性或狀態進行處理。
撰寫fromListWithDuplicates有點復雜,但它是標準的。 它經常被重寫,以至于它或類似的東西可能應該成為Data.Map的一部分:
fromListWithDuplicates :: Ord k => [(k, v)] -> Map k [v]
fromListWithDuplicates pairs = Map.fromListWith ( ) [(k, [v]) | (k, v) <- pairs)
這個想法是,它接收鍵值對的串列,將所有的值轉換為單子串列,然后使用fromListWith來產生一個地圖,在有重復的情況下將這些單子串聯起來。
你可能已經有一個getFinfo函式,不管你的Finfo是什么。 我使用下面的方法進行測驗:
data Finfo = { f_path : : FilePath, f_size :: Int } 。
getFinfo :: FilePath ->IO Finfo
getFinfo path = do
sz <- getFileSize path
回傳 $ Finfo path (fromIntegral sz)
唯一剩下的函式是getAllFiles,它得到一個所有檔案的串列(作為全路徑名稱,已經與父目錄連接)。 一種寫法是用pathWalkLazy從System.Directory.PathWalk:
getAllFiles :: FilePath -> IO [FilePath]
getAllFiles root = do
nodes <- pathWalkLazy root
--從每個節點獲取檔案路徑。
let files = [dir </> file | (dir, _, files) <- nodes, file <- files]
回傳檔案
一個完整的示例程式。 它只需要一個引數,即要處理的目錄。
import System.Director
import System.Directory.PathWalk
import 系統.環境
import System.FilePath
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
type BySize = Map Int [Finfo] /span>
getBySize :: FilePath -> IO BySize
getBySize root = do
--首先,獲取所有的檔案。
files <- getAllFiles root
-- 將它們全部轉換為 finfos 。
finfos <- mapM getFinfo files
--得到一個尺寸/資訊對的串列。
let pairs = [(f_size finfo, finfo)| finfo <- finfos]
--將其轉換為一個地圖,允許重復的鍵。
回傳 $ fromListWithDuplicates 對
--這有點復雜,但卻是標準的。
fromListWithDuplicates :: Ord k => [(k, v)] -> Map k [v]
fromListWithDuplicates pairs = Map.fromListWith ( ) [(k, [v]) | (k, v) < - pairs]
getAllFiles :: FilePath -> IO [FilePath]
getAllFiles root = do
nodes <- pathWalkLazy root
--從每個節點獲取檔案路徑。
let files = [dir </> file | (dir, _, files) <- nodes, file <- files]
回傳檔案
data Finfo = Finfo { f_path : 。FilePath, f_size :: Int }
deriving (Show)
getFinfo :: FilePath ->IO Finfo
getFinfo path = do
sz <- getFileSize path
回傳 $ Finfo path (fromIntegral sz)
main =do
[root] <- getArgs
bs <- getBySize root
列印 bs
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/316980.html
標籤:
