2011-10-05 88 views
10

我试图围绕enumerator库包裹我的头,并遇到了一种情况,我想根据两个现有的枚举构建一个新的Enumeratee。比方说,我有enumeratees:合并两个枚举

e1 :: Enumeratee x y m b 
e2 :: Enumeratee y z m b 

我觉得我应该能够将它们组合成一个enumeratee

e3 :: Enumeratee x z m b 

,但我无法找到一个现有的功能在包中做到这一点。我试图自己编写这样一个函数,但是我对iteratees的理解仍然非常有限,以至于我无法找到让所有复杂类型匹配的方法。

难道我只是想念一些基本的combinator,或者Enumeratees甚至应该是可以相互组合吗?

回答

3

理论上它们是可组合的,但类型有点棘手。难点在于第一枚枚举的最终参数b实际上并不是b;这是另一个迭代器!下面是从iteratee><>运营商,其组成enumeratees类型:

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 

注意在第一enumeratee额外forall;这表明Rank-2类型正在工作。如果作者想保持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

前段时间我遇到了这个问题,你需要首先有一个Iteratee(或一个枚举器)才能组成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) 

上面的代码组成enumeratees的列表,共同创建一个新的枚举,然后将其应用到消费Iteratee。

的($ =)用于构成的枚举和Enumeratee创建一个新的枚举,而(= $)可被用于组成一个Iteratee与Enumeratee以创建新的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]时,您将获得无限递归类型错误。

希望这会有所帮助。