如果我检查我kind
得到Maybe
这个:
λ> :k Maybe
Maybe :: * -> *
Monad
现在,如果我检查我得到的那种:
λ> :k Monad
Monad :: (* -> *) -> Constraint
那里有什么Constraint
以及为什么需要它?为什么不只是这个* -> *
?
如果我检查我kind
得到Maybe
这个:
λ> :k Maybe
Maybe :: * -> *
Monad
现在,如果我检查我得到的那种:
λ> :k Monad
Monad :: (* -> *) -> Constraint
那里有什么Constraint
以及为什么需要它?为什么不只是这个* -> *
?
不像Maybe
,Monad
不是类型;它是一个类型类。
其他类型类也是如此:
Num :: * -> Constraint
Functor :: (* -> *) -> Constraint
Bifunctor :: (* -> * -> *) -> Constraint
where*
表示具体类型(如Bool
or Int
),->
表示更高种类的类型(如Maybe
),并Constraint
表示类型约束的思想。这就是为什么:
正如我们所知,我们不能做这样的签名:
return :: a -> Monad a -- This is nonsense!
因为Monad
应该用作约束,也就是说,'这必须是一个单子才能工作':
return :: (Monad m) => a -> m a
我们这样做是因为我们知道它return
不能在任何旧类型上工作m
,所以我们return
在名称下定义了不同类型的行为Monad
。换句话说,没有单一的东西可以称为 Monad,而只有行为可以称为 Monadic。
出于这个原因,我们创建了这个类型约束,说我们必须预先定义一些东西作为 Monad 才能使用这个函数。这就是为什么那种Monad
是(* -> *) -> Constraint
——它本身不是一种类型!
Maybe
是 的一个实例Monad
。这意味着在某个地方,有人写道:
instance Monad Maybe where
(>>=) = ... -- etc
...并定义了Maybe
应如何表现为 Monad。这就是为什么我们可以使用Maybe
带有前缀约束的函数或类型Monad m => ...
。这本质上是定义由 应用的约束的地方Monad
。
Constraint
Show Int
是, Monad Maybe
, 和的种类Monoid [a]
。=>
粗略地说,它是类型注释左侧可能出现的所有内容。
现在自从
Show Int :: Constraint
并且Int
是一种类型,即
Int :: *
我们可以将功能类型分配给Show
如下
Show :: * -> Constraint
^-- the result kind
^-- the kind of Int
在你的情况下,它只是发生了一个Monad
像这样的参数Maybe
,所以
Maybe Int :: *
Maybe :: * -> *
Monad :: (* -> *) -> Constraint
^-- the result kind
^-- the kind of Maybe