MonadBaseControl IO ... StateT实现

Sim*_*Guy 4 monads haskell monad-transformers

我试图弄清楚如何为类型Foo 实现MonadBaseControl实例,这是一个围绕StateT实例的newtype包装器.你会认为它会像这样实现,但似乎并非如此.我假设状态片在这里引起了问题,所以有没有办法放弃它?

码:

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 
Run Code Online (Sandbox Code Playgroud)

错误:

 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
Run Code Online (Sandbox Code Playgroud)

Dan*_*ner 8

为了避免这种情况UndecidableInstances,链接的答案扩展了一个类型系列,为了人类的可读性,它实际上不应该具有.也就是说,他写道

instance MonadBaseControl IO Foo where
    type StM Foo a = a
Run Code Online (Sandbox Code Playgroud)

相反,人们可能会考虑写作

instance MonadBaseControl IO Foo where
    type StM Foo a = StM (ReaderT Int IO) a
Run Code Online (Sandbox Code Playgroud)

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

> :kind! forall a. StM (StateT Int IO) a
forall a. StM (StateT Int IO) a :: *
= (a, Int)
Run Code Online (Sandbox Code Playgroud)

所以对于我们的StateT版本Foo我们也可以写:

instance MonadBaseControl IO Foo where
    type StM Foo a = (a, Int)
Run Code Online (Sandbox Code Playgroud)