Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MonadBaseControl IO ... StateT Implementation

I'am trying to figure out how to implement an instance of MonadBaseControl for type Foo which is a newtype wrapper around a StateT instance. You would think it would be implemented just like this but that does not seem to be the case. I'm assuming the state piece is causing the issue here, so is there a way to drop it?

Code:

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 

Error:

 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
like image 582
SimpleGuy Avatar asked Feb 08 '23 15:02

SimpleGuy


1 Answers

To avoid UndecidableInstances, the linked answer expanded a type family that, for human readability, it really shouldn't have. Namely, he writes

instance MonadBaseControl IO Foo where
    type StM Foo a = a

when instead one might consider writing

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

to make it more clear how to choose the correct right-hand side for a given newtype wrapping. With the analogous change (and UndecidableInstances), your code works fine. If you want to avoid UndecidableInstances, you can do the same expansion done in the linked answer; an example of asking ghci what the expansion should be looks like this:

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

So for the StateT version of Foo we could also write:

instance MonadBaseControl IO Foo where
    type StM Foo a = (a, Int)
like image 163
Daniel Wagner Avatar answered Feb 14 '23 07:02

Daniel Wagner