Scala lazy val explanation

I am using functional programming in a Scala course on Coursera and I am having a hard time understanding this piece of code -

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
}

      

This method will find 10 approximate square roots of 4 in ascending order of precision when I do sqrtSteam (4). Take (10). toList.

Can someone explain the guesswork estimation strategy here? My doubt is, what is the guessing value in the substitution when the second guessing value is picked up?

+3


source to share


3 answers


Let's start with a simplified example:

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

 scala> a
 Qaru here, because of infinite recursion

      

So, it is a

recalculated until it gets a stable value, for example here:



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

      

You can replace def f(f:() => Any) = 0

on def f(f: => Any) = 0

, so the definition a

would look as if it really passed in f: lazy val a: Int = f(a) + 5

.

Streams use the same mechanism - guesses map improve

will be passed as a parameter called by name (and the lambda associated with the lazy a

will be stored inside the Stream, but not calculated until the tail is requested), so it likes lazy val guesses = #::(1, () => guesses map improve)

When you call guessess.head

- the tail will not be judged; guesses.tail

will return lazily Stream (improve(1), ?)

, guesses.tail.tail

will Stream(improve(improve(1)), ?)

, etc.

+3


source


You can easily find out what's going on by changing the map function, as described in the 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]

      



Output:

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)

      

0


source


The value is guesses

not replaced. A stream is like a list, but its items are only evaluated when they are needed, and then they are stored, so the next time you receive them, the evaluation will not be needed. The link to the stream itself does not change.

At the top of the example Αλεχει it is written, there is a good explanation in the Scala API: http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.Stream

0


source







All Articles