Search code examples
haskellgadtrank-n-types

Generalizing from a specific type to a class in a GADT


I have the following definitions

{-# LANGUAGE GADTs, TypeInType, RankNTypes #-}
import Data.Kind

class Character (a :: * -> *) where
  showVal :: a b -> b -> String

data ExampleCharacter a where
  Variable :: ExampleCharacter String
  EqualSign :: ExampleCharacter ()
  Deref :: ExampleCharacter ()

instance Character ExampleCharacter where
  showVal Variable = id
  showVal EqualSign = const "="
  showVal Deref = const "*"

data Symbol :: forall a. ExampleCharacter a -> * where
  Terminal :: a -> Symbol (b :: ExampleCharacter a)

as you can see I have defined a Symbol class that uses ExampleCharacters in the type signature. Example usage would be let sym = Terminal "xyy" :: Symbol Variable creating a variable symbol with the name "xyy".

Now, the obvious next step would be to generalize ExampleCharacter to Character c. I tried the following:

data Symbol :: (forall c (a :: *). Character c) => c a -> * where
  Terminal :: a -> Symbol (b :: c a)

But I get the following error:

main.hs:22:20: error:
    • Illegal constraint in a type: forall (c :: * -> *) a. Character c
    • In the type ‘Symbol (b :: c a)’
      In the definition of data constructor ‘Terminal’
      In the data declaration for ‘Symbol’

I'm not quite sure what the error wants to tell me. Why is forall (c :: * -> *) a. Character c an illegal constraint and how so? Is there any way around it?


Solution

  • From the docs:

    As kinds and types are the same, kinds can now (with -XTypeInType) contain type constraints. Only equality constraints are currently supported, however. We expect this to extend to other constraints in the future.

    So in principle what you've written is sensible; it simply isn't supported yet (as of writing, most recent GHC is 8.2.2).