在haskell中懒洋洋地读取和操作stdin中的float
我试图从stdin中读取双倍的数据,对它们进行操作,并将其写入。到目前为止,我想到的是:在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
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