Learn You a Haskell For Great Good says:
Types are little labels that values carry so that we can reason about the values. But types have their own little labels, called kinds. A kind is more or less the type of a type. … What are kinds and what are they good for? Well, let’s examine the kind of a type by using the :k command in GHCI.
Scala 2.10 didn’t have a :k
command, so I wrote kind.scala.
Thanks to George Leontiev (@folone) and others, :kind
command is now part of Scala 2.11 (scala/scala#2340). Let’s try using it:
scala> :k Int
scala.Int's kind is A
scala> :k -v Int
scala.Int's kind is A
*
This is a proper type.
Int
and every other types that you can make a value out of are called a proper type and denoted with a *
symbol (read “type”). This is analogous to the value 1
at value-level. Using Scala’s type variable notation this could be written as A
.
scala> :k -v Option
scala.Option's kind is F[+A]
* -(+)-> *
This is a type constructor: a 1st-order-kinded type.
scala> :k -v Either
scala.util.Either's kind is F[+A1,+A2]
* -(+)-> * -(+)-> *
This is a type constructor: a 1st-order-kinded type.
These are normally called type constructors. Another way of looking at it is that it’s one step removed from a proper type. So we can call it a first-order-kinded type. This is analogous to a first-order value (_: Int) + 3
, which we would normally call a function at the value level.
The curried notation uses arrows like * -> *
and * -> * -> *
. Note, Option[Int]
is *
; Option
is * -> *
. Using Scala’s type variable notation they could be written as F[+A]
and F[+A1,+A2]
.
scala> :k -v Eq
algebra.Eq's kind is F[A]
* -> *
This is a type constructor: a 1st-order-kinded type.
Scala encodes (or complects) the notion of typeclasses using type constructors.
When looking at this, think of it as Eq
is a typeclass for A
, a proper type.
This should make sense because you would pass Int
into Eq
.
scala> :k -v Functor
cats.Functor's kind is X[F[A]]
(* -> *) -> *
This is a type constructor that takes type constructor(s): a higher-kinded type.
Again, Scala encodes typeclasses using type constructors,
so when looking at this, think of it as Functor
is a typeclass for F[A]
, a type constructor.
This should also make sense because you would pass List
into Functor
.
In other words, this is a type constructor that accepts another type constructor.
This is analogous to a higher-order function, and thus called higher-kinded type.
These are denoted as (* -> *) -> *
. Using Scala’s type variable notation this could be written as X[F[A]]
.
The terminology around typeclasses tends to get jumbled up.
For example, the pair (Int, +)
forms a typeclass called monoid.
Colloquially, we say things like “is X a monoid?” to mean “can X form a monoid under some operation?”
An example of this is Either[A, B]
, which we implied “is-a” functor yesterday.
This is not completely accurate because, even though it might not be useful, we could have defined another left-biased functor.