在尝试学习ScalaCheck工具时,我编写了两个版本的Map生成器(我知道其中有一个是内置的,但这是一个练习)。
似乎genMap0
和genMap00
应该是等效的,genMap00
更清晰,但实际上genMap0
有效,但genMap00
失败了。
yield
装饰有println
,可以打开以查看发生了什么(只需编辑speak
方法),但即使有了这些信息,我也不能说我真的明白了为什么差异。这让我觉得我尝试写的另一个生成器也可能存在缺陷。
有人可以很好地解释genMap0
和genMap00
之间的不同之处吗?
import org.scalacheck._
import Arbitrary._
import Gen._
import Prop._
def speak(message: String): Unit = if (false) println(message)
lazy val genMap0: Gen[Map[Int, Int]] = for {
k <- arbitrary[Int]
v <- arbitrary[Int]
b <- arbitrary[Boolean]
m <- if (b) value(Map.empty[Int, Int]) else genMap0
} yield if (b) {
speak("false"); m
} else {
speak("true"); m.updated(k, v)
}
lazy val genMap00: Gen[Map[Int, Int]] = for {
k <- arbitrary[Int]
v <- arbitrary[Int]
m <- oneOf(Map.empty[Int, Int], genMap00)
} yield if (m.isEmpty) {
speak("empty:" + m); m
} else {
speak("not empty:" + m); m.updated(k, v)
}
val n = 5
for (i <- 1 to n; m <- genMap0.sample) println(m)
println("--------------")
for (i <- 1 to n; m <- genMap00.sample) println(m)
这是输出(genMap00
总是生成空地图):
scala -cp scalacheck_2.10-1.10.1.jar
...
// Exiting paste mode, now interpreting.
Map()
Map(1 -> 1, 1530546613 -> -1889740266, -187647534 -> 0)
Map()
Map(-1 -> 2039603804)
Map(646468221 -> 1)
--------------
Map()
Map()
Map()
Map()
Map()
答案 0 :(得分:1)
递归生成的问题总是以空映射开始,因此gen00
总是以生成空映射的生成器结束。问题是空状态也被用于检测终止。
这由gen000
修正:
lazy val genMap000: Gen[Map[Int, Int]] = for {
k <- arbitrary[Int]
v <- arbitrary[Int]
m <- oneOf(None, genMap000.map(g => Some(g)))
} yield (for (x <- m) yield x.updated(k, v)).getOrElse(Map())
这使用中间Option[Map]
,None
状态表示终止。
使用显式Boolean
生成器似乎更清晰。