scala - 惰性求值解释

标签 scala

更新:使用两个构造函数的用法更新了代码,基本上我感到困惑的是,ConsStream.cons 之间有什么区别。附:这个例子来自《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

最佳答案

lazy val head = hd

由于您没有指定head的类型,因此它将是() => Int,并且每次获取head时,hd 正在评估,i 不断增加

我认为您想要计算hd并将值存储在Stream.cons函数中,因此您需要显式指定类型:

lazy val head: A = hd

tail 变量也是如此。

关于scala - 惰性求值解释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33246328/

相关文章:

scala - 何时在 Scala 中使用 Option,何时不使用

scala - 如何从 Int 或 Byte 初始化枚举?

scala - 如何在 Spark DataFrame API 中重命名结构数组的元素

scala - 在 play 的配置文件中定义一个数组

list - 在满足谓词的每个元素处拆分列表(Scala)

scala - 将表列的子集巧妙地转换为案例类

scala - 如何解决 eclipse 2019 中的 Scala 错误?

scala - 在ScalaTest中使用 “should NOT produce [exception]”语法

scala - 使用来自 s3 或本地文件系统的 spark 从子目录递归读取文件

scala - 有顺序的 Future.find 吗?