MonadBaseControl IO ... StateT 实现

MonadBaseControl IO ... StateT Implementation

我正在尝试弄清楚如何实现 MonadBaseControl for type Foo which is a newtype wrapper around a StateT instance. You would think it would be implemented just like 的实例,但情况似乎并非如此。我假设 state piece 导致了这里的问题,那么有没有办法删除它?

代码:

newtype Foo a = Foo { unFoo :: StateT Int IO a } 
                deriving (Monad, Applicative, Functor, MonadBase IO)

instance MonadBaseControl IO Foo where
   type StM Foo a = a 
   liftBaseWith f = Foo $ liftBaseWith $ \q -> f (q . unFoo)
   restoreM = Foo . restoreM 

错误:

 Couldn't match type ‘a’ with ‘(a, Int)’
 ‘a’ is a rigid type variable bound by
 the type signature for restoreM :: StM Foo a -> Foo a
  Expected type: a -> StateT Int IO a  
 Actual type: StM (StateT Int IO) a -> StateT Int IO a
 Relevant bindings include
 restoreM :: StM Foo a -> Foo a
 In the second argument of ‘(.)’, namely ‘restoreM’
  In the expression: Foo . restoreM

为了避免 UndecidableInstances,链接的答案扩展了一个类型系列,为了人类的可读性,它确实不应该有。也就是说,他写道

instance MonadBaseControl IO Foo where
    type StM Foo a = a

什么时候可以考虑写作

instance MonadBaseControl IO Foo where
    type StM Foo a = StM (ReaderT Int IO) a

更清楚如何为给定的新类型包装选择正确的右侧。通过类似的更改(和 UndecidableInstances),您的代码可以正常工作。如果你想避免 UndecidableInstances,你可以在链接的答案中做同样的扩展;询问 ghci 扩展应该是什么的示例如下所示:

> :kind! forall a. StM (StateT Int IO) a
forall a. StM (StateT Int IO) a :: *
= (a, Int)

所以对于 FooStateT 版本,我们也可以这样写:

instance MonadBaseControl IO Foo where
    type StM Foo a = (a, Int)