以下代码打击了堆栈:
val fibs: Stream[BigInt] = BigInt(0) #:: BigInt(1) #:: fibs.zip(fibs.tail).map { n => n._1 + n._2 }.takeWhile(x => x < 4000000).filter(x => x % 2 == 0)
scala> fibs foreach println
0
1
java.lang.StackOverflowError
如果我取出过滤器并将其应用于另一个表达式中的流,如下所示,那很好:
scala> val fibs: Stream[BigInt] = BigInt(0) #:: BigInt(1) #:: fibs.zip(fibs.tail).map { n => n._1 + n._2 }.takeWhile(x => x < 4000000)
fibs: Stream[scala.math.BigInt] = Stream(0, ?)
scala> fibs filter ( x => x % 2 == 0)
res8: scala.collection.immutable.Stream[scala.math.BigInt] = Stream(0, ?)
scala> fibs filter ( x => x % 2 == 0) foreach println
0
2
8
34
144
610
2584
10946
46368
196418
832040
3524578
为什么用第一种方法吹掉堆栈而不是第二种?
答案 0 :(得分:2)
问题不在于filter
,而在于递归定义,它试图创建和删除序列中的下一个元素。请考虑以下事项。
scala> val fibs: Stream[Int] = 0 #:: 1 #:: fibs.zip(fibs.tail).map(n => n._1 + n._2).filter(_ < 30)
fibs: Stream[Int] = Stream(0, ?)
scala> fibs(8)
res58: Int = 21
scala> fibs(9)
*<massive stack dump>*
正如您所看到的,它不是filter
的存在,而是尝试访问过滤器尝试删除的元素。
保持递归Stream定义简单。在定义之外应用过滤器和限制(takeWhile
)。
答案 1 :(得分:0)
我只能给出一个肤浅的快速回答。
在第一种情况下,您在递归流中包含filter(x => x % 2 == 0)
,这会导致您的问题。这就是打印0
和1
的原因,这在第二个示例中不会发生,因为您在建立序列后进行过滤。 1
毕竟不是。
您应该单独定义您的fib流,然后才应用过滤器。
val fibs: Stream[BigInt] = BigInt(0) #:: BigInt(1) #::
fibs.zip(fibs.tail).map { n => n._1 + n._2 }
val result = fibs.filter(_ % 2 == 0).takeWhile(_ < 4000000)