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
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.