我在{PMPG上this answer proud haskeller看到了Haskell的这个片段:
x=2:x
我想,"等等,我可以在Scala中做到这一点!"所以我试过了:
lazy val x: List[Int] = 2 :: x
它已编译,我的控制台打印出一个不错的x: List[Int] = <lazy>
。但是这些行中的每一行都会产生StackOverflowException
:
x take 1
x.head
x(1)
x
基于最后一个,看起来任何使用x
的尝试都会试图计算x
(尝试在控制台中打印它时发生堆栈溢出)。在这个例子中,斯卡拉的懒惰与哈斯克尔的懒惰有什么不同?这是Scala lazy val
的功能还是List
类只需要一个完整的尾部?
答案 0 :(得分:10)
你想要的是def x: Stream[Int] = 2 #:: x
。这会产生immutable.Stream[Int]
。
仅在需要时评估惰性变量,但会对其进行全面评估。另一方面,Stream
是一组惰性值。每个元素仅在需要时进行评估,但可能永远不会评估整个集合,这就是为什么它可以是无限的。
答案 1 :(得分:1)
嗯,看起来我在制定问题时想出来了。 List
似乎比lazy val
更容易出问题。为了尝试这一点,我做了一个简单的LazyList
实现:
class LazyList(h: Int, t: => LazyList) {
val head = h
lazy val tail = t
}
然后我可以做:
lazy val x: LazyList = new LazyList(1, x)
x.head // 1
x.tail.tail.tail.head // 1
所以,Scala的懒惰毕竟是懒惰,如果你让一切都变得懒惰,至少。