2015-07-29 18 views
5

Ho due generatori, gen_n & gen_arr:QuickCheck: come combinare due generatori?

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 

Come posso combinare questi due in una Gen (Int, [Int])?

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

risposta

7

(i) È possibile utilizzare normale funtoriale composizione/monade di combinarli:

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

(Control.Applicative.liftA2 e Control.Monad.liftM2 sono anche bene, ovviamente)

(ii) non utilizzare suchThat per limitare un intervallo. Può essere terribilmente inefficiente, in quanto genera istanze casuali fino a quando la condizione non viene soddisfatta, scartando il resto. Invece, è possibile utilizzare elements :: [a] -> Gen a:

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

Aggiornamento: Come Zeta ha osservato di seguito, possiamo fare ancora meglio in questo caso, utilizzando choose (0,100) (choose :: Random a => (a, a) -> Gen a) al posto di elements [0..100]. Vedere here o here per l'elenco completo dei combinatori di generatori.


*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 vs. elements:

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

Il generatore suchThat non ha uscita nulla.

+2

Considerare 'choose (0,100)' invece di 'elements [0..100]'. Mentre 'elements' è ottimo se il tuo range non è continuo o se il tuo tipo non ha un'istanza' Random', 'choose' è solitamente più efficiente se i tuoi valori sono in un range chiuso. – Zeta