Kevin Meredith
Kevin Meredith

Reputation: 41919

Understanding `Kind` of `Random`

Maybe, which I understand to be a type constructor, has kind * -> *. As I understand, it needs a type in order to produce a type.

ghci> :k Maybe
Maybe :: * -> *
ghci> :k Maybe Int
Maybe Int :: *

However, what does the following output mean?

ghci> :k Random
Random :: * -> Constraint

Upvotes: 2

Views: 80

Answers (1)

bheklilr
bheklilr

Reputation: 54068

There are a handful of kinds in Haskell. A concrete type has kind *, this means that it is fully applied, so types like Int, [String], IO (Maybe Int). Then there are kinds that take the form * -> k, where k is a kind variable. These are just like functions in Haskell that take 1 or more arguments, except * has to be a concrete type, it isn't variable. Examples would be

> :kind Maybe
Maybe :: * -> *
> :kind Either
Either :: * -> * -> *
> data Foo a b c d e = Foo
> :kind Foo
Foo :: * -> * -> * -> * -> * -> *

Then there is the kind Constraint, which is constructed with one or more1 other kinds:

> :kind Num
Num :: * -> Constraint
> :kind Show
Show :: * -> Constraint
> import Control.Monad.State
> :kind MonadState
MonadState :: * -> (* -> *) -> Constriant

The last one is a bit more complex, but think of it like a higher order function, where (* -> *) means that the second argument must be a type constructor that has one type argument left.

Random is just a simple typeclass, so it takes a fully applied type and produces a Constraint.

There is also the primitive kind #, values of types that are primitive and baked in to GHC, they even require a language extension just to parse their names:

> import GHC.Prim
> :set -XMagicHash
> :i Int#
data Int#
> :k Int#
Int# :: #

Most Haskell programmers won't ever need to use these, but they're available if you need to do low level programming for the GHC API.

With a couple extensions, you can even make kinds yourself

> :set -XDataKinds
> :set -XKindSignatures
> :set -XGADTs
> -- Multiline input in GHCi
> :set +m
> data FlagType = Flag1 | Flag2 deriving (Show)
> data Foo :: FlagType -> * -> *
|     F1 :: Int -> Foo 'Flag1 Int
|     F2 :: String -> Foo 'Flag2 String
|
> :t F1 1
F1 1 :: Foo 'Flag1 Int
> :t F2 "foo"
F2 "foo" :: Foo 'Flag2 String

Kinds give us a form of type level programming, there are lots of tricks that can be done with them to build nice APIs.

1. Not necessarily true

Upvotes: 7

Related Questions