Почему мой код, использующий монадические списки из пакета List, такой медленный?

На прошлой неделе пользователь 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] .

Что я делаю не так? Я никогда не использовал ListT пакета List , кроме подобных игрушечных примеров, поэтому я не Я не знаю, какой производительности ожидать, но 30 секунд (вместо доли секунды) для обработки каталога с ~ 40 000 файлов кажутся слишком медленными.

13
задан Community 23 May 2017 в 12:04
поделиться