组合两个枚举

发布于 2024-12-08 17:50:27 字数 334 浏览 0 评论 0原文

我试图围绕枚举器库进行思考,但遇到了一种情况,我想根据两个现有的枚举器构建一个新的枚举器。假设我有枚举:

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

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

e3 :: Enumeratee x z m b

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

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

I'm trying to wrap my head around the enumerator library and ran into a situation where I want to build a new Enumeratee in terms of two existing Enumeratees. Let's say I have the enumeratees:

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

I feel that I should be able to combine them into one enumeratee

e3 :: Enumeratee x z m b

but I couldn't find an existing function to do this in the package. I tried to write such a function myself, but my understanding of iteratees is still so limited that I couldn't figure out a way to get all the complex types to match.

Did I just miss some basic combinator, or are Enumeratees even supposed to be composable with each other?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

滴情不沾 2024-12-15 17:50:27

理论上它们是可组合的,但类型有点棘手。困难在于第一个枚举的最终参数 b 实际上并不是 b;这是另一个 iteratee!这是来自 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 组合器,但希望它有足够的信息,您将能够将它们应用于枚举器

In theory they are composable, but the types are a bit tricky. The difficulty is that the final parameter b of the first enumeratee isn't actually b; it's another iteratee!. Here's the type of the ><> operator from iteratee, which composes 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

Note the extra forall in the first enumeratee; this indicates that a Rank-2 type is at work. If the enumerator author wants to maintain H98 compatibility (I believe this was one of the original goals), this approach is unavailable.

It is possible to write this type signature in a form which doesn't require Rank-2 types, but it's either longer, not clear from the type that it's actually two enumeratee's that are being composed, or both. For example, this is ghc's inferred type for (><>):

Prelude Data.Iteratee> :t (><>>)
(><>>)
  :: (Monad m, Nullable s) =>
     (b -> Iteratee s m (Iteratee s' m a1))
     -> (a -> b) -> a -> Iteratee s m a1

Although these types are for iteratee combinators, hopefully it's enough information you'll be able to apply them to enumerator.

土豪我们做朋友吧 2024-12-15 17:50:27

我不久前遇到过这个问题,你需要首先有一个迭代器(或枚举器)才能组成枚举器。

您可以这样开始:

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。

($=) 用于组合Enumerator 和 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))
               ]

如果你尝试通过创建 Enumerator 而不是 Iteratee 来实现上面相同的函数,你将获得无限递归使用 foldl' ($=) (enumList 5 [1..]) [list-of-enumeratees] 时出现类型错误。

希望这有帮助。

I ran with this problem a while ago, you need to have an Iteratee first (or an Enumerator) in order to make the composition of Enumeratees.

You can either start by doing this:

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)

The previous code composes a list of enumeratees together to create a new enumerator, and then it is applied to the consume Iteratee.

The ($=) serves to compose an Enumerator and an Enumeratee to create a new enumerator, while the (=$) can be used to compose an Iteratee with an Enumeratee to create a new Iteratee. I recommend the latter given that types won't bust your balls when composing a list of Enumeratees using (=$):

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))
               ]

If you would try to implement the same function above by creating an Enumerator instead of an Iteratee, you will get an infinite recursive type error when using foldl' ($=) (enumList 5 [1..]) [list-of-enumeratees].

Hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文