【发布时间】:2017-07-22 19:26:21
【问题描述】:
我正在按照一本书的示例在 Scala 中使用惰性求值来实现 Steam 类。
sealed trait Stream[+A]
case object Empty extends Stream[Nothing]
case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A]
object Stream {
def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = {
lazy val head = hd
lazy val tail = tl
Cons(() => head, () => tail)
}
def empty[A]: Stream[A] = Empty
def apply[A](as: A*): Stream[A] = {
if (as.isEmpty) empty else cons(as.head, apply(as.tail: _*))
}
}
然后我用一个简单的函数来测试它是否工作
def printAndReturn: Int = {
println("called")
1
}
然后我像下面这样构造 Stream:
println(s"apply: ${
Stream(
printAndReturn,
printAndReturn,
printAndReturn,
printAndReturn
)
}")
输出是这样的:
called
called
called
called
apply: Cons(fpinscala.datastructures.Stream$$$Lambda$7/1170794006@e580929,fpinscala.datastructures.Stream$$$Lambda$8/1289479439@4c203ea1)
然后我使用cons构造了Stream:
println(s"cons: ${
cons(
printAndReturn,
cons(
printAndReturn,
cons(printAndReturn, Empty)
)
)
}")
输出是:
cons: Cons(fpinscala.datastructures.Stream$$$Lambda$7/1170794006@2133c8f8,fpinscala.datastructures.Stream$$$Lambda$8/1289479439@43a25848)
所以这里有两个问题:
- 当使用 apply 函数构造 Stream 时,所有
printAndReturn都会被计算。这是因为对apply(as.head, ...)的递归调用会评估每个头吗? - 如果第一个问题的答案是正确的,那么如何更改
apply使其不强制评估?
【问题讨论】:
标签: scala lazy-evaluation