I'm incompetently trying to play with the new closed type family feature of GHC 7.8 and I would like to find a nice way to branch on type level constructs.
I have something like
data (:::) :: Symbol -> * -> * where
data Result = Pre | Post | Match
type family Cmp a b :: Result where
Cmp (s ::: t) (s ::: t) = Match
Cmp (s1 ::: t1) (s2 ::: t2) = ???
where I would like to return different types depending on the result of
CmpSymbol
in GHC.TypeLits. It feels like something like
Cmp (s1 ::: t1) (s2 ::: t2) = (CmpSymbol s1 s2 ~ LT) => Pre
Cmp (s1 ::: t1) (s2 ::: t2) = (CmpSymbol s1 s2 ~ GT) => Post
should work, but it does not. Interestingly it's not a syntax error but instead a complaint that it is ill kinded.
I can somehow get it to work by using undecidable instances and a helper function:
type family Cmp a b :: Result where
Cmp (s ::: t) (s ::: t) = Match
Cmp (s1 ::: t1) (s2 ::: t2) = Fun (CmpSymbol s1 s2)
type family Fun r :: Result where
Fun LT = Pre
Fun GT = Post
But this feels rather clunky, surely there is a nicer way? Also ghci says
something like :kind! Cmp ("a" ::: Int) ("a" ::: String)
has type Fun 'EQ
even though Fun
is closed. Why is that? I also can't see an easy way to
work with ordinary classes here? What if the definition of Fun
was something
like
class Fun2 o r
instance Fun2 LT Pre
instance Fun2 GT Post
Is there any way to talk to type classes in a nice way or am I restricted to just
using other type families like Fun
?