【问题标题】:Corecursion vs Recursion understanding in scalascala中的Corecursion与递归理解
【发布时间】:2015-12-05 10:34:13
【问题描述】:

如果递归几乎清晰,例如

 def product2(ints: List[Int]): Int = {
      @tailrec
      def productAccumulator(ints: List[Int], accum: Int): Int = {
          ints match {
              case Nil => accum
              case x :: tail => productAccumulator(tail, accum * x)
          }
      }
      productAccumulator(ints, 1)
  }

我不确定核心游程。根据Wikipedia article,“corecursion 允许程序生成任意复杂且可能无限的数据结构,例如流”。例如这样的构造

list.filter(...).map(...)

使得在filtermap 操作之后准备临时流成为可能。 在filter 流之后将只收集过滤后的元素,然后在map 中我们将更改元素。正确的?

函数组合器是否对map filter 使用递归执行 有没有人在 Scala 中有很好的例子“比较递归和核心递归”?

【问题讨论】:

  • 根据wiki定义,你的product例子 corecursion。 product 递归看起来像 def product(ints: List[Int]): Int = ints match { case Nil => 1 case x :: xs => x * product(xs) }
  • 不——这里的例子不是 corecursion——它是一个用递归实现的折叠的特例。 - 在 Java-world 中,带有 corecursion 的东西例如是 Iterable<..>
  • 你的意思是 foldLeft 或 foldRight 是 corecursion 吗?

标签: scala function recursion functional-programming


【解决方案1】:

理解差异的最简单方法是认为递归消耗数据,而核心递归产生数据。您的示例是递归,因为它使用您作为参数提供的列表。此外,foldLeftfoldRight 也是递归,而不是核心递归。现在是 corecursion 的一个例子。考虑以下函数:

def unfold[A, S](z: S)(f: S => Option[(A, S)]): Stream[A]

只需查看其签名,您就可以看到此函数旨在生成无限的数据流。它采用S 类型的初始状态z,以及从S 到一个可能的元组的函数,该元组将包含流的下一个状态和实际值,即A 类型。如果f 的结果为空(None),则unfold 停止生成元素,否则继续传递下一个状态,依此类推。这是它的实现:

def unfold[S, A](z: S)(f: S => Option[(A, S)]): Stream[A] = f(z) match {
  case Some((a, s)) => a #:: unfold(s)(f)
  case None => Stream.empty[A]
}

您可以使用此功能来实现其他生产功能。例如。下面的函数将产生最多numOfValues 类型的A 元素流:

def elements[A](element: A, numOfValues: Int): Stream[A] = unfold(numOfValues) { x =>
  if (x > 0) Some((element, x - 1)) else None
}

REPL 中的使用示例:

scala> elements("hello", 3)
res10: Stream[String] = Stream(hello, ?)

scala> res10.toList
res11: List[String] = List(hello, hello, hello)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-07
    • 1970-01-01
    • 1970-01-01
    • 2018-12-15
    • 1970-01-01
    • 2012-07-26
    相关资源
    最近更新 更多