更新:使用两个构造函数的用法更新了代码,基本上我感到困惑的是,Cons
和Stream.cons
之间有什么区别。附:这个例子来自Book Scala中的函数编程的第5章。
所以任何人都可以向我解释为什么下面的懒惰评估没有按预期工作?我的Scala工作表的输出是
One
res0: Int = 1
One
res1: Int = 2
One
res2: Int = 3
One
res3: Int = 4
One
res4: Int = 5
One
res5: Int = 6
清除这不是预期的输出,因为延迟评估One
应该只打印一次而i
只应增加一次,但似乎并非如此。我错过了一些东西,却看不到它,任何一双新鲜的眼睛都在伸出援助之手?
sealed trait Stream[+A] {
def toList: List[A] = {
@annotation.tailrec
def go(s: Stream[A], acc: List[A]): List[A] = s match {
case Cons(h,t) => go(t(), h() :: acc)
case _ => acc
}
go(this, List()).reverse
}
}
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: _*))
}
var i = 0
val nonLazy = Cons(
() => { println("One"); i+=1; i },
() => Cons(
() => { println("Two"); i+=2; i },
() => Empty))
nonLazy.h
nonLazy.h
nonLazy.h
var i = 0
val lazy = Stream.cons(
() => { println("One"); i+=1; i },
Stream.cons(
() => { println("Two"); i+=2; i },
Empty)).toList
lazy.head
lazy.head
lazy.head
lazy.head
lazy.head
lazy.head
答案 0 :(得分:2)
lazy val head = hd
因为您没有指定head
的类型,它将是() => Int
,并且每当您获取头部时,hd
正在评估,i
增加并增加
我认为您要计算hd
并将值存储在Stream.cons
函数中,因此您需要明确指定类型:
lazy val head: A = hd
tail
变量也是如此。
答案 1 :(得分:1)
我认为您忘记了hd
是什么 - 即返回Int的function0
,或使用简写() => Int
。
当你这样称呼时:
stream.head()
这是做什么的:
stream.head
(这是一个函数,因此有一个apply()
方法可以调用,它将打印'One',将i
递增2,然后返回{{ 1}}。i
是Scala使其变得简单易用的方式。如果您不想执行该功能,请尝试以下操作:
()
这将返回:
apply()
stream.head
stream.head
stream.head
stream.head
stream.head
stream.head
确实是懒惰的 - 每次都是相同的功能 - 但是你要执行它6次!
答案 2 :(得分:1)
如果您想致电Stream.cons(()=>{println("One"); i+=1; i}, Stream.cons(()=>{println("Two"); i+=2; i}, Empty))
,则需要修改其类型:
def cons[A](hd: () => A, tl: () => Stream[A]): Stream[A] = {
lazy val head = hd()
lazy val tail = tl()
Cons(() => head, () => tail)
}
要访问它,您需要
val stream = Stream.cons(()=>{println("One"); i+=1; i}, Stream.cons(()=>{println("Two"); i+=2; i}, Stream.Empty)) // won't print anything
stream.h() // will print "One" and return 1
stream.h() // will return 1 without printing anything
stream.h() // will return 1 without printing anything
使用toList
会阻止您实际看到懒惰。