First off, *
is not a wildcard! It's also typically pronounced "star."
Bleeding edge note: There is as of Feb. 2015 a proposal to simplify GHC's subkind system (in 7.12 or later). That page contains a good discussion of the GHC 7.8/7.10 story. Looking forward, GHC may drop the distinction between types and kinds, with * :: *
. See Weirich, Hsu, and Eisenberg, System FC with Explicit Kind Equality.
The Standard: A description of type expressions.
The Haskell 98 report defines *
in this context as:
The symbol *
represents the kind of all nullary type constructors.
In this context, "nullary" simply means that the constructor takes no parameters. Either
is binary; it can be applied to two parameters: Either a b
. Maybe
is unary; it can be applied to one parameter: Maybe a
. Int
is nullary; it can be applied to no parameters.
This definition is a little bit incomplete on its own. An expression containing a fully-applied unary, binary, etc. type constructor also has kind *
, e.g. Maybe Int :: *
.
In GHC: Something that contains values?
If we poke around the GHC documentation, we get something closer to the "can contain a runtime value" definition. The GHC Commentary page "Kinds" states that "'*
' is the kind of boxed values. Things like Int
and Maybe Float
have kind *
." The GHC user's guide for version 7.4.1, on the other hand, stated that *
is the kind of "lifted types". (That passage wasn't retained when the section was revised for
PolyKinds
.)
Boxed values and lifted types are a bit different. According to the GHC Commentary page "TypeType",
A type is unboxed iff its representation is other than a pointer. Unboxed types are also unlifted.
A type is lifted iff it has bottom as an element. Closures always have lifted types: i.e. any let-bound identifier in Core must have a lifted type. Operationally, a lifted object is one that can be entered. Only lifted types may be unified with a type variable.
So ByteArray#
, the type of raw blocks of memory, is boxed because it is represented as a pointer, but unlifted because bottom is not an element.
> undefined :: ByteArray#
Error: Kind incompatibility when matching types:
a0 :: *
ByteArray# :: #
Therefore it appears that the old User's Guide definition is more accurate than the GHC Commentary one: *
is the kind of lifted types. (And, conversely, #
is the kind of unlifted types.)
Note that if types of kind *
are always lifted, for any type t :: *
you can construct a "value" of sorts with undefined :: t
or some other mechanism to create bottom. Therefore even "logically uninhabited" types like Void
can have a value, i.e. bottom.
So it seems that, yes, *
represents the kind of types that can contain runtime values, if undefined
is your idea of a runtime value. (Which isn't a totally crazy idea, I don't think.)
GHC Extensions?
There are several extensions which liven up the kind system a bit. Some of these are mundane: KindSignatures
lets us write kind annotations, like type annotations.
ConstraintKinds
adds the kind Constraint
, which is, roughly, the kind of the left-hand side of =>
.
DataKinds
lets us introduce new kinds besides *
and #
, just as we can introduce new types with data
, newtype
, and type
.
With DataKinds
every data
declaration (terms and conditions may apply) generates a promoted kind declaration. So
data Bool = True | False
introduces the usual value constructor and type name; additionally, it produces a new kind, Bool
, and two types: True :: Bool
and False :: Bool
.
PolyKinds
introduces kind variables. This just a way to say "for any kind k
" just like we say "for any type t
" at the type level. As regards our friend *
and whether it still means "types with values", I suppose you could say a type t :: k
where k
is a kind variable could contain values, if k ~ *
or k ~ #
.