A lot of constraints seem to come together. Let's abstract these away.
type MonadNumState a m = (MonadState a m, Num a)
MonadNumState
is just a constraint synonym, so I get the benefit of functional dependencies at every use, and can easily throw a MonadNumState a m
into a context. Now, suppose I wish to abstract this into a constraint family:
class Iterator t where
type MonadIter t a m :: Constraint
next :: (MonadIter t a m) => m t
...
instance Iterator Foo where
type MonadIter Foo a m = (MonadState a m, Num a)
...
instance Iterator Bar where
type MonadIter Bar a m = (MonadRandom m, MonadSplit a m, RandomGen a)
...
But now a
is not a functional dependency. next
is virtually unusable since a
cannot be inferred. What can I do? Well, I could, of course, use a type family instead. MonadState
is written using fundeps, but it should be easy to convert the fundeps to type families.
instance (MonadState s m) => MonadStateFamily m where
type St m = s
get' = get
...
instance (MonadStateFamily m) => MonadState (St m) m where
get = get'
...
Guess not.
Foo.hs:25:3:
The RHS of an associated type declaration mentions type variable `s'
All such variables must be bound on the LHS
What else might I be able to do? What I really want is to existentially quantify away s
. I've not found any way to do that without explicit dictionary passing.
So, how do I get the benefit of fundeps for constraint families?
You can consider using a standalone type family instead of an associated type
type family StateType (m:: * -> *)
Then you can define
class MonadStateFamily m where
get' :: m (StateType m)
instance (MonadState s m, s ~ StateType m) => MonadStateFamily m where
get' = get
and use it on a concrete monad like this:
type instance StateType (State s) = s
getState :: State s s
getState = get'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With