What is a Constraint kind?
Why would someone use it (in practice)?
What is it good for?
Could you give a simple code example to illustrate the answers to the previous two questions?
Why is it used in this code for example?
What is a Constraint kind?
Why would someone use it (in practice)?
What is it good for?
Could you give a simple code example to illustrate the answers to the previous two questions?
Why is it used in this code for example?
Well, I'll mention two practical things it allows you to do:
Maybe it's best to illustrate this with an example. One of the classic Haskell warts is that you cannot make a
Functor
instance for types that impose a class constraint on their type parameter; for example, theSet
class in thecontainers
library, which requires anOrd
constraint on its elements. The reason is that in "vanilla" Haskell, you'd have to have the constraint on the class itself:...but then this class only works for types that require specifically an
Ord
constraint. Not a general solution!So what if we could take that class definition and abstract away the
Ord
constraint, allowing individual instances to say what constraint they require? Well,ConstraintKinds
plusTypeFamilies
allow that:(Note that this isn't the only obstacle to making a
Functor
instance toSet
; see this discussion. Also, credit to this answer for theNoConstraint
trick.)This sort of solution hasn't been generally adopted just yet, though, because
ConstraintKinds
are still more or less a new feature.Another use of
ConstraintKinds
is to parametrize a type by a class constraint or class. I'll reproduce this Haskell "Shape Example" code that I wrote:Here the parameter of the
Object
type is a type class (kind* -> Constraint
), so you can have types likeObject Shape
whereShape
is a class:What the
Object
type does is a combination of two features:GADTs
), which allows us to store values of heterogeneous types inside the sameObject
type.ConstraintKinds
, which allows us to, instead of hardcodingObject
to some specific set of class constraints, have the users of theObject
type specify the constraint they want as a parameter to theObject
type.And now with that we can not only make a heterogeneous list of
Shape
instances:...but thanks to the
Typeable
constraint inObject
we can downcast: if we correctly guess the type contained inside anObject
, we can recover that original type:The
ConstraintKind
extension allows the use of theConstraint
kind. Every expression that appears in a context (generally the things between::
and=>
), has kindConstraint
. For example, in ghci:Generally, it is not possible to manually use this kind, but the
ConstraintKinds
extension allows it. For example, one can now write:Now that you have something that takes a type (kind
*
), and gives aConstraint
, you can write code like this.It is possible that the library you linked to uses
MonadWidget
as a type synonym withConstraint
kind, but you'll have to take a closer look to make sure.