Scala惰性val解释

Scala惰性val解释,scala,lazy-evaluation,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.to

我正在参加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的平方根


有人能解释一下猜测的评估策略吗?我的疑问是,当拾取第二个猜测值时,会替换中的猜测值是多少?

您可以通过修改map函数轻松了解发生了什么,如中所述:

输出为:

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)

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

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

 scala> a
 stack overflow here, because of infinite recursion
您可以将
def(f:()=>Any)=0
替换为
def(f:=>Any)=0
,因此
a
定义看起来像是真的传递给了f:
延迟值a:Int=f(a)+5


流使用相同的机制-
猜测映射改进
将作为名称调用的参数传递(链接到惰性
a
的lambda将保存在流中,但在请求tail之前不会计算),所以这就像
惰性val猜测=#::(1,()=>猜测映射改进)
。当您调用
guessess.head
-将不计算tail<代码>猜测。tail将延迟返回
流(改进(1),?)
猜测。tail.tail
流(改进(1)),?)
等等。

猜测的值不被替换。流就像一个列表,但它的元素只有在需要时才被计算,然后才被存储,所以下次访问它们时,不需要进行计算。对流本身的引用不会更改

Αλεχει编写的示例之上,Scala API中有一个很好的解释:

谢谢。我从未意识到按名称调用参数可以被视为这样的函数
def(f:()=>Any)=0
。我想这澄清了我的主要困惑,即在调用guesses.tail时使用guesses的值是多少。看起来它将是猜测的当前值,尾部被延迟计算。你能解释一下“链接到延迟a的lambda将被保存在流中”是什么意思吗?这里的lambda是什么?如果我们不在猜测之前使用lazy,会发生什么?如果不在猜测之前使用lazy,您将收到编译时错误(val不允许任何递归)。因此lazy val介于val和def之间-它作为def是懒惰的,但像val一样只初始化一次。当我谈论lambdas时,我指的是匿名函数
()=>x+100500
是一个匿名函数,它接受零参数并返回
x+100500
。这里没有提到X作为函数参数,所以这是一个clojure,它作为自由值链接到X。流只是将您的clojure保存在其内部状态中-因此它不会在流的创建时计算。当您尝试实际访问流的尾部时,它将被计算并保存。因此,有没有一种方法可以将猜测实现为def,即使其效率很低?我的问题不是发生了什么。但更像它是如何发生的?
 scala> lazy val a: Int  = a + 5
 a: Int = <lazy>

 scala> a
 stack overflow here, because of infinite recursion
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