10

我试图绕着enumerator图书馆转,遇到了一种情况,我想根据两个现有的 Enumeratee 构建一个新的 Enumeratee。假设我有枚举对象:

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

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

e3 :: Enumeratee x z m b

但我在包中找不到执行此操作的现有函数。我尝试自己编写这样的函数,但我对迭代对象的理解仍然非常有限,以至于我无法找到一种方法来让所有复杂类型都匹配。

我只是错过了一些基本的组合器,还是 Enumeratees 甚至应该可以相互组合?

4

2 回答 2

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.

于 2011-10-05T18:16:47.393 回答
1

前段时间我遇到过这个问题,你需要先有一个 Iteratee(或一个 Enumerator)才能组成 Enumeratees。

您可以从这样做开始:

模块主要在哪里
导入数据。枚举器
将合格的 Data.Enumerator.List 导入为 EL

主::IO()
main = run_ (enum $$ EL.consume) >>= print
  在哪里
    enum = (enumList 5 [1..] $= EL.isolate 100) $= EL.filter 对
    对 = (==0) 。(`mod` 2)

前面的代码将枚举器列表组合在一起创建一个新的枚举器,然后将其应用到consume Iteratee。

($=) 用于组合Enumerator 和 Enumeratee 以创建新的 enumerator,而 (=$) 可用于组合Iteratee 和 Enumeratee 以创建新的 Iteratee。我推荐后者,因为在使用 (=$) 组成 Enumeratees 列表时,类型不会让你大吃一惊:

模块主要在哪里
导入数据。枚举器
将合格的 Data.Enumerator.List 导入为 EL

主::IO()
main = run_ (enumList 5 [1..] $$ it) >>= print
  在哪里
    它=折叠(=$)
               EL.消费
               [ EL. 隔离 100
               , EL.filter ((==0) . (`mod` 2))
               ]

如果您尝试通过创建 Enumerator 而不是 Iteratee 来实现上述相同的功能,那么在使用foldl' ($=) (enumList 5 [1..]) [list-of-enumeratees].

希望这可以帮助。

于 2011-10-05T18:14:44.020 回答