2015-07-29 18 views
5

Ich habe zwei Generatoren, gen_n & gen_arr:QuickCheck: Wie man zwei Generatoren kombiniert?

gen_n :: Gen Int 
gen_n = suchThat arbitrary (\i -> i >= 0 && i <= 10) 

gen_elem :: Gen Int 
gen_elem = suchThat arbitrary (\i -> i >= 0 && i <= 100) 

gen_arr :: Gen [Int] 
gen_arr = listOf gen_elem 

Wie kann ich diese beiden in einem Gen (Int, [Int]) kombinieren?

combine_two_gens :: Gen a -> Gen b -> Gen (a, b) 

Antwort

7

(i) Sie normale funktoriellen/monadischen Zusammensetzung, sie kombinieren können:

gen_comb :: Gen (Int, [Int]) 
gen_comb = (,) <$> gen_elem <*> gen_arr 

(Control.Applicative.liftA2 und Control.Monad.liftM2 auch fein sind, natürlich)

(ii) Verwenden Sie suchThat nicht, um nur einen Bereich zu beschränken. Es kann furchtbar ineffizient sein, da es nur zufällige Instanzen generiert, bis die Bedingung erfüllt ist, und den Rest verwerfen. Stattdessen könnten Sie elements :: [a] -> Gen a verwenden:

gen_elem' :: Gen Int 
gen_elem' = elements [0..100] 

gen_arr' :: Gen [Int] 
gen_arr' = listOf gen_elem' 

gen_comb' :: Gen (Int, [Int]) 
gen_comb' = (,) <$> elements [0..100] <*> listOf (elements [0..100]) 

Update: Wie Zeta unten bemerkt, können wir es besser machen, auch in diesem Fall durch choose (0,100) (choose :: Random a => (a, a) -> Gen a) statt elements [0..100] verwenden. Eine vollständige Liste der Generatorkombinatoren finden Sie unter here oder here.


*Main> sample gen_arr' 
[78] 
[2,27] 
[12,39] 
[92,22,40,6,18,19,25,13,95,99] 
... 
*Main> sample gen_comb' 
(9,[23,3]) 
(11,[67,38,11,79]) 
(5,[96,69,68,81,75,14,59,68]) 
... 

suchThat gegen elements:

*Main> sample (suchThat arbitrary (\i -> i >= 10000 && i <= 10005)) 
^CInterrupted. 
*Main> sample (elements [10000..10005]) 
10003 
10002 
10000 
10000 
... 

Der suchThat Generator aber keine Ausgabe nichts.

+2

Betrachten Sie 'wählen (0,100)' anstelle von 'Elemente [0..100]'. Während 'elements' groß sind, wenn Ihr Bereich nicht kontinuierlich ist oder wenn Ihr Typ keine' Random'-Instanz hat, ist 'choose' normalerweise effizienter, wenn sich Ihre Werte in einem geschlossenen Bereich befinden. – Zeta