HORIZON HASKELLDocslts/ghc-9.10.x248f8f02026-10-05Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · 248f8f0 · 2026-10-05

Moduleconstraints-0.14.2Haskell2010

Data.Constraint

ConstraintKinds made type classes into types of a new kind, Constraint.

Eq :: * -> Constraint
Ord :: * -> Constraint
Monad :: (* -> *) -> Constraint

The need for this extension was first publicized in the paper

Scrap your boilerplate with class: extensible generic functions

by Ralf Lämmel and Simon Peyton Jones in 2005, which shoehorned all the things they needed into a custom Sat typeclass.

With ConstraintKinds we can put into code a lot of tools for manipulating these new types without such awkward workarounds.

  • 4 types
  • 6 classes
  • 16 values
  • Packageconstraints-0.14.2
  • Exports26
  • LanguageHaskell2010
  • LicenceBSD-2-Clause
  • SourceConstraint.hs

The Kind of Constraints

1 declaration

The kind of lifted constraints

Instances5Category, InstV, ForallV'
  • Category (:-)Defined in constraints-0.14.2 · Data.Constraint

    Possible since GHC 7.8, when Category was made polykinded.

  • p ~ c => InstV p cDefined in constraints-0.14.2 · Data.Constraint.Forall
  • p a ~ c => InstV p cDefined in constraints-0.14.2 · Data.Constraint.Forall
  • type ForallV' p = Forall pDefined in constraints-0.14.2 · Data.Constraint.Forall
  • type ForallV' p = pDefined in constraints-0.14.2 · Data.Constraint.Forall

Dictionary

4 declarations
datadata Dict (a :: Constraint) where
#

Values of type Dict p capture a dictionary for a constraint of type p.

e.g.

Dict :: Dict (Eq Int)

captures a dictionary that proves we have an:

instance Eq Int

Pattern matching on the Dict constructor will bring this instance into scope.

Constructors

Instances20:=>, HasDict, Bounded, Enum, Eq, Data, …
  • () :=> Semigroup (Dict a)Defined in constraints-0.14.2 · Data.Constraint
  • () :=> Show (Dict a)Defined in constraints-0.14.2 · Data.Constraint
  • () :=> Eq (Dict a)Defined in constraints-0.14.2 · Data.Constraint
  • () :=> Ord (Dict a)Defined in constraints-0.14.2 · Data.Constraint
  • a :=> Monoid (Dict a)Defined in constraints-0.14.2 · Data.Constraint
  • a :=> Bounded (Dict a)Defined in constraints-0.14.2 · Data.Constraint
  • a :=> Enum (Dict a)Defined in constraints-0.14.2 · Data.Constraint
  • a :=> Read (Dict a)Defined in constraints-0.14.2 · Data.Constraint
  • HasDict a (Dict a)Defined in constraints-0.14.2 · Data.Constraint
  • a => Bounded (Dict a)Defined in constraints-0.14.2 · Data.Constraint
  • a => Enum (Dict a)Defined in constraints-0.14.2 · Data.Constraint
  • Eq (Dict a)Defined in constraints-0.14.2 · Data.Constraint
  • (Typeable p, p) => Data (Dict p)Defined in constraints-0.14.2 · Data.Constraint
  • Ord (Dict a)Defined in constraints-0.14.2 · Data.Constraint
  • a => Read (Dict a)Defined in constraints-0.14.2 · Data.Constraint
  • Show (Dict a)Defined in constraints-0.14.2 · Data.Constraint
  • Semigroup (Dict a)Defined in constraints-0.14.2 · Data.Constraint
  • a => Monoid (Dict a)Defined in constraints-0.14.2 · Data.Constraint
  • NFData (Dict c)Defined in constraints-0.14.2 · Data.Constraint
  • c => Boring (Dict c)Defined in constraints-0.14.2 · Data.Constraint
classclass HasDict (c :: Constraint) e | e -> c where
#

Witnesses that a value of type e contains evidence of the constraint c.

Mainly intended to allow (\\) to be overloaded, since it's a useful operator.

Methods

Instances6HasDict
valuewithDict :: HasDict c e => e -> (c => r) -> r
#

From a Dict, takes a value in an environment where the instance witnessed by the Dict is in scope, and evaluates it.

Essentially a deconstruction of a Dict into its continuation-style form.

Can also be used to deconstruct an entailment, a :- b, using a context a.

withDict :: Dict c -> (c => r) -> r
withDict :: a => (a :- c) -> (c => r) -> r
value(\\) :: HasDict c e => (c => r) -> e -> r
#

Operator version of withDict, with the arguments flipped

Entailment

17 declarations
newtypenewtype (:-) (a :: Constraint) (b :: Constraint)
#

This is the type of entailment.

a :- b is read as a "entails" b.

With this we can actually build a category for Constraint resolution.

e.g.

Because Eq a is a superclass of Ord a, we can show that Ord a entails Eq a.

Because instance Ord a => Ord [a] exists, we can show that Ord a entails Ord [a] as well.

This relationship is captured in the :- entailment type here.

Since p :- p and entailment composes, :- forms the arrows of a Category of constraints. However, Category only became sufficiently general to support this instance in GHC 7.8, so prior to 7.8 this instance is unavailable.

But due to the coherence of instance resolution in Haskell, this Category has some very interesting properties. Notably, in the absence of IncoherentInstances, this category is "thin", which is to say that between any two objects (constraints) there is at most one distinguishable arrow.

This means that for instance, even though there are two ways to derive Ord a :- Eq [a], the answers from these two paths _must_ by construction be equal. This is a property that Haskell offers that is pretty much unique in the space of languages with things they call "type classes".

