2010-12-20 35 views
7

我正在寻找一种有效的方式来从文本文件中读取数字而无需安装其他软件包Data.ByteString.Lazy.Char8.readInt似乎做整数的伎俩。我读过ByteString现在有一个readDouble方法,但是当我写import Data.ByteString.Lex.Lazy.Double (readDouble)编译器会抱怨:Haskell中有效的数字读取

 
    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 

我的字节串包的版本是0.9.1.5。

那么,我做错了什么?或者也许有更好的解决方案?谢谢。

更新:好的,似乎readDouble在包字节串lexer,这是默认情况下不安装。任何其他想法?

+1

只需安装字节串,词法分析器包即可。 “cabal install bytestring-lexer” – sclv 2010-12-20 16:41:01

+1

我想在没有附加包的情况下执行操作,因为我的程序将在我无法控制的服务器上运行。 – adamax 2010-12-20 18:34:20

+0

@adamax:值得向你的问题添加限制。 – 2010-12-20 20:36:29

回答

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在当时字节串,虽然。如果现在是标准的话,那可能会是更好的解决方案。

+0

谢谢!我做了一些实验。为了使事情变得简单,我把atoi代替atof,并将其与通常的显示函数和我的天真实现(iread)进行比较。 FFI完全打败了节目,但是它向iread输了约20%。也许,转换为CString会导致开销 – adamax 2010-12-20 22:06:47

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) 
It processes an 11Mb file (1M numbers) in about 0.5 seconds

I also found several links , where a much more efficient version of readInt进行了讨论。据推测,人们可以根据类似的想法建立一个readDouble。但是我想现在我会坚持使用我目前的版本。

5

另一种解决方案:安装bytestring-lexing包,并使用readDouble,我为你优化。

cabal install bytestring-lexing 

该软件包提供optimized parsing functions浮点文字:

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