我发现Monad Option
直观易懂,而List
则不是。
Some(1) >>= { x=>Some(x+1)}
Ma -> a -> Mb -> Mb
如果我从 Some(1) 中提取值,我知道它是 1
但在列表情况下
List(3,4,5) flatMap { x=> List(x,-x) }
如果我从列表中提取值,我能得到什么? 如何使理解过程直观
Option
或Maybe
背后的直觉实际上与List
monad非常相似。主要区别在于List
是不确定的 - 我们不知道我们可以得到多少值,而Option
它总是成功时为一,失败时为零。空列表被视为失败。
我认为这篇文章很好地描述了它:
对于列表,一元绑定涉及将一组 计算列表中的每个值。与列表一起使用时, >>= 的签名变为:
(>>=) :: [a] -> (a -> [b]) -> [b]
也就是说,给定一个 a 列表和一个将 a 映射到列表的函数 对于 B,绑定将此函数应用于输入中的每个 A 并返回所有生成的 b 连接成一个列表。
列表实现的示例:
instance Monad [] where
return x = [x]
xs >>= f = concat (map f xs)
fail _ = []
很抱歉把Haskell放进Scala的答案中,但这是我用来理解这些东西的资源。
斯卡拉的flatMap
并不完全是哈斯克尔的绑定>>=
,但非常接近它。那么这一切意味着什么呢?
想象一下,您有一个List[Client]
客户端列表的实际情况,您可以将它们绑定到单个订单列表List[Order]
该订单将自动为您展平flatMap
或>>=
。如果您改用map
,则会得到一个List[List[Order]]
。在实践中,您将提供供>>=
使用的函数,类似地,您将如何向fold
提供函数 - 您决定如何生成/聚合/等数据。bind 为您所做的是提供组合两个 monadic 值的一般模式,并且每种类型的 monads 实现都是唯一的。
您可能更愿意将其视为多个抽象级别(从更一般到更少):
Monad 具有绑定操作,可将两个 monadic 值合并为一个:
(>>=) :: m a -> (a -> m b) -> m b
。List
作为 monad 实例实现绑定,如下所示:xs >>= f = concat (map f xs)
- 将函数映射到所有元素上并将结果连接到单个列表中。您可以根据需要为绑定函数提供函数
f
的实现(客户端 -> 订单示例)。
一旦你知道了 bind 在 monad 实例(List
、Option
)上的行为,你就可以考虑只使用它,而"忘记"实际的实现。