我想知道是否有办法从io-streams
包中"拆分"/"复制"System.IO.Streams.InputStream
以转发到两个处理阶段?
duplicate :: InputStream a -> IO (InputStream a, InputStream a)
我可以看到这可能不适用于流的需求驱动性质,但是如果您需要处理几件事,规范的解决方案是什么?你会构建一个"写到一边"的管道吗?喜欢:
input >>= countEvents countIORef >>= logEvents loggerRef >>= output
我可能会走Arrow
路线并将所有内容存储在元组中,但这很快就会变脏,据我所知,没有 Arrow 接口可以io-streams
:
input >>= (countEvents *** logEvents) >>= output
有什么建议吗?
多种方式执行此操作,但由于countEvents
和logEvents
都是流上的折叠,因此重复应用outputFoldM
可能是最简单的。您不是在寻找拆分流的方法,而是在寻找链接折叠的方法。 outputFoldM
将流转换为与对其应用重复折叠操作的结果相关联的新流,如您所说,将结果"写入一侧"。
>>> 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`
为了它的价值,我写了一个补丁,以便可以将foldl
库中的Fold
和FoldM
s应用于InputStreams
https://github.com/snapframework/io-streams/issues/53。这将允许您无限期地同时应用许多折叠,随心所欲地使用镜头区分元素,从而符合您提到的箭头类比。这是以这种方式应用的相同折叠/水槽。我曾经用ApplicativeDo
来编写一个大折叠,它执行"日志记录"并收集统计信息并格式化它们。同样的事情可以用应用运算符编写。
{-#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
等。这是一个由超可组合的褶皱和水槽组成的独立学科。