免责声明:这个问题最近在haskell-cafe列表上被问到。
我所知道的所有迭代实现包(例如iteratee
, iterIO
和conduit
)都定义了一个枚举组合函数,除了enumerator
包。在我看来,这似乎是一个严重的限制,但它似乎也相对容易实现:
import Data.Enumerator
import Data.Enumerator.Internal
(=$=) :: Monad m
=> Enumeratee a0 a1 m (Step a2 m b) -> Enumeratee a1 a2 m b
-> Enumeratee a0 a2 m b
(=$=) e01 e12 step = Iteratee $ do
step' <- runIteratee $ e12 step
runIteratee . joinI $ e01 step'
这里有我错过的东西吗?或者enumerator
没有定义枚举组成的其他原因?
现在enumerator
的新版本(0.4.17)包含了具有我上面给出的签名的(=$=)
操作符。我给这个包的作者发了一封电子邮件,他提出了一个很好的理由,反对在包中包含许多简化的操作符(如($=)
、(=$)
和现在的(=$=)
)。
基本上,问题是处理剩余输入。joinI
组合子
joinI :: Monad m => Iteratee a m (Step a' m b) -> Iteratee a m b
丢弃由内部Iteratee
产生的剩余Stream a'
。如果使用像
joinI (foo $$ (bar $$ baz))
,其中剩余的数据仅在计算结束时被丢弃。但是,使用简化的操作符会导致多个隐式连接,并且遗留的数据变得更加难以跟踪。如果所使用的迭代器很简单(即它们不会产生剩余数据),那么这就不是问题,使用简化的操作符是有意义的。