看看这个例子:
ReaderT Integer (ErrorT String (StateT Integer Identity)) Integer
这里将使用哪个运算符绑定(>>=)
?
例如,如果我们使用do
表示法,那么编译器将选择哪个绑定运算符?
答案 0 :(得分:5)
作为参考,(>>=)
的类型为
(>>=) :: Monad m => m a -> (a -> m b) -> m b
并注意到
ReaderT Integer (ErrorT String (StateT Integer Identity)) Integer
与
相同(ReaderT Integer (ErrorT String (StateT Integer Identity))) Integer
因为类型应用程序(如函数应用程序)在Haskell中保持关联。
所以,给定
x :: ReaderT Integer (ErrorT String (StateT Integer Identity)) Integer
和表达式
中具有适当类型的f
x >>= f
类型检查器将尝试将x
的类型与左参数类型(>>=)
匹配。这意味着它会尝试将ReaderT Integer (ErrorT String (StateT Integer Identity)) Integer
与m a
统一起来。这种统一的唯一方法是将a
设为Integer
,将m
设为ReaderT Integer (ErrorT String (StateT Integer Identity))
。因此,使用~
类型等式表示法,我们最终得到
m ~ (ReaderT Integer (ErrorT String (StateT Integer Identity)))
a ~ Integer
因此,它必须使用(ReaderT r n)
的{{1}}实例,Monad
和r ~ Integer
。
这是类型统一在Haskell中的工作原理的结果,而不仅仅是n ~ ErrorT String (StateT Integer Identity)
,所以这个一般的想法可以用来解释其他多态函数的类型检查是如何工作的。