理解 `Random` 的 `Kind`

Understanding `Kind` of `Random`

Maybe,据我所知是 type constructor,种类 * -> *。据我了解,它需要一个类型才能产生一个类型。

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

但是,下面的输出是什么意思?

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

Haskell 中有一些种类。具体类型具有种类 *,这意味着它已被完全应用,因此类型如 Int[String]IO (Maybe Int)。然后是采用 * -> k 形式的种类,其中 k 是种类变量。这些就像 Haskell 中接受 1 个或多个参数的函数,除了 * 必须 是具体类型,它不是变量。例如

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

然后是Constraint种,它是由一个或多个1个其他种类构成的:

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

最后一个有点复杂,但可以把它想象成一个高阶函数,其中 (* -> *) 意味着第二个参数必须是一个类型构造函数,它还剩下一个类型参数。

Random 只是一个简单的类型类,因此它采用完全应用的类型并生成 Constraint.

还有原始类型 #,原始类型的值并融入 GHC,它们甚至需要语言扩展来解析它们的名称:

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

大多数 Haskell 程序员永远不需要使用这些,但如果您需要为 GHC API.

进行低级编程,它们是可用的

通过一些扩展,您甚至可以自己制作类型

> :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

种类为我们提供了一种类型级编程形式,可以使用它们来构建漂亮的 APIs。

可以使用很多技巧

1. Not necessarily true