How to put constraints on type variable of kind `Constraint`?
gadt, ghc, haskell, typeclass
Solution
The closest we are able to get is a `Class1` class that reifys the relationship between a class and a single superclass constraint as a class. It's based on the `Class` from constraints.
First, we'll take a short tour of the constraints package. A `Dict` captures the dictionary for a `Constraint`
data Dict :: Constraint -> * where
Dict :: a => Dict a
`:-` captures that one constraint entails another. If we have `a :- b`, whenever we have the constraint `a` we can produce the dictionary for the constraint `b`.
newtype a :- b = Sub (a => Dict b)
We need a proof similar to `:-`, we need to know that `forall a. h a :- b a`, or `h a => Dict (b a)`.
Single Inheritance
Actually implementing this for `class`es with just single inheritance requires the kitchen sink of language extensions, including `OverlappingInstances`.
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE OverlappingInstances #-}
import Data.Constraint
We'll define the class of constraints of kind `k -> Constraint` where the constraint has a single superclass.
class Class1 b h | h -> b where
cls1 :: h a :- b a
We're now equipped to tackle our example problem. We have a class `A` that requires a `Show` instance.
class Show a => A a
instance A Int
`Show` is a superclass of `A`
instance Class1 Show A where
cls1 = Sub Dict
We want to write `Show` instances for `Some`
data Some (c :: * -> Constraint) where
Some :: c a => a -> Some c
We can `Show` a `Some Show`.
instance Show (Some Show) where
showsPrec x (Some a) = showsPrec x a
We can `Show` a `Some h` whenever `h` has a single superclass `b` and we could show `Some b`.
instance (Show (Some b), Class1 b h) => Show (Some h) where
showsPrec x (Some (a :: a)) =
case cls1 :: h a :- b a of
Sub Dict -> showsPrec x ((Some a) :: Some b)
This lets us write
x :: Some A
x = Some (1 :: Int)
main = print x
Problem
I'm playing around with the `ConstraintKinds` extension of GHC. I have the following data type, which is just a box for things fulfilling some one parameter constraint `c`: ``` data Some (c :: * -> Constraint) where Some :: forall a. c a => a -> Some c ``` For example, I could construct a box with some kind of number (arguably not very useful). ``` x :: Some Num x = Some (1 :: Int) ``` Now, as long as `c` includes the constraint `Show`, I could provide an instance of `Show (Some c)`. ``` instance ??? => Show (Some c) where show (Some x) = show x -- Show dictionary for type of x should be in scope here ``` But how do I express this requirement in the instance context (marked with `???`)? I cannot use an equality constraint (`c ~ Show`), because the two are not necessarily equal. `c` could be `Num`, which implies, but is not equal to, `Show`. Edit I realised that this cannot be possible in general. If you have two values of type `Some Eq`, it is not possible to compare them for equality. They could be of different types that each have their own notion of equality. What applies to `Eq` applies to any type class in which the type parameter appears on the right hand side of the first function arrow (like the second `a` in `(==) :: a -> a -> Bool`). Considering that there is no way to create a constraint expressing "this type variable is not used beyond the first arrow", I don't think it is possible to write the instance I want to write.