2014-02-08 104 views
0

在試圖學習ScalaCheck工具時,我寫了兩個版本的Map生成器(我知道其中有一個內置,但這是一個練習)。這些scalacheck遞歸生成器爲什麼不等價?

似乎genMap0genMap00應該是等價的,並且genMap00是有點清潔,但實際上genMap0作品,但genMap00悲慘的失敗了。

yield裝飾着一個println可以打開,看看有什麼發生(只需編輯speak方法),但即使有這樣的信息,我不能說我真正明白爲什麼差異。這讓我認爲我試圖寫的另一個發電機也可能有缺陷。

有人可以給出一個很好的解釋genMap0genMap00之間有什麼不同嗎?

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() 

回答

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生成器似乎更清潔。