Scala中懒惰流的第一个元素

时间:2016-08-31 19:07:09

标签: scala functional-programming stream lazy-evaluation scala-streams

这是一个最小的例子,我可以定义一个函数,通过

给出下一个整数
def nextInteger(input: Int): Int = input+1

然后我可以将一个惰性整数流定义为

lazy val integers: Stream[Int] = 1 #::  integers map(x=>nextInteger(x))

令我惊讶的是,获取此流的第一个元素是2而不是1

scala> integers
res21: Stream[Int] = Stream(2, ?)

在这个简单的例子中,我可以在整数的定义中使用0而不是1来实现我想要的结果,但是如何通常设置流以使初始值不丢失?在我的情况下,我正在设置一个迭代算法,并希望知道初始值。

编辑: 此外,我从未理解使以下语法失败的设计选择:

scala> (integers take 10 toList) last
res27: Int = 11

scala> integers take 10 toList last
<console>:24: error: not found: value last
              integers take 10 toList last
                                      ^

我发现括号中的包装物很麻烦,有没有我不知道的速记?

1 个答案:

答案 0 :(得分:4)

您可能认为1 #:: integers map(x=>nextInteger(x))被解析为1 #:: (integers map(x=>nextInteger(x))),而它实际上被解析为(1 #:: integers).map(x=>nextInteger(x))。添加parens可以解决您的问题:

val integers: Stream[Int] = 1 #:: (integers map nextInteger)

(请注意,由于nextInteger只是一个函数,因此您不需要为它创建一个lambda,并且因为Stream已经是懒惰的,所以integers懒惰是不必要)

关于您的修改,请查看this关于此事的优秀答案。简而言之:没有简单的方法。问题是,除非你已经知道所涉及功能的优点,否则你所建议工作的内容对于下一个阅读代码的人来说将是完美的...例如,

myList foo bar baz

可能是myList.foo.bar.baz以及myList.foo(bar).baz,如果不检查foobarbaz的定义,您就不会知道。 Scala决定消除这种模糊性 - 它始终是后者。