mpchau
mpchau

Reputation: 21

Proper use of delayed evaluation in Scala

I am trying to rewrite the following example from the book "Structure and Interpretation of Computer Programs", chapter 3.5.4: http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-24.html#%_sec_3.5.4

The following are my codes:

def addStream(s1 : Stream[Double], s2 : Stream[Double]) : Stream[Double] = {
  (s1.head + s2.head) #:: addStream(s1.tail, s2.tail)
}

def scaleStream(stream : Stream[Double], factor : Double) : Stream[Double] =    {
  (stream.head * factor) #:: scaleStream(stream.tail, factor)
}

def integral(integrandLazy: => Stream[Double], initialValue : Double, dt : Double) : Stream[Double] = {
  def int : Stream[Double] = {
    initialValue #:: addStream(scaleStream(evalStream, dt), int)
  }
  def evalStream : Stream[Double] ={
    lazy val stream : Stream[Double] = integrandLazy
    stream
  }
  int
}

def solve(f : Double => Double, y0 : Double, dt : Double) : Stream[Double] = {
  def y : Stream[Double] = {
    integral(dy, y0, dt)
  }
  def dy : Stream[Double] = {
    y.map(f)
  }
  y
}

val returnedStream = solve((x : Double) => {x}, 1, 0.001)
val limited = returnedStream take 30
limited foreach println

So you can see I am trying to use the lazy val feature in Scala to mimic the delayed evaluation in the book. The program runs, but it gets stuck when it tries to evaluate the 24th elements in the stream.

What's wrong with my program? Am I using the right feature in Scala to mimic the delayed evaluation?

Upvotes: 2

Views: 104

Answers (1)

sjrd
sjrd

Reputation: 22085

In Scala, lazy vals are evaluated as soon as you mention them. So in your example, it doesn't accomplish anything, since you mention it right after you define it.

Essentially, you can translate the lazy val as follows (the actual translation is more involved because it takes care of threading issues, but never mind that here):

def evalStream: Stream[Double] = {
  var _stream: Stream[Double] = null
  var _streamInit: Boolean = false
  def stream: Stream[Double] = {
    if (!_streamInit) {
      _stream = integrandLazy
      _streamInit = true
    }
    _stream
  }
  stream
}

From this rewriting, it should be clear that the whole thing is basically equivalent to just evaluating integrandLazy eagerly.

Upvotes: 1

Related Questions