5

递归很酷,但是当您被高阶库函数包围时,它有点低级。我试图避免为依赖于生成的最后一个值的进程编写递归函数。

我通常会iterate在 Clojure 中使用函数,而不是最后一个值和当前参数的“压缩”列表。Scala 的集合 API 中是否有等效功能?

这是一些疯狂的伪代码中的抽象示例的尝试:

说你有

  • 输入列表:Seq(1,2,3)
  • 您对生成的最后一个值和列表中的下一项执行的一些操作:

    lastValue ^ 2 + nextInt(i)

并且您想要累积所有生成的值。

我试图避免写类似的东西:

def f(ls:Seq[Int]):Seq[Float] = {

  def g(pos:Int, lastGen:Float):Seq[Float] = { 
    val v = gen(lastGen, ls(pos))
    if( end(v) )
      Seq(v)
    else
      Seq(v) ++ g(pos+1, v)
  }

  f(0, 1)
}

我在 Haskell 中定义了 Fibonacci 的惰性流版本时看到了类似的东西,所以假设我可以使用引用自身的惰性流,但这比 Clojure 的迭代更难让我的大脑环绕。

4

3 回答 3

6

这是你要找的吗?iterate它与Clojure 中的基本相同:

List.iterate(1, 5) { _ + 1 }
// res1: List[Int] = List(1, 2, 3, 4, 5)

我认为iteratefor的定义List来自GenTraversableFactory.

唯一的缺点是第二个参数是您想要的参数数量,因此它不会像Clojurelen中那样返回无限序列。iterate

更新:

刚学到新东西!该Stream对象也有一个iterate方法,这使您可以创建无限的惰性流:

(Stream.iterate(1) { _ * 2 } take 5).toList
// res1: List[Int] = List(1, 2, 4, 8, 16)
于 2012-08-23T03:54:05.267 回答
3

您显示的代码基本上相当于:

ls.foldLeft(List(1.0))((a, b) => gen(a.head, b) :: a).reverse
于 2012-08-23T04:04:18.153 回答
0

听起来你想要的高阶函数是scanLeft,它就像一个记住其中间步骤的折叠。例如,假设您有以下内容:

val ls = Seq(1, 2, 3)
def gen(lastValue: Double, n: Int) = math.pow(lastValue, 2) + n

然后你可以像这样将它们与scanLeft

scala> ls.scanLeft(1.0)(gen)
res0: Seq[Double] = List(1.0, 2.0, 6.0, 39.0)

这或多或少等同于 Apocalisp 的公式 with foldLeft,只是它scanLeft会为您保留中间值。

于 2012-08-23T12:16:07.587 回答