组合两个水槽的首选方法是什么?

tym*_*mym 21 haskell conduit

我已经习惯zipSinks :: Monad m => Sink i m r -> Sink i m r' -> Sink i m (r, r')了这个,但它被认为已被弃用了.

Eri*_*ric 7

编辑

考虑到这一点后,我不认为使用当前版本的Data.Conduit是可能的.管道不是类别,因此&&&是不可能的.并且我无法想到从上游提取结果,逐步将它们提供给两个接收器,并在第一个接收器完成时短路.(虽然我不认为Data.Conduit.Util.zipSinks这种方式会短路,但这似乎是非常可取的.)当然,除了两个接收器上的模式匹配(就像zipSinks在包中一样),但这就是我们想要的避免在这里.

这就是说,我会喜欢在这里证明是错误的.


它不漂亮,但你可以用一种显而易见的方式做到这一点.

首先进口:

module Main where

import Control.Monad.Trans
import Data.Conduit
import qualified Data.Conduit.Binary as CB
import qualified Data.Conduit.List as CL
import qualified Data.Conduit.Text as CT
import qualified Data.Conduit.Util as CU
import Data.Maybe
import Data.Text (unpack)
Run Code Online (Sandbox Code Playgroud)

现在为zipSinks.基本上,您希望创建一个从上游提取输入并将其分别发送到每个子接收器的接收器.在这种情况下,我曾经CL.sourceList这样做过.如果await返回Nothing,则maybeToList返回一个空列表,因此子汇也会在没有输入的情况下运行.最后,每个子汇的输出然后被馈送到元组中.

zipSinks :: Monad m => Sink i m r -> Sink i m r' -> Sink i m (r, r')
zipSinks s1 s2 = do
    l  <- fmap maybeToList await
    o1 <- lift $ CL.sourceList l $$ s1
    o2 <- lift $ CL.sourceList l $$ s2
    return (o1, o2)
Run Code Online (Sandbox Code Playgroud)

以下是一些使用示例zipSinks.它似乎在它的内部IO和外部工作正常,并且在我做的少数测试中,输出匹配zipped'使用旧的输出创建的输出zipSinks.

doubleHead :: Monad m => Sink Int m (Maybe Int)
doubleHead = await >>= return . fmap (2*)

-- old version
zipped' :: Monad m => Sink Int m (Maybe Int, Maybe Int)
zipped' = CU.zipSinks CL.head doubleHead

-- new version
zipped :: Monad m => Sink Int m (Maybe Int, Maybe Int)
zipped = zipSinks CL.head doubleHead

fromList = CL.sourceList [7, 8, 9] $$ zipped
-- (Just 7, Just 14)

fromFile :: String -> IO (Maybe Int, Maybe Int)
fromFile filename = runResourceT $
       CB.sourceFile filename
    $= CB.lines
    $= CT.decode CT.utf8
    $= CL.map (read . unpack)
    $$ zipped

-- for a file with the lines:
--
-- 1
-- 2
-- 3
--
-- returns (Just 1, Just 2)
Run Code Online (Sandbox Code Playgroud)

  • 您的`zipSinks`版本仅包含第一个元素.例如`runResourceT $ CL.sourceList [1,2,3] $$ zipSinks(CL.take 2)(CL.take 2)`将返回`([1],[1])`但是应该`([1 ,2],[1,2])`. (2认同)

com*_*nad 6

((包是conduit-0.5.2.3.整个模块只是为了向后兼容.))


[ 编辑 ]

所以,即使类型是正确的,我直截了当的monadic猜测(见下文)似乎是错误的.现在,我只能猜到答案是:

替换功能仍在开发中,非常类似于所有Pipe/Conduit和类似的概念和库.

我等待下一个API来解决这个问题,zipSink直到那时仍然使用.(也许它只是放错地方.)

[ /编辑 ]

我不熟悉这个软件包,但它不会像这样做吗?

zipSinks :: Monad m => Sink i m r -> Sink i m r' -> Sink i m (r, r')
zipSinks s1 s2 = (,) <$> s1 <*> s2
Run Code Online (Sandbox Code Playgroud)

毕竟这是Monad.(Functor,Applicative)

zipSinks :: Monad sink => sink r -> sink r' -> sink (r, r')
zipSinks s1 s2 = liftM2 (,) s1 s2
Run Code Online (Sandbox Code Playgroud)

  • 类型是可以的,但不是语义.您的`zipSinks`版本将连续运行接收器,第一个接收器将完全消耗源. (2认同)