【问题标题】:Scala: filter forcing evaluation of entire StreamScala:整个流的过滤器强制评估
【发布时间】:2012-12-24 22:25:39
【问题描述】:

下面的代码在类的构造函数内部调用一次的方法本身调用一次。当它作为规范 UnitTest 的一部分执行时,测试会卡住,并产生一个快速消耗更多内存的 javaw 进程。

private def placeMines( excludes: List[( Int, Int )] ) {
    def rndstream: Stream[( Int, Int )] = {
        def s: Stream[( Int, Int )] =
            ( Random.nextInt( ysize ), Random.nextInt(  xsize ) ) #:: s
        s
    }
    def posPermitted( pos: ( Int, Int ) ): Boolean = {
        !excludes.contains( pos ) &&
            fieldEmpty( pos._1, pos._2 )
    }
    val positions = rndstream.filter( posPermitted )
    positions.take( minecount ).foreach( x => grid( x._1 )( x._2 ) = MineField() )
}

为了找出发生了什么,我用副作用注释掉了最后一行(网格是一个二维数组),并用不同的过滤谓词替换了过滤谓词,包括 x => false 和 x => true。有趣的是,它在 true 情况下终止,但在 false 情况下一直运行。插入一些 println 显示谓词在我终止 java 进程之前被调用了数十万次。

我尝试使用以下代码重现这种情况:

import scala.util.Random
import org.specs.SpecificationWithJUnit

class foobar extends SpecificationWithJUnit {
    val x = 0xDead
    val y = 0xBeef

    bar(x, y)

    private def bar(x: Int, y: Int) = foo(x)

    private def foo(x: Int) = {
        def s: Stream[( Int, Int )] = {
            def p: Stream[( Int, Int )] =
                ( Random.nextInt( x ), Random.nextInt( y ) ) #:: p
            p
        }
        val fiveodd = s.filter( x => x._1 % 2 == 1 )
        println( fiveodd.take( 5 ).toList )
    }
}

但是该代码运行良好。

搜索“scala 流过滤器无止境”“scala 流过滤器强制评估”和“scala 流过滤器不终止”只提供了教程,这些教程展示了流的用法,这在原则上与我的代码相同。

【问题讨论】:

  • 对了,可以简化rndstream方法:def rndstream: Stream[( Int, Int )] = ( Random.nextInt( ysize ), Random.nextInt( xsize ) ) #:: rndstream

标签: scala filter stream


【解决方案1】:

我猜你的过滤功能有问题。 Stream.filter 尝试找到第一个匹配值,如果没有,它将永远搜索。

获取您的示例流并调用

s.filter(_ => false)

这不会返回,所以它必须是你的过滤函数。

【讨论】:

  • 好吧,我再次检查,虽然谓词是造成症状的原因,但原因在于测试用例以及 ysize 和 xsize。具体来说,我有一堆使用 1 * 1 网格的测试用例,在这种情况下,Random.next(*size) 显然总是返回 0。但由于我也有 (0,0):: Nil 指定为排除第一部分谓词总是评估为假。我想我会做出改变并要求 ysize * xsize 至少为 2 。感谢您抽出宝贵时间回答我,并为浪费您的时间而道歉,我应该从一开始就对我的谓词提出更多质疑。
猜你喜欢
  • 2017-12-28
  • 1970-01-01
  • 2016-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多