首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Scala:编写foldLeft的常见实践

Scala:编写foldLeft的常见实践
EN

Stack Overflow用户
提问于 2017-02-24 17:55:09
回答 2查看 62关注 0票数 0

在函数式编程中,有两种重要的方法:foldLeftfoldRight。下面是foldRight的实现

代码语言:javascript
复制
sealed trait List[+A]
case object Nil extends List[Nothing]
case class Cons[+A](head: A, tails: List[A]) extends List[A]

 def foldRight[A, B](ls: List[A], z: B)(f: (A, B) => B): B = ls match {
    case Nil => z
    case Cons(x, xs) => f(x, foldRight(xs, z)(f))
  }

下面是foldLeft的实现

代码语言:javascript
复制
  @annotation.tailrec
  def foldLeft[A, B](ls: List[A], z: B)(f: (B, A) => B): B = ls match {
    case Nil => z
    case Cons(x, xs) => foldLeft(xs, f(z, x))(f)
  }
}

我的问题是:我从很多文献中读到,他们经常把f函数的顺序是:f: (B, A) => B而不是f: (A, B) => B。为什么这个定义更好?因为如果我们使用其他方式,它将具有与foldLeft相同的签名,并且它会更好。

EN

回答 2

Stack Overflow用户

发布于 2017-02-26 00:40:33

因为foldLeft在遍历过程中“改变”了cons结构:

代码语言:javascript
复制
foldRight(Cons(1, Cons(2, Nil)), z)(f) ~> f(1, f(2, z))
                                            ^  ^
                                            A  B
foldLeft(Cons(1, Cons(2, Nil)), z)(f) ~> f(f(z, 2), 1)
                                           ^        ^
                                           B        A

而且由于它以相反的顺序访问conses,所以类型也传统上是反转的。当然,参数可以互换,但如果你有一个非交换操作,并且期望“传统”行为,你会感到惊讶。

票数 3
EN

Stack Overflow用户

发布于 2017-02-26 15:47:51

...if我们使用其他方式,它将具有与foldLeft相同的签名,并且它会更好。

不,我认为那不会更好。如果它们具有相同的签名,那么如果您打算使用一个签名,但无意中输入了另一个签名,则编译器将无法捕获它。

A/B顺序也很方便地提醒了B (初始或“零”)值与A元素集合的关系。

代码语言:javascript
复制
foldLeft: B-->>A, A, A, ...   // (f: (B, A) => B)
foldRight: ... A, A, A<<--B   // (f: (A, B) => B)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42435562

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档