在scala中clojure迭代等效?

时间:2012-08-23 03:41:03

标签: scala clojure

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

我通常会在Clojure中使用iterate函数而不是最后一个值和当前参数的“压缩”列表。 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的迭代更难包裹我的大脑。

3 个答案:

答案 0 :(得分:6)

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

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

我认为iterate List的定义来自GenTraversableFactory

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

更新

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

(Stream.iterate(1) { _ * 2 } take 5).toList
// res1: List[Int] = List(1, 2, 4, 8, 16)

答案 1 :(得分:3)

您展示的代码基本上等同于:

ls.foldLeft(List(1.0))((a, b) => gen(a.head, b) :: a).reverse

答案 2 :(得分: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使用foldLeft的公式,除了scanLeft负责保留中间值。