Scala lazy val解释

时间:2014-11-07 08:19:07

标签: scala lazy-evaluation

我正在使用Coursera的Scala课程中的函数式编程,我很难理解这段代码片段 -

def sqrtStream(x: Double): Stream[Double] = {
  def improve(guess: Double): Double = (guess+ x/ guess) / 2
  lazy val guesses: Stream[Double] = 1 #:: (guesses map improve)
  guesses
}

当我做sqrtSteam(4).take(10).toList时,这个方法会以递增的精度顺序找到10个近似的4的平方根。

有人可以在这里解释猜测的评估策略吗?我怀疑当猜测的第二个价值被提升时,猜测的价值取代了什么?

3 个答案:

答案 0 :(得分:3)

让我们从简化的例子开始:

 scala> lazy val a: Int  = a + 5
 a: Int = <lazy>

 scala> a
 stack overflow here, because of infinite recursion

所以a重新计算,直到它得到一些稳定的值,就像这里:

scala> def f(f:() => Any) = 0 //takes function with captured a - returns constant 0
f: (f: () => Any)Int

scala> lazy val a: Int  = f(() => a) + 5
a: Int = <lazy>

scala> a
res4: Int = 5 // 0 + 5

您可以将def f(f:() => Any) = 0替换为def f(f: => Any) = 0,因此a定义看起来确实会传递给f:lazy val a: Int = f(a) + 5

Streams使用相同的机制 - guesses map improve将作为名称调用的参数传递(链接到惰性a的lambda将保存在Stream中,但在请求tail之前不会计算),因此它& #39;类似于lazy val guesses = #::(1, () => guesses map improve)。当你致电guessess.head时 - 不会评估尾巴; guesses.tail会懒洋洋地返回Stream (improve(1), ?)guesses.tail.tail将会Stream(improve(improve(1)), ?),依此类推。

答案 1 :(得分:0)

您可以通过修改地图功能轻松找出正在发生的事情,如scaladoc example中所述:

scala> def sqrtStream(x: Double): Stream[Double] = {
     |   def improve(guess: Double): Double = (guess + x / guess) / 2
     |   lazy val guesses: Stream[Double] = 1 #:: (guesses map {n =>
     |     println(n, improve(n))
     |     improve(n)
     |   })
     |   guesses
     | }
sqrtStream: (x: Double)Stream[Double]

输出结果为:

scala> sqrtStream(4).take(10).toList
(1.0,2.5)
(2.5,2.05)
(2.05,2.000609756097561)
(2.000609756097561,2.0000000929222947)
(2.0000000929222947,2.000000000000002)
(2.000000000000002,2.0)
(2.0,2.0)
(2.0,2.0)
(2.0,2.0)
res0: List[Double] = List(1.0, 2.5, 2.05, 2.000609756097561, 2.0000000929222947, 2.000000000000002, 2.0, 2.0, 2.0, 2.0)

答案 2 :(得分:0)

guesses的值未被替换。流类似于列表,但仅在需要时才对其元素进行评估,然后将其存储,因此下次访问它们时,评估将不再必要。对流本身的引用不会改变。

Αλεχει上写的示例中,Scala API中有一个很好的解释: http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.Stream