列表上的 monad 绑定操作不直观



我发现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) }

如果我从列表中提取值,我能得到什么? 如何使理解过程直观

OptionMaybe背后的直觉实际上与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 实现都是唯一的。

您可能更愿意将其视为多个抽象级别(从更一般到更少):

  1. Monad 具有绑定操作,可将两个 monadic 值合并为一个:(>>=) :: m a -> (a -> m b) -> m b

  2. List 作为 monad 实例实现绑定,如下所示: xs >>= f = concat (map f xs) - 将函数映射到所有元素上并将结果连接到单个列表中。

  3. 您可以根据需要为绑定函数提供函数f的实现(客户端 -> 订单示例)。

一旦你知道了 bind 在 monad 实例(ListOption)上的行为,你就可以考虑只使用它,而"忘记"实际的实现。

最新更新