Haskell GHCi打印延迟序列,但Scala REPL不打印

时间:2014-06-16 15:56:55

标签: scala haskell

我打印出一个数字流,但下面的代码只打印出序列中的第一个数字:

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,

3 个答案:

答案 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)