这是>>=
:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
它需要一个函数作为第二个参数。
以下是return
的类型:
return :: Monad m => a -> m a
返回m a
这显然是类型检查:
(>>) :: Monad m => m a -> m b -> m b
x >> y = x >>= (\_ -> y)
但是为什么以下类型检查并与上面的代码类似?
(>>) :: Monad m => m a -> m b -> m b
x >> y = x >>= return y
此处return y
应该是m a
类型,而不是a -> m a
。那它为什么有用呢?
答案 0 :(得分:5)
你实际上在这里混合了两个不同的monad,这就是正在发生的事情。 x >>= return y
在这种情况下统一为
(>>) :: ∀ m a b . Monad m => m a -> m b -> m b
x >> y = x >>= (return :: m b -> a -> m b) y
-- aka return :: (m b) -> (a->) (m b)
在return
实例中实现Monad (a->)
:
instance Monad (->) a where
return x = \_ -> x
...
它与Monad m
实例没有任何关系。
至于为什么这个return
在函数monad中运行:return :: m b -> a -> m b
是在编译器开始推理类型类实例之前从环境中推断的。现在,类型m b -> a -> m b
,即m b -> (a->m b)
,格式为mb -> amb
。签名return :: Monad μ => α -> μ α
因此使编译器匹配μ α ~ amb ~ a->m b
。只有在这一点上,编译器才会真正选择return
的monad实例,并且通过观察a -> m b
确实具有μ α
形式,μ ~ (a->)
和{{α ~ m b
来实现这一点。 1}}。因此,它必须是(a->)
monad。
答案 1 :(得分:4)
有一个函数的monad实例,其return
为return x = \_ -> x
(或等效return = const
)。
因此,当您执行return y
预期函数时,它只会选择函数monad的return
。