How to use 'oneof' in quickCheck (Haskell)

I am trying to write a prop that changes a Sudoku and then checks if it's still valid.
However, I am not sure how to use the "oneof"function properly. Can you give me some hints, please?
prop_candidates :: Sudoku > Bool prop_candidates su = isSudoku newSu && isOkay newSu where newSu = update su aBlank aCandidate aCandidate = oneof [return x  x < candidates su aBlank] aBlank = oneof [return x  x < (blanks su)]
Here are some more info...
type Pos = (Int, Int) update :: Sudoku > Pos > Maybe Int > Sudoku blanks :: Sudoku > [Pos] candidates :: Sudoku > Pos > [Int] [return x  x < (blanks example)] :: (Monad m) => [m Pos]
I have struggeled with this prop for 3 hours now, so any ideas are welcome!
What I was driving at is that you have a type mixup. Namely,
aBlank
is not aPos
, but aGen Pos
, soupdate su aBlank aCandidate
makes no sense! In fact, what you want is a way to generate a new sudoku given an initial sudoku; in other words a functionsimilarSudoku :: Sudoku > Gen Sudoku
Now we can write it:
similarSudoku su = do aBlank < elements (blanks su)  simpler than oneOf [return x  x < blanks su] aCandidate < elements (candidates su aBlank) return (update su aBlank aCandidate)
or even simpler:
similarSudoku su = liftM2 (update su) (elements (blanks su)) (elements (candidates su aBlank))
And the property looks like
prop_similar :: Sudoku > Gen Bool prop_similar su = do newSu < similarSudoku su return (isSudoku newSu && isOkay newSu)
Since there are instances
Testable Bool Testable prop => Testable (Gen prop) (Arbitrary a, Show a, Testable prop) => Testable (a > prop)
Sudoku > Gen Bool
isTestable
as well (assuminginstance Arbitrary Sudoku
).On my blog, I wrote a simple craps simulator with QuickCheck tests that use
oneof
to generate interesting rolls.Say we have a supersimple Sudoku of a single row:
module Main where import Control.Monad import Data.List import Test.QuickCheck import Debug.Trace type Pos = Int data Sudoku = Sudoku [Char] deriving (Show)
No supersimple Sudoku should have repeated values:
prop_noRepeats :: Sudoku > Bool prop_noRepeats s@(Sudoku xs) = trace (show s) $ all ((==1) . length) $ filter ((/='.') . head) $ group $ sort xs
You might generate a supersimple Sudoku with
instance Arbitrary Sudoku where arbitrary = sized board :: Gen Sudoku where board :: Int > Gen Sudoku board 0 = Sudoku `liftM` shuffle values board n  n > 6 = resize 6 arbitrary  otherwise = do xs < shuffle values let removed = take n xs dots = take n $ repeat '.' remain = values \\ removed ys < shuffle $ dots ++ remain return $ Sudoku ys values = ['1' .. '9'] shuffle :: (Eq a) => [a] > Gen [a] shuffle [] = return [] shuffle xs = do x < oneof $ map return xs ys < shuffle $ delete x xs return (x:ys)
The
trace
is there to show the randomly generated boards:*Main> quickCheck prop_noRepeats Sudoku "629387451" Sudoku "91.235786" Sudoku "1423.6.95" Sudoku "613.4..87" Sudoku "6..5..894" Sudoku "7.2..49.." Sudoku "24....1.." [...] +++ OK, passed 100 tests.
it seems that
aBlank :: Gen Pos
which does not match the way it is used as an argument ofcandidates :: Sudoku > Pos > [Int]
.I've been looking through here to find a way to convert
Gen a
toa
which would allow you to use it with candidates. The best i could see is thegenerate
function.Tell me if I'm missing something...
来源：https://stackoverflow.com/questions/1828850/howtouseoneofinquickcheckhaskell