6
votes

I have code that works for a monad that's constrained to have some state. I'm having a problem because the state has a type variable that requires the monad.

It looks like:

myget :: MonadState (MyState m A) m => m A

Now when I try to make it more specific, there's a problem. E.g. just with StateT (on some inner-monad im):

myget' :: StateT <loops here> im A
myget' :: StateT (MyState <loop> A) im A
myget' :: StateT (MyState (MyState <loop> A) A) im A
myget' :: StateT (MyState (MyState (MyState <loop> A) A) A) im A
...
myget' = myget

So obviously I can't write this type signature; I can't even leave it for type-inference.

How can I solve this?
I did kind of solve it by making myget (the first, general definition) work on a monad transformer instead, and it did work, but then the code doesn't play nicely with anything else (because usually people work with monads transformers as just monads), so it's not a really good solution.

Any ideas?

1
What does MyState look like, by the way?dfeuer
Can you define your own monad, MSM, with an instance that's something along the lines of MonadState (MyState MSM A) MSM?Tanner Swett
@dfeuer MyState m a looks like a record of {msValue :: a, msValidate :: m Bool} (in the actual code it's authentication data).MasterMastic

1 Answers

4
votes

newtype to the rescue! A newtype or data declaration can break a loop.

newtype MS s m a = MS
  {getMS :: StateT (MyState (MS s m) s) m a}
  deriving (Functor, Applicative, Monad)

deriving instance Monad m =>
  MonadState (MyState (MS s m) s) (MS s m)

instance MonadTrans (MS s) where
  lift = MS . lift