I have the following snippet:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeInType #-}
import Data.Proxy
data Foo where
FooInt :: Foo
FooProxy :: IsEnum e ~ True => Proxy e -> Foo
type family IsEnum e :: Bool
type family FromFoo (foo :: Foo) where
FromFoo FooInt = Int
FromFoo (FooProxy ('Proxy :: Proxy e)) = e
The general idea is that I'm trying to use Foo as a data kind where I could do
type MyFoo1 = FooInt :: Foo
type instance IsEnum Bool = True
type MyFoo2 = FooProxy ('Proxy :: Proxy Bool) :: Foo
and ensure that the proxied type being passed to FooProxy is a part of the IsEnum type family (I can't just do FooProxy :: Enum e => Proxy e -> Foo because only equality constraints are currently supported).
But when I try to compile this, I get the error:
<interactive>:30:12: error:
• Couldn't match expected kind ‘'True’ with actual kind ‘IsEnum e’
• In the first argument of ‘FromFoo’, namely
‘(FooProxy ( 'Proxy :: Proxy e))’
In the type family declaration for ‘FromFoo’
The problem is when I want to convert from my Foo type to the concrete type in FromFoo, I want FooProxy to evaluate to the proxied type. So I'm trying to pattern match on Proxy to return the proxied type e, but then it seems to be checking the IsEnum e ~ True constraint again. I would think that the constraint would only be checked when creating a FooProxy value, but it seems to be checking again when pattern matching.