Haskell中的高效数字读取

时间:2010-12-20 12:15:12

标签: performance parsing haskell

我正在寻找一种有效的方法来从文本文件中读取数字而无需安装其他软件包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在package bytestring-lexer中,默认情况下没有安装。还有其他想法吗?

3 个答案:

答案 0 :(得分:5)

另一种解决方案:安装bytestring-lexing软件包,然后使用我为您优化的readDouble

 cabal install bytestring-lexing

该包为浮点文字提供optimized parsing functions

 readDouble :: ByteString -> Maybe (Double, ByteString)         

答案 1 :(得分:3)

我在关键路径上遇到解析双打的唯一一次,我使用了这个:

{-# 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 :(得分:2)

这就是我想出来的。

我使用了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

一个示例程序,用于计算输入中所有数字的总和:

main = LB.getContents >>= (print . sum . map readDouble . LB.lines)
它在约0.5秒内处理一个11Mb文件(1M个数字)

我还found several links,其中讨论了更高效的readInt版本。据推测,可以根据类似的想法构建readDouble。但我想我现在会坚持使用现在的版本。