什么是 scalaz filterM 方法?

what is the scalaz filterM method?

这个scalaz tutorial提供了使用filterM方法的例子,但是没有解释

List(1, 2, 3) filterM { x => List(true, false) }
res19: List[List[Int]] = List(List(1, 2, 3), List(1, 2), List(1, 3), List(1), List(2, 3), List(2), List(3), List())

我看到我可以向它传递一个任意大小的布尔列表。这个 filterM 方法是什么?

此外,是否有 book/tutorial scalaz 的更多解释?

根据实现,需要传递函数A => F[Boolean],比如F: ApplicativefilterM 遍历列表,过滤元素,为其传递谓词(返回 F[true] ),最后将此 List 放入 F.

更简单一点的例子:

List(1, 2, 3).filterM[Option](_.some.map(_ % 2 == 0)) // Some(List(2))

请注意,这为您提供了额外的自由度,不仅可以考虑 truefalse,还可以考虑 None。你可以尝试不同的Applicatives来掌握这个概念。

在您输入的示例中,List 也是 Applicative。那么,会发生什么(因为它是递归的,所以从最后开始更容易):
1) 当你在列表的末尾时 - 你只会得到一个空列表
2) 你有一个列表 3 :: Nil。将谓词应用于 3 会得到 List(true, false)。因此,您正在使用整个 List(3) 和尾部 List().
3) 接下来是 22 -> true :: false 映射到 head :: head :: tailList(2) :: List(2, 3)。将它附加到您之前拥有的内容,您将得到 List(List(2, 3), List(2), List(3), List())
4)现在是最后一步,你得到一个。与将 1 添加到 true 的每个列表并将其余部分用于 false.

的方式相同
List(List(1, 2, 3), List(1, 2), List(1, 3), List(1), List(2, 3), List(2), List(3), List())

我添加了一些日志记录,以弄清楚发生了什么:

current list: List(1, 2, 3)
current list: List(2, 3)
current list: List(3)
current list: List()
filtered value: List(List())
taking head and tail :   List(3)
taking tail: List()
filtered value: List(List(3), List())
taking head and tail :   List(2, 3)
taking head and tail :   List(2)
taking tail: List(3)
taking tail: List()
filtered value: List(List(2, 3), List(2), List(3), List())
taking head and tail :   List(1, 2, 3)
taking head and tail :   List(1, 2)
taking head and tail :   List(1, 3)
taking head and tail :   List(1)
taking tail: List(2, 3)
taking tail: List(2)
taking tail: List(3)
taking tail: List()
List(List(1, 2, 3), List(1, 2), List(1, 3), List(1), List(2, 3), List(2), List(3), List())

我不完全确定发生了什么,但结果是事实 table。似乎 filterM 只是组合了两个 applicatives,其中一个是 applicative of Boolean 所以基本上结果是对导致 true.[=15= 的每个组合的应用]

1,2,3   (true, true ,true)
1,2     (true, true, false)
2,3     (false, true, true)
1,3     (true, false, true)
1       (true, false, false)
2       (false, true, false)
3       (false, false, true)
()      (false, false, false)

这是一个很老的问题。我只是回答以防万一其他人想知道。

你可以从Learn You a Haskell for Good!中找到一个很好的解释。在我引用的 link 中搜索 filterM。

在书中,它说了以下内容(你可以辨认出 haskell 语法):

The filter function is pretty much the bread of Haskell programming (map being the butter). It takes a predicate and a list to filter out and then returns a new list where only the elements that satisfy the predicate are kept. Its type is this:

filter :: (a -> Bool) -> [a] -> [a]

The predicate takes an element of the list and returns a Bool value. Now, what if the Bool value that it returned was actually a monadic value? Whoa! That is, what if it came with a context? Could that work? For instance, what if every True or a False value that the predicate produced also had an accompanying monoid value, like ["Accepted the number 5"] or ["3 is too small"]? That sounds like it could work. If that were the case, we'd expect the resulting list to also come with a log of all the log values that were produced along the way. So if the Bool that the predicate returned came with a context, we'd expect the final resulting list to have some context attached as well, otherwise the context that each Bool came with would be lost.

filterM :: (Monad m) => (a -> m Bool) -> [a] -> m [a]

The predicate returns a monadic value whose result is a Bool, but because it's a monadic value, its context can be anything from a possible failure to non-determinism and more! To ensure that the context is reflected in the final result, the result is also a monadic value.

作为参考的好书,我会阅读以下Scalaz作为简要教程:Learning Scalaz。如果您需要更深入的解释,我会回去给您学习一本 haskell 书。

我仍然不明白 filterM 在 Scalaz 示例中的作用。从 Haskell 书中的解释来看,这是完全有道理的。

编辑:澄清了不合理之处。