迭代器/迭代器抽象化是由Oleg Kiselyov发明的。它们提供了一种干净的方法来进行IO操作,并具有可预测(低)的资源需求。目前的Enumerators软件包与Oleg最初的工作非常接近。
Conduits是为Yesod Web框架创建的。我的理解是它们被设计成非常快速。该库的早期版本高度依赖状态。
Pipes专注于优雅性。它们只有一种类型而不是多种,形成了单子(变换器)和类别实例,并且在设计上非常“函数化”。如果您喜欢范畴解释:Pipe类型只是以下不可思议简单的函数子上的自由单子。
data PipeF a b m r = M (m r) | Await (a -> r) | Yield b r
instance Monad m => Functor (PipeF a b m) where
fmap f (M mr) = M $ liftM mr
fmap f (Await g) = Await $ f . g
fmap f (Yield b p) = Yield b (f p)
--Giving:
newtype Pipe a b m r = Pipe {unPipe :: Free (PipeF a b m) r}
deriving (Functor, Applicative, Monad)
--and
instance MonadTrans (Pipe a b) where
lift = Pipe . inj . M
在实际的管道定义中,这些都是内置的,但这个定义的简洁性令人惊叹。管道在操作(<+<) :: Monad m => Pipe c d m r -> Pipe a b m r -> Pipe a d m r
下形成一个类别,该操作将第一个管道yield
的内容传送到等待的第二个管道中。Conduits
正在变得更像Pipe
(使用CPS代替状态,并转换为单一类型),而 Pipes 正在获得更好的错误处理支持,或许会恢复生成器和消费者的独立类型。