在 Haskell 的绑定运算符 (>>=) 中使用 return
Using return in Haskell's bind operator (>>=)
这是>>=
的类型:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
它需要一个函数作为第二个参数。
这里是 return
的类型:
return :: Monad m => a -> m a
Returns 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
。那么它为什么有效?
函数有一个 monad 实例,它的 return
是 return x = \_ -> x
(或等效的 return = const
)。
因此,当您在需要函数的地方执行 return y
时,它只是选择函数 monad 的 return
。
你实际上在这里混合了两个不同的单子,这就是正在发生的事情。 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
。因此,它必须是 (a->)
monad。
这是>>=
的类型:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
它需要一个函数作为第二个参数。
这里是 return
的类型:
return :: Monad m => a -> m a
Returns 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
。那么它为什么有效?
函数有一个 monad 实例,它的 return
是 return x = \_ -> x
(或等效的 return = const
)。
因此,当您在需要函数的地方执行 return y
时,它只是选择函数 monad 的 return
。
你实际上在这里混合了两个不同的单子,这就是正在发生的事情。 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
。因此,它必须是 (a->)
monad。