Hello, yesterday I was looking at Monadstate
and wondering about the functional dependency in the definition, a dependency that does not allow you to have a MonadState
instance that focuses on a part of your BigState™.
Yesterday I found myself writing something like this:
{-# Language GeneralizedNewtypeDeriving #-}
{-# Language FlexibleContexts #-}
import Control.Monad.State.Strict
newtype MyState = MyState { str :: String,
bl :: Bool }
testState = MyState "foo" True
newtype Scaffold a = Scaffold (State MyState a)
deriving (Functor, Applicative, Monad, MonadState MyState)
This allows us to write a polymorphic function like
f :: (MonadState MyState m) => m Int
f = fromEnum <$> gets bl
prova :: Int
prova = evalState f testState
-- this will of course work with any instance (MonadState Mystate)
Which is extremely handy when you do not want to tie your code to a concrete type. But say now I have another function similar function which operates on Bool
rather than MyState
as state:
-- I can write this
g :: (MonadState Bool m) => m Int
g = fromEnum <$> get
instance MonadState Bool Scaffold where
{- This errors with:
src/Piece.hs:30:48-65: error:
Functional dependencies conflict between instance declarations:
instance MonadState MyState Scaffold
-- Defined at src/Piece.hs:30:48
instance MonadState Bool Scaffold -- Defined at src/Piece.hs:43:10 -}
I understand that the reason of functional dependencies is to avoid having to write countless annotations to make the compiler happy, but in this case I lose the ability of writing polymorphic code.
You can write a new class similar to
class MonadBool m where
putMM :: Menu -> m ()
but then you lose some convenience operators and similar goodies.
I am sure I must not be the first to have met this, is there a better way to walk around or approach the problem?