解释scalaz seven中的遍历[List]实现

解释scalaz seven中的遍历[List]实现,scala,typeclass,traversal,scalaz,applicative,Scala,Typeclass,Traversal,Scalaz,Applicative,我试图理解以下内容中的traverseImpl实现: 有人能解释一下列表如何与应用程序交互吗?最后,我希望能够为遍历实现其他实例,这并不是那么容易掌握的。我建议你阅读本书开头的文章 在悉尼的最后一次函数式编程会议上,我也做了一个关于这个主题的演示,你可以找到幻灯片 如果我能用几句话解释一下,travel将逐个遍历列表中的每个元素,最终重新构建列表(::),但积累/执行应用程序所给出的某种“效果”。如果F是State它会跟踪某些状态。如果F是与Monoid对应的应用程序,那么它会为列表中的每个元素

我试图理解以下内容中的
traverseImpl
实现:


有人能解释一下
列表如何与
应用程序交互吗?最后,我希望能够为
遍历
实现其他实例,这并不是那么容易掌握的。我建议你阅读本书开头的文章

在悉尼的最后一次函数式编程会议上,我也做了一个关于这个主题的演示,你可以找到幻灯片

如果我能用几句话解释一下,
travel
将逐个遍历列表中的每个元素,最终重新构建列表
(::)
,但积累/执行
应用程序所给出的某种“效果”。如果
F
State
它会跟踪某些状态。如果
F
是与
Monoid
对应的应用程序,那么它会为列表中的每个元素聚合某种度量

列表和应用程序的主要交互是与
map2
应用程序的交互,其中它接收
F[B]
元素并将其附加到另一个
F[list[B]]
元素定义为
F
应用程序
,并使用
列表
构造函数
作为要应用的特定函数


从这里可以看出,实现
遍历
的其他实例只是关于
应用
遍历要遍历的数据结构的数据构造函数。如果您查看链接的powerpoint演示文稿,您将看到一些带有二叉树遍历的幻灯片。

应用程序允许您将上下文中的函数应用于上下文中的值。例如,您可以将
some((i:Int)=>i+1)
应用于
some(3)
并获得
some(4)
。让我们暂时忘记这一点。我稍后再谈这个问题

列表有两种表示形式,要么是
Nil
要么是
head::tail
。您可以使用
foldLeft
将其折叠起来,但还有另一种折叠方法:

def foldr[A, B](l: List[A], acc0: B, f: (A, B) => B): B = l match {
   case Nil => acc0
   case x :: xs => f(x, foldr(xs, acc0, f))
}
给定
List(1,2)
我们从右侧开始应用函数折叠列表-即使我们真的从左侧解构列表

f(1, f(2, Nil))
这可以用来计算列表的长度。给定
列表(1,2)

这也可用于创建另一个列表:

foldr[Int, List[Int]](List(1, 2), List[Int](), _ :: _)
//List[Int] = List(1, 2)
因此,给定一个空列表和
函数,我们可以创建另一个列表。如果我们的元素在某些上下文中呢?如果我们的上下文是应用程序,那么我们仍然可以在该上下文中应用元素和
。继续使用
列表(1,2)
选项作为我们的应用程序。我们从
some(List[Int]())
开始,我们想在
选项中应用
函数。这就是
F.map2
的作用。它在其
选项
上下文中获取两个值,将提供的两个参数的函数放入
选项
上下文中,并将它们一起应用

因此,在上下文之外,我们有
(2,Nil)=>2::Nil

在上下文中,我们有:
(一些(2),一些(Nil))=>一些(2::Nil)

回到原来的问题:

// do a foldr 
DList.fromList(l).foldr(F.point(List[B]())) {
  // starting with an empty list in its applicative context F.point(List[B]())
  (a, fbs) => F.map2(f(a), fbs)(_ :: _)
  // Apply the `::` function to the two values in the context
}
我不确定为什么要使用差异
DList
。我所看到的是,它使用了蹦床,所以很有希望使这个实现在不破坏堆栈的情况下工作,但我没有尝试过,所以我不知道

像这样实现右折叠的有趣之处在于,我认为它为您提供了一种使用

例如:

trait Tree[+A]
object Leaf extends Tree[Nothing]
case class Node[A](a: A, left: Tree[A], right: Tree[A]) extends Tree[A]
Fold的定义如下(实际上遵循与
列表
相同的方法):

traverse将使用
折叠
F.point(Leaf)
并将其应用于
节点。虽然没有
F.map3
,但它可能有点麻烦。

List#foldRight
为大型列表扫清了障碍。在REPL中尝试以下操作:

List.range(0, 10000).foldRight(())((a, b) => ())
通常,您可以反转列表,使用
foldLeft
,然后反转结果以避免此问题。但是使用
遍历
时,我们必须按照正确的顺序处理元素,以确保正确处理效果<代码>数据列表
是一种方便的方法,借助蹦床

最终,这些测试必须通过:

https://github.com/scalaz/scalaz/blob/scalaz-seven/tests/src/test/scala/scalaz/std/ListTest.scala#L11

的确,你的博客文章和幻灯片都很有帮助!很棒的幻灯片!你能把它做成pdf格式吗?我在字体和对齐方面遇到了一些恼人的问题。我在这里上传了pdf幻灯片:很棒的答案,不需要任何外部知识
trait Tree[+A]
object Leaf extends Tree[Nothing]
case class Node[A](a: A, left: Tree[A], right: Tree[A]) extends Tree[A]
def fold[A, B](tree: Tree[A], valueForLeaf: B, functionForNode: (A, B, B) => B): B = {
  tree match {
    case Leaf => valueForLeaf
    case Node(a, left, right) => functionForNode(a, 
        fold(left, valueForLeaf, functionForNode), 
        fold(right, valueForLeaf, functionForNode)
      )
  }
}
List.range(0, 10000).foldRight(())((a, b) => ())