繁体   English   中英

选项上的折叠关系是什么,是等等还是折叠在Traversable上?

[英]What's the relation of fold on Option, Either etc and fold on Traversable?

Scalaz为各种ADT提供了一个名为fold的方法,例如BooleanOption[_]Validation[_, _]Either[_, _]等。此方法基本上采用与给定ADT的所有可能情况相对应的函数。 换句话说,模式匹配如下所示:

x match {
  case Case1(a, b, c) => f(a, b, c)
  case Case2(a, b) => g(a, b)
  .
  .
  case CaseN => z
}

相当于:

x.fold(f, g, ..., z)

一些例子:

scala> (9 == 8).fold("foo", "bar")
res0: java.lang.String = bar

scala> 5.some.fold(2 *, 2)
res1: Int = 10

scala> 5.left[String].fold(2 +, "[" +)
res2: Any = 7

scala> 5.fail[String].fold(2 +, "[" +)
res6: Any = 7

同时, Traversable[_]类型有一个同名的操作,它遍历集合对其元素执行某些操作,并累积结果值。 例如,

scala> List(2, 90, 11).foldLeft("Contents: ")(_ + _.toString + " ")
res9: java.lang.String = "Contents: 2 90 11 "

scala> List(2, 90, 11).fold(0)(_ + _)
res10: Int = 103

scala> List(2, 90, 11).fold(1)(_ * _)
res11: Int = 1980

为什么这两个操作被识别出相同的名称 - fold / catamorphism? 我没有看到两者之间有任何相似之处/关系。 我错过了什么?

我认为你遇到的问题是你看到这些东西是基于它们的实现,而不是它们的类型。 考虑这种简单的类型表示:

List[A] = Nil 
        | Cons head: A tail: List[A]

Option[A] = None
          | Some el: A

现在,让我们考虑Option的折叠:

fold[B] = (noneCase: => B, someCase: A => B) => B

因此,在Option ,它将每个可能的情况减少到B某个值,并返回。 现在,让我们看一下List的相同内容:

fold[B] = (nilCase: => B, consCase: (A, List[A]) => B) => B

但请注意,我们在List[A]上有一个递归调用。 我们必须以某种方式折叠,但我们知道List[A]上的fold[B] List[A]将始终返回B ,因此我们可以像这样重写它:

fold[B] = (nilCase: => B, consCase: (A, B) => B) => B

换句话说,我们用B代替了List[A] ,因为折叠它将总是返回一个B ,给定fold的类型签名。 现在,让我们看看foldRight Scala(用例)类型签名:

foldRight[B](z: B)(f: (A, B) ⇒ B): B

说,这会让你想起什么吗?

如果你认为“折叠”是“通过一个操作使用种子值来压缩容器中的所有值”,并且你认为Option是一个最多只能有一个值的容器,那么这就开始有意义了。

实际上, foldLeft具有相同的签名,如果您在空列表中使用它与无,并且在仅包含一个元素的列表上, foldLeft给出完全相同的结果。

scala> val opt : Option[Int] = Some(10)
opt: Option[Int] = Some(10)

scala> val lst : List[Int] = List(10)
lst: List[Int] = List(10)

scala> opt.foldLeft(1)((a, b) => a + b)
res11: Int = 11

scala> lst.foldLeft(1)((a, b) => a + b)
res12: Int = 11

fold也在Scala标准库中的ListOption上定义,具有相同的签名(我相信它们都是从trait继承它,实际上)。 再一次,你在单身人士名单上获得与在某些人身上相同的结果:

scala> opt.fold(1)((a, b) => a * b)
res25: Int = 10

scala> lst.fold(1)((a, b) => a * b)
res26: Int = 10

我不是100%肯定Scalaz在Option / Either / etc上的fold ,你在那里提出了一个很好的观点。 它似乎与我习惯的“折叠”具有完全不同的签名和操作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM