I am experimenting with an mtl
-style class that allows me to lift Pipe
composition over an outer monad. To do so, I must define which two variables of the type are the domain and codomain of Pipe
composition.
I tried using an associated type family approach, but to no avail:
{-# LANGUAGE TypeFamilies #-}
import Control.Monad.Trans.Free
import Control.Monad.Trans.State
import Control.Pipe hiding (Pipe)
data Pipe a b m r = Pipe { unPipe :: FreeT (PipeF a b) m r }
class MonadPipe m where
type C a b (m :: * -> *) :: * -> *
idT :: C a a m r
(<-<) :: C b c m r -> C a b m r -> C a c m r
instance (Monad m) => MonadPipe (Pipe i o m) where
type C a b (Pipe i o m) = Pipe a b m
idT = Pipe idP
(Pipe p1) <-< (Pipe p2) = Pipe (p1 <+< p2)
instance (MonadPipe m) => MonadPipe (StateT s m) where
type C a b (StateT s m) = StateT s (C a b m)
idT = StateT $ \s -> idT
(StateT f1) <-< (StateT f2) = StateT $ \s -> f1 s <-< f2 s
However, the above code does not type-check. GHC gives the following errors:
family.hs:23:15:
Could not deduce (C a a m ~ C a0 a0 m0)
from the context (MonadPipe m)
bound by the instance declaration at family.hs:21:14-52
NB: `C' is a type function, and may not be injective
Expected type: C a a (StateT s m) r
Actual type: StateT s (C a0 a0 m0) r
In the expression: StateT $ \ s -> idT
In an equation for `idT': idT = StateT $ \ s -> idT
In the instance declaration for `MonadPipe (StateT s m)'
family.hs:24:10:
Could not deduce (C b c m ~ C b0 c0 m1)
from the context (MonadPipe m)
bound by the instance declaration at family.hs:21:14-52
NB: `C' is a type function, and may not be injective
Expected type: C b c (StateT s m) r
Actual type: StateT s (C b0 c0 m1) r
In the pattern: StateT f1
In an equation for `<-<':
(StateT f1) <-< (StateT f2) = StateT $ \ s -> f1 s <-< f2 s
In the instance declaration for `MonadPipe (StateT s m)'
<<Two other errors for 'C a b m' and 'C a c m'>>
It's hard for me to understand why the types won't unify, especially for the idT
definition, since I'd expect the inner idT
to be universally quantified over a
so it would match the outer one.
So my question is whether this is implementable with type families, and if not possible with type families, how could it be implemented?