结合两个枚举

时间:2011-10-05 17:31:30

标签: haskell iterate

我正试图绕过enumerator库并遇到一种情况,我希望根据两个现有的Enumeratees构建一个新的Enumeratee。假设我有枚举:

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

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

e3 :: Enumeratee x z m b

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

我是否只是错过了一些基本的组合器,或者是枚举者甚至应该相互合成?

2 个答案:

答案 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]时将会出现无限递归类型错误。

希望这有帮助。

相关问题