问题描述
我想知道是否有一种方法可以从io-streams 包中拆分"/复制" System.IO.Streams.InputStream
两个处理阶段?
I wonder if there is a way to "split"/"duplicate" an System.IO.Streams.InputStream
from the io-streams
package to be forwarded to two processing stages?
duplicate :: InputStream a -> IO (InputStream a, InputStream a)
我可以看到,这可能与流的需求驱动性质不兼容,但是如果您需要处理几件事,那么规范的解决方案是什么?您是否会构建写到一边"的管道?喜欢:
I can see that this probably doesn't work with the demand driven nature of streams, but what would be the canonical solution if you need several things to be processed? Would you build a pipeline that "writes to the side"? Like:
input >>= countEvents countIORef >>= logEvents loggerRef >>= output
我可能会走 Arrow
路线并将所有内容存储在元组中,但这很快就会变得肮脏,据我所知,没有 io-streams
的Arrow接口>:
I could probably go the Arrow
route and store everything in tuples, but that is going to get dirty quickly and to my knowledge there is no Arrow interface to io-streams
:
input >>= (countEvents *** logEvents) >>= output
有什么建议吗?
推荐答案
您可以通过多种方式执行此操作,但是由于 countEvents
和 logEvents
都是流中, outputFoldM
的重复应用可能是最简单的.您并不是在寻找一种将流分离的方法,而是一种将折痕连接在一起的方法. outputFoldM
将一个流转换成一个新流,该流与对其应用重复折叠操作的结果相关联,如您所说,将结果写到一边".
You can do this a number of ways, but since countEvents
and logEvents
are both folds over the stream, repeated applications of outputFoldM
is probably the simplest. You aren't looking for a way to split the stream so much as a way to link the folds. outputFoldM
turns a stream into a new stream associated with the result of applying a repeated fold operation to it, writing the result 'to the side' as you say.
>>> let logger = IOS.inputFoldM (\() x -> print x >> putStrLn "----") ()
>>> let counter = IOS.inputFoldM (\a _ -> return $! a + 1) (0::Int)
>>> ls0 <- IOS.fromList [1..5::Int]
>>> (ls1,io_count) <- counter ls0
>>> (ls2,_) <- logger ls1
>>> IOS.fold (+) 0 ls2
1 -- here we see the "logging" happening from `logger`
----
2
----
3
----
4
----
5
----
15 -- this is the sum from the `fold (+) 0` that actually exhausted the stream
>>> io_count
5 -- this is the result of `counter`
对于它的价值,我写了一个补丁程序以使其可以应用来自Fold s和 FoldM
s.haskell.org/package/foldl-1.2.1/docs/Control-Foldl.html"rel =" nofollow> foldl
库转换为 InputStreams
https://github.com/snapframework/io-streams/issues/53 .这将允许您无限期地应用多个同时折叠,并根据需要使用镜片来区分元素,从而适合您提到的箭头"类比.这是相同的折叠/水槽方式.我用 ApplicativeDo
编写了一个记录"并收集统计数据并格式化它们的大折叠.可以用应用运算符写同样的东西.
For what it's worth, I wrote a patch to make it possible to apply the Fold
s and FoldM
s from the foldl
library to InputStreams
https://github.com/snapframework/io-streams/issues/53 . This would permit you to apply indefinitely many simultaneous folds, discriminating elements as you please with lens, thus fitting the Arrow analogy you mention. Here's the same folds/sinks applied that way. I used ApplicativeDo
to write the one big fold that does "logging" and collects statistics and formats them. The same thing can be written with the applicative operators.
{-#LANGUAGE ApplicativeDo #-}
import qualified System.IO.Streams as IOS
import qualified Control.Foldl as L
import Control.Lens (filtered)
main = do
ls <- IOS.fromList [1..5::Int]
res <- L.impurely IOS.foldM_ myfolds ls
putStrLn res
myfolds = do
sum_ <- L.generalize L.sum -- generalize makes an 'impure' fold
length_ <- L.generalize L.length -- out of a pure one like sum or length
odd_length_ <- L.generalize (L.handles (filtered odd) L.length)
_ <- L.sink (\n -> print n >> putStrLn "-------")
pure (format sum_ length_ odd_length_)
where
format sum_ length_ odd_length_ = unlines
[ ""
, "Results:"
, "sum: " ++ show sum_
, "length: " ++ show length_
, "number odd: " ++ show odd_length_]
所以看起来像这样
>>> main
1
-------
2
-------
3
-------
4
-------
5
-------
Results:
sum: 15
length: 5
number odd: 3
像 foldl
中那样的美丽的折叠"折叠很不错,因为它们对任何给定的框架都不特殊.您可以将 myfolds
应用于列表, Sequence
,非装箱矢量,管道 Producer
,管道 Source
等.这是超可折叠和水槽的独立学科.
The "beautiful folding" folds like the ones in foldl
are nice since they are not special to any given framework. You can apply the myfolds
without alteration to a list, a Sequence
, an unboxed vector, a pipes Producer
, conduit Source
etc etc.. It's a separate discipline of hyper-composable folds and sinks.
这篇关于有没有办法拆分InputStream?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!