先週、ユーザーMasseは、Haskellのディレクトリにファイルを再帰的にリストすることについて質問しました。List
私が最初に考えたのは、パッケージのモナディックリストを使用して、印刷を開始する前にリスト全体をメモリに作成しないようにすることでした。私はこれを次のように実装しました:
module Main where
import Prelude hiding (filter)
import Control.Applicative ((<$>))
import Control.Monad (join)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.ListT (ListT)
import Data.List.Class (cons, execute, filter, fromList, mapL)
import System (getArgs)
import System.Directory (getDirectoryContents, doesDirectoryExist)
import System.FilePath ((</>))
main = execute . mapL putStrLn . listFiles =<< head <$> getArgs
listFiles :: FilePath -> ListT IO FilePath
listFiles path = liftIO (doesDirectoryExist path) >>= listIfDir
where
valid "." = False
valid ".." = False
valid _ = True
listIfDir False = return path
listIfDir True
= cons path
$ join
$ listFiles
<$> (path </>)
<$> (filter valid =<< fromList <$> liftIO (getDirectoryContents path))
これは、すぐに印刷を開始し、メモリをほとんど使用しないという点で美しく機能します。FilePath -> IO [FilePath]
残念ながら、同等のバージョンよりも数十倍遅くなります。
私は何が間違っているのですか?List
このようなおもちゃの例以外のパッケージを使用したことListT
がないので、どのようなパフォーマンスが期待できるかわかりませんが、40,000ファイルまでのディレクトリを処理するのに30秒(数分の1秒)もかかるようですスロー。