我理解为Maybetype 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,它是用一种或多种其他种类构造的:

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


实物为我们提供了一种类型级别的编程形式,可以使用许多技巧来构建漂亮的API。

1. Not necessarily true

10-07 21:00