2010-12-20 33 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)