【发布时间】:2017-05-22 15:52:52
【问题描述】:
我对 Haskell 中绑定函数(>>=) 的定义有一些疑问。
因为 Haskell 是纯语言,所以我们可以使用 Monad 来处理有副作用的操作。我认为这个策略有点像把所有可能对另一个世界造成副作用的行为,我们可以通过do 或>>=,从我们的“纯”haskell 世界控制它们。
所以当我查看>>=函数的定义时
(>>=) :: Monad m => m a -> (a -> m b) -> m b
它需要一个(a -> m b) 函数,因此前一个操作的结果m a 可以“解包”到>>= 中的非单子a。然后函数(a -> m b) 将a 作为其输入并返回另一个单子m b 作为其结果。通过绑定函数,我可以在不给纯 Haskell 代码带来任何副作用的情况下对 monadic 进行操作。
我的问题是为什么我们使用(a -> m b) 函数?在我看来,m a -> m b 函数也可以做到这一点。是有什么原因,还是只是因为它是这样设计的?
编辑
从 cmets 我了解到很难从 m a 中提取 a。但是,我认为我可以将一元 m a 视为具有副作用的 a。
是否可以假设函数m a -> m b 与a -> b 行为相似,所以我们可以像定义a -> b 一样定义m a -> m b?
【问题讨论】:
-
m a -> m b函数无法做到这一点,因为没有通用方法可以从m a中提取a,IO是最常见的示例。 -
如果是
m a -> m b,那么我们总是可以让x >>= f = f x为任何m。这不会很有趣:它不会实现>>=的“临时拆箱”,因为f不会传递“拆箱值”。 -
OK 尝试在不使用
>>=的情况下定义IO Int -> IO String类型的函数。 -
@calvin -
Monad对Applicative的额外能力是能够检查内部值a以选择结果值m b。如果(>>=)采用函数m a -> m b,那么您需要一个函数m a -> a才能检查a来决定返回哪个值m b。但是 monad 不支持这样的功能。由于 monad 是函子,它们已经支持将a -> b提升到m a -> m b和fmap。 -
@Lee 如果
(>>=)采用函数m a -> m b,那么它将被称为(.)。