Kind (type theory)
In the area of
A kind is sometimes confusingly described as the "type of a
Since higher-order type operators are uncommon in
Examples
- , pronounced "type", is the kind of all functional programming languages.
- is the kind of a list typeconstructor.
- is the kind of a pair type constructor, and also that of a function typeconstructor (not to be confused with the result of its application, which itself is a function type, thus of kind )
- is the kind of a higher-order type operator from unary type constructors to proper types.[3]
Kinds in Haskell
(Note: Haskell documentation uses the same arrow for both function types and kinds.)
The kind system of
- , pronounced "type" is the kind of all data types.
- is the kind of a unary type constructor, which takes a type of kind and produces a type of kind .
An inhabited type (as proper types are called in Haskell) is a type which has values. For instance, ignoring type classes which complicate the picture, 4
is a value of type Int
, while [1, 2, 3]
is a value of type [Int]
(list of Ints). Therefore, Int
and [Int]
have kind , but so does any function type, for instance Int -> Bool
or even Int -> Int -> Bool
.
A type constructor takes one or more type arguments, and produces a data type when enough arguments are supplied, i.e. it supports partial application thanks to currying.[5][6] This is how Haskell achieves parametric types. For instance, the type []
(list) is a type constructor - it takes a single argument to specify the type of the elements of the list. Hence, [Int]
(list of Ints), [Float]
(list of Floats) and even [[Int]]
(list of lists of Ints) are valid applications of the []
type constructor. Therefore, []
is a type of kind . Because Int
has kind , applying []
to it results in [Int]
, of kind . The 2-tuple constructor (,)
has kind , the 3-tuple constructor (,,)
has kind and so on.
Kind inference
Standard Haskell does not allow polymorphic kinds. This is in contrast to parametric polymorphism on types, which is supported in Haskell. For instance, in the following example:
data Tree z = Leaf | Fork (Tree z) (Tree z)
the kind of z
could be anything, including , but also etc. Haskell by default will always infer kinds to be , unless the type explicitly indicates otherwise (see below). Therefore the type checker will reject the following use of Tree
:
type FunnyTree = Tree [] -- invalid
because the kind of []
, does not match the expected kind for z
, which is always .
Higher-order type operators are allowed however. For instance:
data App unt z = Z (unt z)
has kind , i.e. unt
is expected to be a unary data constructor, which gets applied to its argument, which must be a type, and returns another type.
GHC has the extension PolyKinds
, which, together with KindSignatures
, allows polymorphic kinds. For example:
data Tree (z :: k) = Leaf | Fork (Tree z) (Tree z)
type FunnyTree = Tree [] -- OK
Since GHC 8.0.1, types and kinds are merged.[7]
See also
- System F-omega
- Pure type system
References
- Pierce, Benjamin (2002). ISBN 0-262-16209-1., chapter 29, "Type Operators and Kinding"
- ^ "CS 115: Parametric Polymorphism: Template Functions". www2.cs.uregina.ca. Retrieved 2020-08-06.
- ^ "Generics of a Higher Kind" (PDF). Archived from the original (PDF) on 2012-06-10. Retrieved 2012-06-10.
- ^ Pierce (2002), chapter 32
- ^ Kinds - The Haskell 98 Report
- ^ "Chapter 4 Declarations and Binding". Haskell 2010 Language Report. Retrieved 23 July 2012.
- ^ Miran, Lipovača. "Learn You a Haskell for Great Good!". Making Our Own Types and Typeclasses. Retrieved 23 July 2012.
- ^ "9.1. Language options — Glasgow Haskell Compiler Users Guide".