我已经使用zipSinks :: Monad m => Sink i m r -> Sink i m r' -> Sink i m (r, r')
这个,但它被认为不推荐。组合两个接收器的首选方法是什么?
回答
((包是conduit-0.5.2.3,整个module只是为了向下兼容。))
[编辑]
所以,我简单的一元猜想(见下文)似乎是错误,即使类型是正确的。 现在,我只能猜测答案是:
替换功能仍在开发中,几乎和所有Pipe/Conduit以及类似的概念和库一样。
我等待下一个API来解决这个问题,直到那时仍然使用zipSink
。 (也许这只是放错了地方。)
[/编辑]
我不是这个包familar,但不会是做一样的,因为这?
zipSinks :: Monad m => Sink i m r -> Sink i m r' -> Sink i m (r, r')
zipSinks s1 s2 = (,) <$> s1 <*> s2
毕竟这是一个Monad。 (Functor,Applicative)
zipSinks :: Monad sink => sink r -> sink r' -> sink (r, r')
zipSinks s1 s2 = liftM2 (,) s1 s2
类型可以,但不是语义。您的zipSinks版本将连续运行接收器,并且第一个接收器将完全消耗源代码。 – tymmym 2012-08-15 05:56:26
编辑
考虑在此之后,我不认为这是可能的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)
现在对于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)
以下是使用zipSinks
的一些示例。它似乎在IO
内部以及其外部均正常工作,并且在我进行的少数测试中,输出与使用旧的zipSinks
创建的zipped'
的输出相匹配。
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)
不错! (注意,你可以为'doubleHead'写'await >> = return。fmap(2 *)',同样''l -fmap mayToList await'而不是在'zipSinks'中使用'input', Data.Conduit.Internals'是一个额外的导入?) – huon 2012-08-15 19:31:29
是的,我意识到我可能可以在某些地方使用函子。对于Haskell来说,我仍然足够了,这对我来说通常是第二遍编辑,不幸的是。 是的,'Data.Conduits.Internals'是无关的。最初,我正在使用'sinkToPipe'。 感谢您指出这些。我会更新答案。 – Eric 2012-08-15 20:14:41
您的zipSinks版本只包含第一个元素。例如'runResourceT $ CL.sourceList [1,2,3] $$ zipSinks(CL.take 2)(CL.take 2)''会返回'([1],[1])',但应该是'([1 ,2],[1,2])'。 – tymmym 2012-08-16 05:49:07
- 1. 跨线程编组COM接口的首选方法是什么?
- 2. 什么是预先分配NumPy数组的首选方法?
- 3. 什么是组织回调的首选方法?
- 4. 在猫鼬中定义数组的首选方法是什么?
- 5. 数据更改时刷新组合框的首选方法是什么?
- 6. 从Android上传到服务器的首选方法是什么?
- 7. 什么是协调多个默认页面的首选方法?
- 8. 在C#中处理这个TCP连接的首选方法是什么?
- 9. 注释中注释方法的首选方式是什么?
- 10. 从参数分配集合的首选方式是什么?
- 11. 找到两个集合的最有效方法是什么?
- 12. 什么是您的软件版本的首选方法?
- 13. REST webservice的'WSDL'的首选方法是什么?
- 14. 在VB.NET中声明数组的首选语法是什么?
- 15. 什么是测试代理设置的首选或可接受的方法?
- 16. 跨浏览器协调keyCode/charCode的首选方式是什么?
- 17. 无堆栈Python中TCP/IP IPC的首选方法是什么?
- 18. 什么是Zend Acl的首选实现方法
- 19. 在SSRS中生成数据集的首选方法是什么?
- 20. 什么是使用bash生成强密码的首选方法?
- 21. C#中事件处理的首选方法是什么?
- 22. 在.Net中构建Web服务的首选方法是什么?
- 23. Zend 2中本地化的首选方法是什么?
- 24. 在表格中更新字段的首选方法是什么?
- 25. 什么是OS X中进程间通信的首选方法?
- 26. Angular - 终止Observables的首选方法是什么?
- 27. 现代D的首选控制台输出方法是什么?
- 28. 处理缺少DynamicObject成员的首选方法是什么?
- 29. 将视图模型连接到视图的首选方法是什么?
- 30. 预加载图像<img>的首选方法是什么?为什么?
什么样的行为,*确切*,你想要“合并”水槽有?我试着查看'zipSinks'的旧文档和实现,但行为不容易一眼就看出来。 – 2012-08-07 15:58:29
@DanBurton:'zipSinks'需要两个接收器并返回一个接收器,该接收器会产生一个具有相应接收器结果的对。例如'sizeCrc32Sink = zipSinks sizeSink crc32Sink'会计算大小和校验和。我和Oleg描述的行为一样[here](http://okmij.org/ftp/Streams.html#1enum2iter)。 – tymmym 2012-08-07 16:46:56
好吧,我明白了;它基本上挂起了等待并同时将上游输出馈送到两个接收器,将输入流分成两部分。 Data.Conduit.Util的文档声明“现在有更简单的方法来处理它们的用例”,但我没有看到这种用例的更简单的方法,因为它需要深入研究管道内部实现。 – 2012-08-08 03:46:05