我打印出一个数字流,但下面的代码只打印出序列中的第一个数字:
for ( n <- Stream.from(2) if n % 2 == 0 ) yield println(n)
2
res4: scala.collection.immutable.Stream[Unit] = Stream((), ?)
在Haskell中,以下保持打印出数字,直到被打断,我希望在Scala中有类似的行为:
naturals = [1..]
[n | n <- naturals, even n]
[2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,
答案 0 :(得分:4)
而不是仅仅产生println(为什么人们会想要无限的单元序列?):
for ( n <- Stream.from(2) if n % 2 == 0 ) println(n)
如果您真的想要无限的单位序列,请强制结果:
val infUnit = for ( n <- Stream.from(2) if n % 2 == 0 ) yield println(n)
infUnit.force // or convert to any other non-lazy collection
虽然最终它会崩溃程序(由于物化序列的长度很长)。
答案 1 :(得分:2)
for comprehension 的结果类型是第一个子句中相同类型的集合的集合。 See the flatMap function signature
所以
的结果for ( n <- Stream.from(2) .....
是Stream [_]类型的集合,它是惰性的,因此您必须将元素值或操作拉出来。
查看结果类型:
scala> :type for( n <- Stream.from(2)) yield n
scala.collection.immutable.Stream[Int]
scala> :type for( n <- List(1,2,3)) yield n
List[Int]
scala> :type for( n <- Set(1,2,3)) yield n
scala.collection.immutable.Set[Int]
要打印数字直到中断,请尝试:
Stream.from(2).filter(_ % 2 == 0) foreach println
它的类型授予我们它将起作用:
scala> :type Stream.from(2).filter(_ % 2 == 0) foreach println
Unit
答案 2 :(得分:1)
我认为你的意思是:
for (n <- Stream.from(2) if n % 2 == 0) yield n
(因为yield println(n)
始终yield ()
会产生副作用n
)
这为您提供了所需的收藏。但是,与Haskell不同,Scala在打印惰性列表(Stream
)时不会评估(惰性)列表的所有成员。但您可以使用.toList
将其转换为非惰性列表。但是,您在Scala中看不到相同的无限打印行为,因为它会在打印任何内容之前先尝试构建整个(无限)列表。
基本上,当使用内置toString
基础结构打印无限列表时,与Haskell相比,Scala中无法获得完全相同的语义和行为组合。
P.S。
for (n <- Stream.from(2) if n % 2 == 0) yield n
更快地表达为
Stream.from(2).filter(_ % 2 == 0)