Вот то, что я придумал.
Я использовал функцию, предложенную JB, и добавил два трюка, которые я изучил из исходного кода bytestring-lexing (спасибо, sclv!).Первая - это функция:
strict = SB.concat . LB.toChunks
Эффективно преобразует ленивую строку в ленивую.
Второй трюк - функция Data.ByteString.Internal.inlinePerformIO
, которая является более эффективным вариантом unsafePerformIO..
Вот полный код, который позволяет довольно быстро читать числа:
{-# LANGUAGE ForeignFunctionInterface #-}
import qualified Data.ByteString.Lazy.Char8 as LB
import qualified Data.ByteString as SB
import Data.ByteString.Internal (inlinePerformIO)
import Foreign.C.String (CString)
import Foreign.C (CDouble)
import Data.Maybe (fromJust)
foreign import ccall unsafe "stdlib.h atof" c_atof :: CString -> IO Double
unsafeReadDouble = inlinePerformIO . flip SB.useAsCString c_atof
{-# INLINE unsafeReadDouble #-}
readDouble = unsafeReadDouble . SB.concat . LB.toChunks
readInt = fst . fromJust . LB.readInt
И пример программы, которая вычисляет сумму всех чисел на входе: <pre>
main = LB.getContents >>= (print . sum . map readDouble . LB.lines)
Он обрабатывает11 МБ файл (1M чисел) примерно за 0,5 секунды
Я также нашел несколько ссылок , где гораздо более эффективная версия readInt
обсуждается.Предположительно можно построить readDouble
на основе аналогичных идей.Но я думаю, что пока буду придерживаться моей текущей версии.