gpt4 book ai didi

haskell - 如何制作 "branched"导管?

转载 作者:行者123 更新时间:2023-12-04 08:44:02 26 4
gpt4 key购买 nike

我希望将相同的数据分成两个“分支”分别处理,然后“加入”......

                                +----------+
+---------+ -->| doublber |--- +--------+
+--------+ | |-- +----------+ -->| | +------+
| source |-->| splitter| | summer |-->| sink |
+--------+ | |-- +----------+ -->| | +------+
+---------+ -->| delayer |--- +--------+
+----------+

我该怎么做?

我的尝试:
import Data.Conduit
import Control.Monad.IO.Class
import qualified Data.Conduit.List as CL
-- import Data.Conduit.Internal (zipSources)
import Control.Arrow ((>>>))

source :: Source IO Int
source = do
x <- liftIO $ getLine
yield (read x)
source

splitter :: Conduit Int IO (Int, Int)
splitter = CL.map $ \x -> (x,x)

doubler = CL.map (* 2)

delayer :: Conduit Int IO Int
delayer = do
yield 0
CL.map id

twoConduitBranches :: Monad m => Conduit a m b -> Conduit c m d -> Conduit (a,b) m (c,d)
twoConduitBranches q w = awaitForever $ \(x, y) -> do
out1 <- undefined q x
out2 <- undefined w y
yield (out1, out2)


summer :: Conduit (Int,Int) IO Int
summer = CL.map $ \(x,y) -> x + y

sink :: Sink Int IO ()
sink = CL.mapM_ (show >>> putStrLn)

-- combosrc = zipSources (source $= delayer) (source $= doubler)
main = source $= splitter $= twoConduitBranches doubler delayer $= summer $$ sink

我应该写什么来代替 undefined年代?

最佳答案

你可以这样做,但它很丑陋,希望实现能够清楚地说明为什么它很丑陋,而不是管道的内置功能:

twoConduitBranches :: Monad m => Conduit a m c -> Conduit b m d -> Conduit (a,b) m (c,d)
twoConduitBranches q w = getZipConduit
(ZipConduit (CL.map fst =$= q =$= CL.map Left)
<* ZipConduit (CL.map snd =$= w =$= CL.map Right)) =$= collapse
where
collapse = do
v1 <- await
case v1 of
Nothing -> return ()
Just (Left _) -> error "out of sequence 1"
Just (Right d) -> do
v2 <- await
case v2 of
Nothing -> error "mismatched count"
Just (Right _) -> error "out of sequence 2"
Just (Left c) -> do
yield (c, d)
collapse

(注意:我稍微调整了您的类型签名,我认为这是您真正想要的类型签名。)

方法如下:转 q变成 Conduit从每个传入元组中获取第一个值,然后用 Left 包装其输出.同样,我们从每个传入元组中获取第二个值并将其传递给 w , 然后用 Right 包装输出.

既然这些 Conduit s 具有相同的类型(它们接受相同的输入元组,并生成相同的 Either 值),我们使用 ZipConduit 组合它们,它在所有组件之间共享输入并将输出合并为单个流。

此流是 Either c d 的流,而不是所需的 (c, d) .为了进行最终转换,我们使用 collapse .它弹出 RightLeft值,然后将它们放在一个它产生的单个元组中。

此函数假定输出值序列始终是 w 中的一个值。 ,然后是 q 中的一个.如果发生其他任何事情,它将抛出异常。问题是:管道中没有任何内容暗示它们实际上会以相同的速度产生输出。事实上,管道是专门为避免这种假设而设计的!

因此,如果您知道您的两个组件管道将始终以相同的速率产生输出,则此功能将起作用。但一般来说这不会是真的。

关于haskell - 如何制作 "branched"导管?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24661350/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com