Я разобрался, как исправить ошибку типа.Ключом к исправлению ошибки типа является понимание взаимосвязи между Data.ListLike.filter и ByteString входными данными, которые передаются этому фильтру,Вот тип Data.ListLike.filter:
Data.ListLike.filter
:: Data.ListLike.Base.ListLike full item =>
(item -> Bool) -> full -> full
full относится к потоку в контексте перечислителя / итератора, если я его понимаюправильно. item относится к элементу потока.
Теперь, если мы хотим выполнить фильтрацию по новой строке во входном файле, мы должны знать тип потока входного файла и тип элементов в этом потоке.В этом случае входной файл читается как ByteString stream. ByteString задокументировано как эффективное для пространства представление вектора Word8.Итак, тип item здесь - Word8.
Итак, когда мы пишем фильтр, в функции шага мы должны убедиться, что операция Bool определена для Word8, поскольку это типэлемента, передаваемого в фильтр (как описано выше).Мы фильтруем новую строку.Таким образом, функция bool, подобная приведенной ниже, которая создает представление новой строки в Word8 и проверяет равенство x для типа Word8, должна работать:
\x -> x == Data.ByteString.Internal.c2w '\n'
Еще одна недостающая часть - по некоторым причинамкомпилятор (v7.0.3 Mac) не может определить тип el в сигнатуре типа numfile (если у кого-то есть идеи, почему это так, пожалуйста, обсудите).Итак, явное указание на то, что Word8 решает проблему компиляции:
numlines :: (Monad m, Num a, LL.ListLike s Word8) => Iteratee s m a
Полный код ниже - он компилируется и работает довольно быстро.
{-# LANGUAGE BangPatterns,FlexibleContexts #-}
import Data.Iteratee as I
import Data.ListLike as LL
import Data.Iteratee.IO
import Data.ByteString
import GHC.Word (Word8)
import Data.ByteString.Internal (c2w)
numlines :: (Monad m, Num a, LL.ListLike s Word8) => Iteratee s m a
numlines = liftI $ step 0
where
step !i (Chunk xs) = let newline = c2w '\n' in liftI (step $i + fromIntegral (LL.length $ LL.filter (\x -> x == newline) 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
{- Time to run on mac OSX:
$ time ./test ## above compiled program: ghc --make -O2 test.hs
235886
real 0m0.011s
user 0m0.007s
sys 0m0.004s
$ time wc -l /usr/share/dict/words
235886 /usr/share/dict/words
real 0m0.005s
user 0m0.002s
sys 0m0.002s
-}