Эффективное чтение чисел в Haskell - PullRequest
7 голосов
/ 20 декабря 2010

Я ищу эффективный способ чтения чисел из текстового файла без установки дополнительных пакетов .Data.ByteString.Lazy.Char8.readInt, кажется, делает трюк для целых чисел.Я читал, что ByteString теперь имеет метод readDouble, но когда я пишу import Data.ByteString.Lex.Lazy.Double (readDouble), компилятор жалуется:

    Main.hs:4:7:
        Could not find module `Data.ByteString.Lex.Lazy.Double':
          locations searched:
            Data/ByteString/Lex/Lazy/Double.hs
            Data/ByteString/Lex/Lazy/Double.lhs

Моя версия пакета bytestring - 0.9.1.5.

Так я что-то не так делаю?Или, может быть, есть лучшее решение проблемы?Спасибо.

Обновление: ОК, похоже, что readDouble находится в пакете bytestring-lexer, который не установлен по умолчанию.Любая другая идея?

Ответы [ 3 ]

5 голосов
/ 13 мая 2011

Другое решение: установите пакет bytestring-lexing и используйте readDouble, который я оптимизировал для вас.

 cabal install bytestring-lexing

Пакет обеспечивает оптимизированные функции анализа для литералов с плавающей точкой:

 readDouble :: ByteString -> Maybe (Double, ByteString)         
3 голосов
/ 20 декабря 2010

Единственный раз, когда я встречал парсалы на критическом пути, я использовал это:

{-# LANGUAGE ForeignFunctionInterface #-}
import qualified Data.ByteString.Char8 as B
import Foreign.C.Types
import Foreign.C.String
import System.IO.Unsafe

foreign import ccall unsafe "stdlib.h atof" c_atof :: CString -> IO CDouble
unsafeReadDouble = unsafePerformIO . flip B.useAsCString c_atof

В то время не было ничего похожего на readDouble в строке байтов. Возможно, это было бы лучшим решением, если бы оно теперь было стандартным.

2 голосов
/ 22 декабря 2010

Вот то, что я придумал.

Я использовал функцию, предложенную 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 на основе аналогичных идей.Но я думаю, что пока буду придерживаться моей текущей версии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...