我正试图绕过enumerator
库并遇到一种情况,我希望根据两个现有的Enumeratees构建一个新的Enumeratee。假设我有枚举:
e1 :: Enumeratee x y m b
e2 :: Enumeratee y z m b
我觉得我应该能够将它们组合成一个枚举
e3 :: Enumeratee x z m b
但我在包中找不到现有的功能。我自己尝试编写这样一个函数,但是我对iteratees的理解仍然非常有限,以至于无法找到让所有复杂类型匹配的方法。
我是否只是错过了一些基本的组合器,或者是枚举者甚至应该相互合成?
答案 0 :(得分:3)
理论上它们是可组合的,但类型有点棘手。困难在于第一个枚举的最终参数b
实际上不是b
;这是另一个迭代!以下是来自iteratee的><>
运算符的类型,它构成了枚举数:
Prelude Data.Iteratee> :t (><>)
(><>)
:: (Monad m, Nullable s1) =>
(forall x. Enumeratee s1 s2 m x)
-> Enumeratee s2 s3 m a -> Enumeratee s1 s3 m a
注意第一个枚举中的额外forall
;这表明Rank-2类型正在起作用。如果enumerator
作者希望保持H98兼容性(我认为这是最初的目标之一),则此方法不可用。
可以用不需要Rank-2类型的形式编写这种类型的签名,但它要么更长,要么从它实际上是两个枚举的类型中清楚,或两者都不清楚。例如,这是(><>)
的ghc推断类型:
Prelude Data.Iteratee> :t (><>>)
(><>>)
:: (Monad m, Nullable s) =>
(b -> Iteratee s m (Iteratee s' m a1))
-> (a -> b) -> a -> Iteratee s m a1
虽然这些类型适用于iteratee
个组合器,但希望它足够的信息可以将它们应用到enumerator
。
答案 1 :(得分:1)
我刚才遇到这个问题,你需要先有一个Iteratee(或一个Enumerator)来组成Enumeratees。
你可以从这开始:
module Main where import Data.Enumerator import qualified Data.Enumerator.List as EL main :: IO () main = run_ (enum $$ EL.consume) >>= print where enum = (enumList 5 [1..] $= EL.isolate 100) $= EL.filter pairs pairs = (==0) . (`mod` 2)
前面的代码组成了一个枚举列表,一起创建一个新的枚举器,然后将它应用于消耗的Iteratee。
($ =)用于组成一个枚举器和一个枚举器来创建一个新的枚举器,而(= $)可以用来组成一个带有枚举的Iteratee来创建一个新的Iteratee 。我推荐后者,因为在使用(= $)组成一个Enumeratees列表时,类型不会破坏你的球:
module Main where import Data.Enumerator import qualified Data.Enumerator.List as EL main :: IO () main = run_ (enumList 5 [1..] $$ it) >>= print where it = foldr (=$) EL.consume [ EL.isolate 100 , EL.filter ((==0) . (`mod` 2)) ]
如果您尝试通过创建枚举器而不是Iteratee来实现上述相同的功能,则在使用foldl' ($=) (enumList 5 [1..]) [list-of-enumeratees]
时将会出现无限递归类型错误。
希望这有帮助。