scala - scala 中的函数式编程 - 无限流

标签 scala functional-programming

我正在完成《Scala 函数式编程》一书中的练习和概念。假设我需要定义一个常量函数,它按给定值返回无限流。

这是我的版本:

def constant[A](a: A): Stream[A] = Stream.cons(a, constant(a))

答案在 GitHub :

def constant[A](a: A): Stream[A] = {
  lazy val tail: Stream[A] = Cons(() => a, () => tail)
  tail
}

评论说后者比前者更有效,因为它只是一个引用自身的对象。 我无法理解这一点,任何帮助将不胜感激。 (对我蹩脚的英语感到抱歉:)

最佳答案

假设您以第一种方式定义constant。现在,

constant(something)

这是一个 Cons 单元格,它引用了惰性值 somethingconstant(something)

Cons(() => something, () => constant(something))

现在,让我们尝试获取第 1000 个元素。我们需要评估尾部,因为我们需要比第一个元素更深入。因此,我们执行 constant(something),然后我们得到一个 Cons 单元格,它看起来就像原来的一样:

Cons(() => something, () => constant(something))

我们尝试获取此Stream的第999个元素。这是低效的,因为这个对象与之前的对象相同,所以我们只是浪费了时间来制作它。我们将继续浪费时间和内存来制作 1000 个相同的 Cons 单元。 (请原谅糟糕的绘图。)

Graph of first version

现在,用第二种方式定义constant

constant(something)
{ lazy val self = Cons(something, self); self }

现在,您的Stream仅具有对其自身的引用。获取此 Stream 的尾部不会创建新的 Cons 单元;它只是返回原始流(self.tail eq self),这意味着您不会浪费任何内存,而且时间成本也会下降,因为您也不会浪费时间分配和填充该内存。

Graph of second version

关于scala - scala 中的函数式编程 - 无限流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46900605/

相关文章:

scala - 像 $read 和 $iw 这样的奇怪名称在具体化表达式中做了什么?

scala - 使用 Scala Either,如何在第一个错误处停止,但获取已经计算的值

haskell - 如何在haskell中编写定点函数

algorithm - Clojure DAG(贝叶斯网络)

function - 在 Scala 中,为什么我们在定义方法时需要 "="?

scala - 如何将 RDD[(Key, Value)] 转换为 Map[Key, RDD[Value]]

java - 如何在 Scala 中子类化 Exception

java - mod-mysql-postgresql 在启动期间尝试下载 io.vertx~lang-scala~1.0.0 模块

scala - 在 Scala 代码中使用全部大写字母

java - 从 Either<L, R> vavr 中取消装箱值