如何在Haskell中实现Coroutine队列?

时间:2014-12-30 03:17:23

标签: haskell coroutine

在延续tutorial的底部附近有一个以

开头的Coroutine实现
-- The CoroutineT monad is just ContT stacked with a StateT containing the suspended coroutines.
newtype CoroutineT r m a = CoroutineT {runCoroutineT' :: ContT r (StateT [CoroutineT r m ()] m) a}
    deriving (Functor,Applicative,Monad,MonadCont,MonadIO)

-- Used to manipulate the coroutine queue.
getCCs :: Monad m => CoroutineT r m [CoroutineT r m ()]
getCCs = CoroutineT $ lift get

putCCs :: Monad m => [CoroutineT r m ()] -> CoroutineT r m ()
putCCs = CoroutineT . lift . put

然后还使用dequeuequeue定义了后来的getCCsputCCs函数。

我不明白如何维护Coroutine队列。 getCCsputCCs的类型签名似乎并不表示在调用之间保持任何类型的“变量”。我怀疑州在getput的实施中与getCCsputCCs有关,但我不知道它们是什么。

1 个答案:

答案 0 :(得分:1)

CoroutineT只是monad转换器堆栈ContT r (StateT [CoroutineT r m ()] m) a类型的包装器。这实质上意味着它是包含状态类型为[CoroutineT r m ()]的状态monad的continuation monad。 getput函数是MonadState类型类的成员,StateT实现。当您致电lift get时,它的类型为(MonadTrans t, MonadState m s) => t m s。由于StateT sMonadState s的实例,而s在我们的案例中是[CoroutineT r m ()],我们可以将其插入以获取

lift get
    :: (MonadTrans t, Monad m)
    => t (StateT [CoroutineT r m ()] m) [CoroutineT r m ()]

由于ContT r实现MonadTrans,我们可以替换它并获取

lift get
    :: (Monad m)
    => ContT r (StateT [CoroutineT r m ()] m) [CoroutineT r m ()]

现在,如果我们将它包装在CoroutineT构造函数中,我们就会得到

CoroutineT $ lift get
    :: (Monad m)
    => Coroutine r m [CoroutineT r m ()]

这是很多类型争论,只是说CoroutineT $ lift getMonadState get函数包装到CoroutineT类型中。这与putCCs非常相似。所有这些都是获取并设置[CoroutineT r m ()]的内部状态,在这个monad中很好地包裹起来。您可以使用这些定义将CoroutineT设为MonadState [CoroutineT r m]

的实例
instance MonadState [CoroutineT r m ()] (CoroutineT r m) where
    get = CoroutineT $ lift get
    put = CoroutineT . lift . put

理想情况下,您可以让GeneralizedNewtypeDeriving执行此操作,但可能无法执行此操作,因为它是递归类型定义。