Search code examples
haskellmonad-transformersstate-monad

Haskell -- Chaining two states using StateT monad transformers


I have two or more independent states to track in one Haskell application.

I am declaring two new type classes using

type MonadTuple m = MonadState (Int, Int) m
type MonadBool m = MonadState Bool m

The monad transformer stack is declared as

type Stack = StateT (Int, Int) (StateT Bool IO) ()

I intend to use the stack as such

ret :: Stack
ret = apply

apply :: (MonadTuple m, MonadBool m) => m ()
apply = undefined

The complier is unhappy because it cannot match Bool with (Int, Int) when trying to check if Stack conforms to MonadBool.

I am aware of the solution given in the Combining multiple states in StateT. Are there any simpler solutions other than arrows or global state with lens?

Appendix: The full code block is

{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}

import Control.Monad.State.Class
import Control.Monad.State.Lazy

type MonadTuple m = MonadState (Int, Int) m
type MonadBool m = MonadState Bool m

type Stack = StateT (Int, Int) (StateT Bool IO) ()

ret :: Stack
ret = apply

apply :: (MonadTuple m, MonadBool m) => m ()
apply = undefined

Solution

  • The definition of MonadState has a functional dependency m -> s, which means that one monad m must have at most one instance of MonadState s m. Or, in plainer terms, the same monad cannot have two instances of MonadState for two different states, which is exactly what you're trying to do.