在Scala中正确使用延迟评估

时间:2015-02-04 03:53:41

标签: scala lazy-evaluation sicp

我试图重写以下示例来自书籍"计算机程序的结构和解释",第3.5.4章: http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-24.html#%_sec_3.5.4

以下是我的代码:

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

所以你可以看到我正在尝试使用Scala中的lazy val功能来模拟书中的延迟评估。该程序运行,但在尝试评估流中的第24个元素时会卡住。

我的计划有什么问题?我是否在Scala中使用正确的功能来模拟延迟评估?

1 个答案:

答案 0 :(得分:1)

在Scala中,只要您提及,就会对lazy val进行评估。所以在你的例子中,它并没有完成任何事情,因为你在定义之后就提到了它。

基本上,您可以按照以下方式翻译lazy val(实际翻译更为复杂,因为它会处理线程问题,但不要在意这里):

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
}

从这次改写中,应该清楚的是,整个事情基本上等同于只是急切地评估integrandLazy