What are the two ways?

Well, we can go from Ord a :- Eq a via the superclass relationship, and then from Eq a :- Eq [a] via the instance, or we can go from Ord a :- Ord [a] via the instance then from Ord [a] :- Eq [a] through the superclass relationship and this diagram by definition must "commute".

Diagrammatically,

                   Ord a
               ins /     \ cls
                  v       v
            Ord [a]     Eq a
               cls \     / ins
                    v   v
                   Eq [a]

This safety net ensures that pretty much anything you can write with this library is sensible and can't break any assumptions on the behalf of library authors.

Constructors

Instances10Category, :=>, HasDict, Eq, Data, Ord, …
  • Category (:-)Defined in constraints-0.14.2 · Data.Constraint

    Possible since GHC 7.8, when Category was made polykinded.

  • () :=> Show (a :- b)Defined in constraints-0.14.2 · Data.Constraint
  • () :=> Eq (a :- b)Defined in constraints-0.14.2 · Data.Constraint
  • () :=> Ord (a :- b)Defined in constraints-0.14.2 · Data.Constraint
  • a => HasDict b (a :- b)Defined in constraints-0.14.2 · Data.Constraint
  • Eq (a :- b)Defined in constraints-0.14.2 · Data.Constraint

    Assumes IncoherentInstances doesn't exist.

  • (Typeable p, Typeable q, p => q) => Data (p :- q)Defined in constraints-0.14.2 · Data.Constraint
  • Ord (a :- b)Defined in constraints-0.14.2 · Data.Constraint

    Assumes IncoherentInstances doesn't exist.

  • Show (a :- b)Defined in constraints-0.14.2 · Data.Constraint
  • a => NFData (a :- b)Defined in constraints-0.14.2 · Data.Constraint
typetype (⊢) = (:-)
#

Type entailment, as written with a single character.

classclass (p => q) => (|-) (p :: Constraint) (q :: Constraint)
#

The internal hom for the category of constraints.

This version can be passed around inside Dict, whereas (a => b) is impredicative

foo :: Dict (Ord a => Eq a)
foo = Dict

fails to typecheck due to the lack of impredicative polymorphism, but

foo :: Dict (Ord a |- Eq a)
foo = Dict

typechecks just fine.

Instances1|-
  • (p => q) => p |- qDefined in constraints-0.14.2 · Data.Constraint
classclass (p, q) => (&) (p :: Constraint) (q :: Constraint)
#

due to the hack for the kind of (,) in the current version of GHC we can't actually make instances for (,) :: Constraint -> Constraint -> Constraint, but we can define an equivalent type, that converts back and forth to (,), and lets you hang instances.

Instances1&
  • (p, q) => p & qDefined in constraints-0.14.2 · Data.Constraint
valueweaken1 :: (a, b) :- a
#

Weakening a constraint product

The category of constraints is Cartesian. We can forget information.

valueweaken2 :: (a, b) :- b
#

Weakening a constraint product

The category of constraints is Cartesian. We can forget information.

valuecontract :: a :- (a, a)
#

Contracting a constraint / diagonal morphism

The category of constraints is Cartesian. We can reuse information.

value(&&&) :: a :- b -> a :- c -> a :- (b, c)
#

Constraint product

trans weaken1 (f &&& g) = f
trans weaken2 (f &&& g) = g
value(***) :: a :- b -> c :- d -> (a, c) :- (b, d)
#

due to the hack for the kind of (,) in the current version of GHC we can't actually make instances for (,) :: Constraint -> Constraint -> Constraint, but (,) is a bifunctor on the category of constraints. This lets us map over both sides.

valuetrans :: b :- c -> a :- b -> a :- c
#

Transitivity of entailment

If we view (:-) as a Constraint-indexed category, then this is (.)

valuerefl :: a :- a
#

Reflexivity of entailment

If we view (:-) as a Constraint-indexed category, then this is id

valueimplied :: (a => b) => a :- b
#

Convert a quantified constraint into an entailment.

classclass Any => Bottom where
#

Any inhabits every kind, including Constraint but is uninhabited, making it impossible to define an instance.

Methods

valuetop :: a :- ()
#

Every constraint implies truth

These are the terminal arrows of the category, and () is the terminal object.

Given any constraint there is a unique entailment of the () constraint from that constraint.

Dict is fully faithful

2 declarations
valuemapDict :: a :- b -> Dict a -> Dict b
#

Apply an entailment to a dictionary.

From a category theoretic perspective Dict is a functor that maps from the category of constraints (with arrows in :-) to the category Hask of Haskell data types.

valueunmapDict :: (Dict a -> Dict b) -> a :- b
#

This functor is fully faithful, which is to say that given any function you can write Dict a -> Dict b there also exists an entailment a :- b in the category of constraints that you can build.

Reflection

2 declarations
classclass Class (b :: Constraint) (h :: Constraint) | h -> b where
#

Reify the relationship between a class and its superclass constraints as a class

Given a definition such as

class Foo a => Bar a

you can capture the relationship between 'Bar a' and its superclass 'Foo a' with

instance Class (Foo a) (Bar a) where cls = Sub Dict

Now the user can use 'cls :: Bar a :- Foo a'

Methods

Instances25:=>, Class, …
classclass (:=>) (b :: Constraint) (h :: Constraint) | h -> b where
#

Reify the relationship between an instance head and its body as a class

Given a definition such as

instance Foo a => Foo [a]

you can capture the relationship between the instance head and its body with

instance Foo a :=> Foo [a] where ins = Sub Dict

Methods

Instances194Class, :=>, …