我正在尝试从标准输入读取数据作为 double 数据,操作它们并写入它们。到目前为止我想出的是:
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
这个想法是将数据提供给程序,然后在将数据写入标准输出之前通过反馈系统。虽然现在它只打印前 10 个值。
这有效,但似乎不会懒惰地评估。即它必须将所有输入读入内存。
所以:
dd if=/dev/urandom bs=8 count=10 | runhaskell feedback.hs
会工作得很好,但是:
dd if=/dev/urandom | runhaskell feedback.hs
将不会。我猜是
listOfFloat64le
使事情无法正常工作的功能。那么我如何创建一个迭代来传递到我的 sys
功能而不必将所有内容读入内存?我不是一个非常有经验的haskeller。
最佳答案
我采取了另一条路线,而是以 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)
这似乎至少有效,但我不知道性能如何。
编辑:我从
chunk
切换过来的至 chunker
它使用 runGetState 代替: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
并像这样使用它:
let signal = chunker getFloat64le input
关于haskell - 在haskell中从stdin懒惰地读取和操作 float ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12514013/