【问题标题】:Readable FoldRight via FoldLeft in Scala通过 Scala 中的 FoldLeft 可读的 FoldRight
【发布时间】:2019-03-10 06:12:05
【问题描述】:

Functional Programming in Scala,作者要求通过FoldLeft 表达FoldRight。然后作者提供以下implementation

  def foldRightViaFoldLeftAuthor[A, B](l: List[A], z: B)(f: (A, B) => B): B = {
    foldLeft(l, (b: B) => b)((g, a) => b => g(f(a, b)))(z)
  }

有几个问题,例如this,要求解释作者的解决方案。可能很多人还在努力理解它。

当我在思考这个任务时,我想出了一个不同的实现,至少对我来说,它似乎更具可读性和更容易掌握

  def foldRightViaFoldLeftMy[A, B](l: List[A], z: B)(f: (A, B) => B): B = {
    foldLeft(l, z)(((g: (A, B) => B) => (b: B, a: A) => g(a, b)) (f))
  }

所以我基本上准备了一个将f(a,b) 转换为f(b,a) 的函数,现在我可以调用尾递归的foldLeft

所以我的问题是:

  1. 有什么理由按照作者的方式实现吗?
  2. 与作者的相比,我的实现有什么缺点吗?

【问题讨论】:

    标签: scala functional-dependencies


    【解决方案1】:

    您已经编写了一个与foldRight 具有相同签名的实现,但是当组合操作不可交换时,它没有正确的语义。举个例子,以空列表为0,以cons为组合操作的右折叠应该是identity:

    scala> val input = List(1, 2, 3)
    input: List[Int] = List(1, 2, 3)
    
    scala> val f: (Int, List[Int]) => List[Int] = _ :: _
    f: (Int, List[Int]) => List[Int] = $$Lambda$1912/991363637@5e9bf744
    
    scala> foldRightViaFoldLeftAuthor(input, List.empty[Int])(f)
    res0: List[Int] = List(1, 2, 3)
    

    但是你的实现颠倒了列表:

    scala> foldRightViaFoldLeftMy(input, List.empty[Int])(f)
    res1: List[Int] = List(3, 2, 1)
    

    这是因为您仍然从左到右折叠,即使您已经切换了组合函数参数的顺序。我发现the Wikipedia page about fold 上的图表对于可视化差异很有用。在您的实现中,应用程序是这样发生的:

    scala> f(3, f(2, f(1, Nil)))
    res2: List[Int] = List(3, 2, 1)
    

    在本书的实现中,你有这样的东西:

    ((b3: List[Int]) =>
      ((b2: List[Int]) =>
        ((b1: List[Int]) => identity(f(1, b1)))(f(2, b2)))(f(3, b3)
      )
    )(Nil)
    

    归结为:

    scala> f(1, f(2, f(3, Nil)))
    res3: List[Int] = List(1, 2, 3)
    

    所以你的两个问题的答案都是“是”,你的实现和本书的实现之间有一个重要的区别。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-12
      • 1970-01-01
      • 2017-11-04
      • 1970-01-01
      • 1970-01-01
      • 2011-09-09
      • 2017-03-25
      • 1970-01-01
      相关资源
      最近更新 更多