在延续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
然后还使用dequeue
和queue
定义了后来的getCCs
和putCCs
函数。
我不明白如何维护Coroutine队列。 getCCs
和putCCs
的类型签名似乎并不表示在调用之间保持任何类型的“变量”。我怀疑州在get
和put
的实施中与getCCs
和putCCs
有关,但我不知道它们是什么。
答案 0 :(得分:1)
CoroutineT
只是monad转换器堆栈ContT r (StateT [CoroutineT r m ()] m) a
类型的包装器。这实质上意味着它是包含状态类型为[CoroutineT r m ()]
的状态monad的continuation monad。 get
和put
函数是MonadState
类型类的成员,StateT
实现。当您致电lift get
时,它的类型为(MonadTrans t, MonadState m s) => t m s
。由于StateT s
是MonadState 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 get
将MonadState
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
执行此操作,但可能无法执行此操作,因为它是递归类型定义。