所以此时您肯定听说过currying 或部分应用程序:如果您有f :: a -> b -> c 和x :: a,那么f x :: b -> c。即,如果f 是一个双参数函数并且x 具有f 的第一个参数的类型,那么f x 是一个接受第二个参数并“完成”应用程序的函数。
嗯,在 Haskell 中,同样的事情也适用于像 State 这样的类型构造函数。类型和类型构造函数有一个 kind,这类似于值如何具有类型。像Integer 这样的非参数类型有一种*;像Maybe 这样的单参数类型有一种* -> *; State 有种* -> * -> *。
然后,State state 是State 类型构造函数的部分应用,并且具有类型* -> *。 Monad 是一个适用于* -> * 的类。因此,应用于我们的示例:
-
instance Monad (Integer) where ... 是被禁止的,因为 Integer 有一种 *。
-
instance Monad (Maybe) where ... 是允许的,因为 Maybe 有一种 * -> *。
-
instance Monad (State) where ... 是被禁止的,因为State 有一种* -> * -> *。
-
instance Monad (State st) where ... 是允许的,因为 State st 有一种 * -> *。
我们怎么知道Monad 适用于* -> * 的类型?我们可以从类声明中推断出来:
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
-- ...
看看m在这个类声明中是如何使用的:作为m a和m b的一部分,即作为一个参数。因此,Haskell 推断 m 是一种类型变量 * -> *。
比较一下:
class Num a where
(+) :: a -> a -> a
(-) :: a -> a -> a
-- ...
这里的类型变量a 不应用于其他类型变量——因此它必须是一种*。
所以严格来说,State 不是单子;它是一个两位类型的构造函数,当部分应用于仅一种类型时,它会为您提供一个 monad。所以State state 是一个 monad,State Integer、State [a] 等也是如此。人们确实经常说话松散并谈论 State 和类似 monad 的东西,但是你应该明白它是一个 参数化 monad——它是一个具有内部类型参数的 monad,因此该参数的类型有许多不同的变体。