scala中的函数编程 - 无限流

时间:2017-10-24 00:56:44

标签: scala functional-programming

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

这是我的版本:

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
}

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

1 个答案:

答案 0 :(得分:7)

假设您以第一种方式定义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