I'm attempting to use DataKinds to do type-level programming, but am running into difficulties when I have one of these structures nested in another.
{-# LANGUAGE DataKinds, TypeFamilies, GADTs, MultiParamTypeClasses, FlexibleInstances #-}
module Temp where
data Prop1 = D | E
data Lower :: Prop1 -> * where
SubThing1 :: Lower D
SubThing2 :: Lower E
class ClassLower a where
somefunc2 :: a -> String
instance ClassLower (Lower D) where
somefunc2 a = "string3"
instance ClassLower (Lower E) where
somefunc2 a = "string4"
data Prop2 = A | B | C
data Upper :: Prop2 -> * where
Thing1 :: Upper A
Thing2 :: Upper B
Thing3 :: Lower a -> Upper C
class ClassUpper a where
somefunc :: a -> String
instance ClassUpper (Upper A) where
somefunc a = "string1"
instance ClassUpper (Upper B) where
somefunc a = "string2"
instance ClassUpper (Upper C) where
somefunc (Thing3 x) = somefunc2 x
As soon as I add that last instance of ClassUpper, I end up with an error.
Temp.hs:37:25: error:
• Could not deduce (ClassLower (Lower a))
arising from a use of ‘somefunc2’
from the context: 'C ~ 'C
bound by a pattern with constructor:
Thing3 :: forall (a :: Prop1). Lower a -> Upper 'C,
in an equation for ‘somefunc’
at /Users/jdouglas/jeff/emulator/src/Temp.hs:37:13-20
• In the expression: somefunc2 x
In an equation for ‘somefunc’: somefunc (Thing3 x) = somefunc2 x
In the instance declaration for ‘ClassUpper (Upper 'C)’
I understand that 'C ~ 'C
indicates type equality, but I don't understand what the underlying problem is, much less the solution or workaround.
What am I not understanding, and what is the best way to tackle this problem?
Or you could write out your
ClassLower
instance like this, using pattern matching (rather than the type variable) to distinguish the cases of the GADT: