2016-04-13 36 views
1

ScalaCheck發電機與Scala的語法糖表達式工作:如何在內部使用ScalaCheck生成器來理解?

for(s1 <- Gen.choose(1, 10); s2 <- Gen.choose(10, 100)) yield (s1, s2) 

我希望能夠與ScalaCheck表達式都搭配「傳統」斯卡拉。例如:

for(s0 <- 0 until 10; s1 <- Gen.choose(1, 10); s2 <- Gen.choose(10, 100)) yield (s0, s1, s2) 

然而,這將不編譯,由於0 until 10表達式不是一個類型的Gen

如何在同一個for循環內實現此操作(和Seq和/或Traversable表達式)?

編輯:在答案中的共識似乎是我所尋找的那種語法糖是不可能的。

但是,這可能不是用某種形式的有狀態的Gen來完成的嗎?特別是使用國家monad的?

+3

我不清楚您要在此實現的目標。你想要表達什麼樣的表達方式? (在你的問題中第一個'for'表達式的類型爲Gen [(Int,Int)]' - 應該是第二個?] –

+0

我希望得到的表達式具有Gen [(Int,Int,Int) ],但是s0的數值範圍從0到10,而s1和s2是每次隨機選擇的。 – NietzscheanAI

+0

我明白了 - 所以你只需要「確保」使用(1到10)的所有值,而不是從這個範圍中隨機選擇。我不知道有什麼辦法可以做到這一點...... –

回答

2

我希望能夠將「傳統」Scala與ScalaCheck表達式混合使用。

你不能那樣做;至少,不是你的建議。你可以做的是定義一個發生器,其產生10長列表的三元組(即長度爲10的列表)中,其中

  • 第一元件是不是隨機的(而是範圍從0至10),
  • 第二元件1和10之間隨機選擇的,
  • 第三元件10和100。

發生器執行之間隨機選擇

我假定org.scalacheck.Gen在範圍內。

  1. 定義生成器,用於一個一個三元組的第二和第三元件組成的一對:

    val pairGen: Gen[(Int, Int)] = for { 
        s1 <- Gen.choose(1, 10) 
        s2 <- Gen.choose(10, 100) 
    } yield (s1, s2) 
    
  2. 定義發生器10長,例如對列表:

    val listOfPairsGen: Gen[List[(Int, Int)]] = Gen.listOfN(10, pairGen) 
    
  3. Define

    val intList: List[Int] = (0 until 10).toList 
    
  4. 郵編intListlistOfPairsGen的結果,而 「變平的每個元素,以三」:

    val myGen: Gen[List[(Int, Int, Int)]] = 
        listOfPairsGen map { list: List[(Int, Int)] => 
        (intList zip list) map { case (a, (b, c)) => (a, b, c) } 
        } 
    

例子

scala> myGen.sample.head 
res0: List[(Int, Int, Int)] = List((0,2,58), (1,10,34), (2,3,94), (3,2,91), (4,6,15), (5,7,99), (6,4,82), (7,10,69), (8,8,78), (9,10,27)) 

scala> myGen.sample.get 
res1: List[(Int, Int, Int)] = List((0,2,56), (1,2,83), (2,4,76), (3,4,87), (4,4,55), (5,6,80), (6,4,94), (7,7,67), (8,10,92), (9,4,84)) 

scala> myGen.sample.get 
res2: List[(Int, Int, Int)] = List((0,10,40), (1,9,48), (2,10,63), (3,5,100), (4,5,67), (5,4,73), (6,8,56), (7,6,58), (8,6,82), (9,10,86)) 

scala> myGen.sample.get 
res3: List[(Int, Int, Int)] = List((0,6,56), (1,7,94), (2,4,40), (3,7,27), (4,1,91), (5,3,50), (6,1,70), (7,6,90), (8,7,23), (9,7,49)) 
+0

等效(但更容易)的方法是將屬性驗證包裝在'(1到10).forall {s1 => – Aivean

+1

@Aivean True中,但OP是否需要基於屬性的測試環境中的此生成器尚不清楚。他/她可能希望將此生成器用於其他目的。 – Jubobs

1

由於Jubobs已經解釋的,你不能

將「傳統」Scala與ScalaCheck表達式混合使用

但是,你可以使用索引用稍差慣用的方法達到上述結果:

def indexedGenerator = { 
    val index = new AtomicInteger(0) 
    for (s1 <- Gen.choose(1, 10); s2 <- Gen.choose(10, 100)) yield (index.getAndIncrement(), s1, s2) 
} 

val gen = indexedGenerator 
println(gen.sample) |-> Some((0,1,60)) 
println(gen.sample) |-> Some((1,8,82)) 
println(gen.sample) |-> Some((2,9,29)) 
println(gen.sample) |-> Some((3,6,76)) 
println(gen.sample) |-> Some((4,5,32)) 

雖然你將不得不謹慎對待的時間和地點來實例化一個Generator喜歡這一點,因爲計數變量將不會重置爲每個屬性檢查。因此,您需要在每次需要索引從0開始時創建一個新的本地實例。

相關問題