我正在完成本书的练习和概念: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
}
评论说后者比前者效率更高,因为它只是一个引用自身的对象。 我无法理解这一点,任何帮助都将不胜感激。 (抱歉我的英语不好:)。
答案 0 :(得分:7)
假设您以第一种方式定义constant
。现在,
constant(something)
这是一个Cons
单元格,它引用了惰性值something
和constant(something)
Cons(() => something, () => constant(something))
现在,让我们尝试获取第1000个元素。我们需要评估尾部,因为我们需要比第一个元素更深入。所以,我们执行constant(something)
,然后我们得到一个看起来像原始的新 Cons
单元格:
Cons(() => something, () => constant(something))
我们尝试获得此Stream
的第999个元素。这是低效的,因为这个对象与以前的对象相同,所以我们浪费了时间来制作它。我们将继续浪费时间和内存,制作1000个相同的Cons
单元格。 (请原谅可怕的画作。)
现在,第二种方式定义constant
。
constant(something)
{ lazy val self = Cons(something, self); self }
现在,您的Stream
只是引用了自己。获取此Stream
的尾部不会创建新的Cons
单元格;它只返回原始流(self.tail eq self
),这意味着你不会浪费任何内存,时间成本会下降,因为你也不会浪费时间来分配和填充内存。