Написание «wc -l» с использованием библиотеки Iteratee - как отфильтровать новую строку?

Я пытаюсь придумать эквивалент «wc -l», используя Haskell Iteratee библиотека. Ниже приведен код для «wc» (который просто подсчитывает слова - аналогично коду в итеративном примере при взломе) и выполняется очень быстро:


{-# LANGUAGE BangPatterns #-}
import Data.Iteratee as I
import Data.ListLike as LL
import Data.Iteratee.IO
import Data.ByteString


length1 :: (Monad m, Num a, LL.ListLike s el) => Iteratee s m a
length1 = liftI (step 0)
  where
    step !i (Chunk xs) = liftI (step $ i + fromIntegral (LL.length xs))
    step !i stream     = idone i stream
{-# INLINE length1 #-}
main = do
  i' <- enumFile 1024 "/usr/share/dict/words" (length1 :: (Monad m) => Iteratee ByteString m Int)
  result <- run i'
  print result
  {- Time measured on a linux x86 box: 
  $ time ./test ## above haskell compiled code
  4950996

  real    0m0.013s
  user    0m0.004s
  sys     0m0.007s

  $  time wc -c /usr/share/dict/words
  4950996 /usr/share/dict/words

  real    0m0.003s
  user    0m0.000s
  sys     0m0.002s
  -}

Теперь, как вы расширите его, чтобы подсчитать количество строк, которые тоже выполняются быстро? Я сделал версию с использованием Prelude.filter для фильтрации только «\ n» по длине, но она медленнее, чем linux «wc -l» из-за слишком большого объема памяти и gc (я думаю, ленивая оценка). Итак, я написал другую версию, используя Data.ListLike.filter, но она не будет компилироваться, потому что не проверяет тип - помощь здесь будет признательна:


  {-# LANGUAGE BangPatterns #-}
  import Data.Iteratee as I
  import Data.ListLike as LL
  import Data.Iteratee.IO
  import Data.ByteString
  import Data.Char
  import Data.ByteString.Char8 (pack)

  numlines :: (Monad m, Num a, LL.ListLike s el) => Iteratee s m a
  numlines = liftI $ step 0
    where
      step !i (Chunk xs) = liftI (step $i + fromIntegral (LL.length $ LL.filter (\x ->  x == Data.ByteString.Char8.pack "\n")  xs))
      step !i stream = idone i stream
  {-# INLINE numlines #-}

  main = do
    i' <- enumFile 1024 "/usr/share/dict/words" (numlines :: (Monad m) => Iteratee ByteString m Int)
    result <- run i'
    print result
7
задан Sal 3 November 2011 в 02:13
поделиться