在haskell中懒洋洋地读取和操作stdin中的float

在haskell中懒洋洋地读取和操作stdin中的float,haskell,stdin,lazy-evaluation,Haskell,Stdin,Lazy Evaluation,我试图从stdin中读取双倍的数据,对它们进行操作,并将其写入。到目前为止,我想到的是: import qualified Data.ByteString.Lazy as B import Data.Binary.IEEE754 import Data.Binary.Get -- gives a list of doubles read from stdin listOfFloat64le = do empty <- isEmpty if empty then retu

我试图从stdin中读取双倍的数据,对它们进行操作,并将其写入。到目前为止,我想到的是:

import qualified Data.ByteString.Lazy as B
import Data.Binary.IEEE754
import Data.Binary.Get

-- gives a list of doubles read from stdin
listOfFloat64le = do
  empty <- isEmpty
  if empty
     then return []
     else do v <- getFloat64le
             rest <- listOfFloat64le
             return (v : rest)


-- delay signal by one
delay us = 0 : us

-- feedback system, add delayed version of signal to signal
sys us = zipWith (+) us (delay us)

main = do
    input <- B.getContents
    let hs = sys $ runGet listOfFloat64le input
    print $ take 10 hs
工作正常,但:

dd if=/dev/urandom | runhaskell feedback.hs
不会。我猜是
listdowlet64le
函数使事情无法正常工作。那么,我如何创建一个iterable来传入我的
sys
函数,而不必将所有内容读入内存


我不是一个经验丰富的哈斯凯尔人。

见。看起来二进制比我很久以前使用它时更加严格了。

我采用了另一种方法,以8字节为间隔拆分ByteString,并在其上映射:

import qualified Data.ByteString.Lazy as L
import Data.Binary.IEEE754
import Data.Binary.Get

-- delay signal by one
delay us = 0 : us

-- feedback system, add delayed version of signal to signal
sys us = zipWith (+) us (delay us)

-- split ByteString into chunks of size n
chunk n xs = if (L.null xs)
        then []
        else y1 : chunk n y2
          where
            (y1, y2) = L.splitAt n xs


main = do
    input <- L.getContents

    let signal = map (runGet getFloat64le) (chunk 8 input)
    print $ take 10 (sys signal)

像这样使用:
let signal=chunker getFloat64le input

这似乎是一个标准问题,您可以轻松使用管道或导管之类的东西。您可以将
stdin
作为源,将
stdout
作为接收器,并将变压器作为
导管应用

如果输入很快到达,并且您消耗了大量输入,则拆分将需要一些时间。在这种情况下,最好完全跳过
Get
monad,直接从输入构建一个
Double
s列表;通过testring从
读取8个字节,从中生成
字64
,并将该位模式转换为
双字节(例如使用)。如果输入不是很快到达,程序仍然是IO绑定的。如果你不消耗太多,那也没关系。我最终修改了chunk函数,改为使用
runGetState
。使用Get monad比普通读取和使用wordToDouble慢,还是只是拆分了一个可能不好的ByteString?噢,“不推荐:改用runGetPartial。此函数将被删除。”Get的实现已更改。我不确定忽略偏移量对于旧的实现是否合适。monad带来了一点开销,我不认为这是一件大事,但是,我预计将
ByteString
拆分成这么多短的块所需的分配成本会显著增加。但我没有测量,所以我可能错了。
import qualified Data.ByteString.Lazy as L
import Data.Binary.IEEE754
import Data.Binary.Get

-- delay signal by one
delay us = 0 : us

-- feedback system, add delayed version of signal to signal
sys us = zipWith (+) us (delay us)

-- split ByteString into chunks of size n
chunk n xs = if (L.null xs)
        then []
        else y1 : chunk n y2
          where
            (y1, y2) = L.splitAt n xs


main = do
    input <- L.getContents

    let signal = map (runGet getFloat64le) (chunk 8 input)
    print $ take 10 (sys signal)
chunker :: Get a -> L.ByteString -> [a]
chunker f input = if (L.null input)
                     then []
                     else val : chunker f rest
                       where
                        (val, rest, _) = runGetState f input 0