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 constrai
The new QuantifiedConstraints extension allows this.
class (a => b) => Implies a b where
instance (a => b) => Implies a b where
instance (forall a. c a `Implies` Show a) => Show (Some c) where
show (Some x) = show x
Within the body of the Show instance, it is as if there is a
instance forall a. Implies (c a) (Show a)
in scope. If you then have T :: Type and know c T, then the superclass of c T => Show T of the specialized Implies (c T) (Show T) instance allows you to derive Show T. It is necessary to use Implies instead of a straight forall a. c a => Show a constraint. This incorrect constraint acts like
instance forall a. c a => Show a
which overlaps with every Show instance, causing weird breakage. Forcing an indirection through the superclass of an otherwise useless constraint fixes everything.
You cannot make Some c an instance of Show, except trivially.
You want to show the a inside Some, but that variable is existentially quantified, so we cannot depend on any knowledge of the type of a. In particular, we have no way of knowing that a is an instance of Show.
EDIT: I'll expand on my answer.
Even with more machinery, and giving up on a Show instance, I still don't think what you want is possible because of the existential quantification.
First I'll rewrite Some in a more familiar form
data Dict p where
Dict :: p a => a -> Dict p
The usual way to talk about "constraints implying constraints" is with the concept of constraint entailment.
data p :- q where
Sub :: p a => Dict q -> p :- q
We can think about a value of type p :- q as a proof that if the constraint forall a. p a holds, then forall a. q a follows.
Now we try to write a sensible show-ish function
showD :: p :- Show -> Dict p -> String
showD (Sub (Dict a)) (Dict b) = show b
At a glance, this might work. We have brought the following constraints into scope (forgive the pseudo-exists syntax)
(0) p :: * -> Constraint
(1) exists a. p a -- (Dict p)
(2) exists b. p b => Show b -- (p :- Show)
But now things fall apart, GHC rightfully complains:
main.hs:10:33:
Could not deduce (Show a2) arising from a use of `show'
from the context (p a)
bound by a pattern with constructor
Sub :: forall (p :: * -> Constraint) (q :: * -> Constraint) a.
(p a) =>
Dict q -> p :- q,
in an equation for `showD'
at main.hs:10:8-19
or from (Show a1)
bound by a pattern with constructor
Dict :: forall (p :: * -> Constraint) a. (p a) => a -> Dict p,
in an equation for `showD'
at main.hs:10:13-18
or from (p a2)
bound by a pattern with constructor
Dict :: forall (p :: * -> Constraint) a. (p a) => a -> Dict p,
in an equation for `showD'
at main.hs:10:23-28
because it is impossible to unify the a from (1) with the b from (2).
This is the same essential idea that is used throughout the constraints package mentioned in the comments.
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).
Actually implementing this for classes 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