Как использовать 'oneof' в quickCheck (Haskell) - PullRequest
5 голосов
/ 01 декабря 2009

Я пытаюсь написать реквизит, который изменяет судоку, а затем проверяет, все ли еще действует.

Однако я не уверен, как правильно использовать функцию «oneof». Можете ли вы дать мне несколько советов, пожалуйста?

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

Вот еще немного информации ...

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]

Я боролся с этой опорой уже 3 часа, поэтому любые идеи приветствуются!

Ответы [ 3 ]

5 голосов
/ 02 декабря 2009

То, на чем я ехал, - это то, что у вас смешанные шрифты. А именно, aBlank - это не Pos, а Gen Pos, поэтому update su aBlank aCandidate не имеет смысла! Фактически, то, что вы хотите, - это способ генерировать новую судоку с учетом первоначальной судоку; другими словами, функция

similarSudoku :: Sudoku -> Gen Sudoku

Теперь мы можем написать это:

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)

или даже проще:

similarSudoku su = liftM2 (update su) (elements (blanks su)) (elements (candidates su aBlank))

И свойство выглядит как

prop_similar :: Sudoku -> Gen Bool
prop_similar su = do newSu <- similarSudoku su
                     return (isSudoku newSu && isOkay newSu)

Так как есть экземпляры

Testable Bool
Testable prop => Testable (Gen prop)
(Arbitrary a, Show a, Testable prop) => Testable (a -> prop)

Sudoku -> Gen Bool равно Testable (при условии instance Arbitrary Sudoku).

2 голосов
/ 02 декабря 2009

В своем блоге я написал простой симулятор игры в кости с тестами QuickCheck, которые используют oneof для генерации интересных бросков.

Скажем, у нас есть супер-простая судоку из одного ряда:

module Main where
import Control.Monad
import Data.List
import Test.QuickCheck
import Debug.Trace

type Pos = Int
data Sudoku = Sudoku [Char] deriving (Show)

Никакое супер-простое судоку не должно иметь повторяющихся значений:

prop_noRepeats :: Sudoku -> Bool
prop_noRepeats s@(Sudoku xs) =
  trace (show s) $ all ((==1) . length) $
                   filter ((/='.') . head) $
                   group $ sort xs

Вы можете создать супер-простое судоку с

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)

trace здесь, чтобы показать случайно сгенерированные доски:

*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.
1 голос
/ 02 декабря 2009

кажется, что aBlank :: Gen Pos, что не соответствует тому, как оно используется в качестве аргумента candidates :: Sudoku -> Pos -> [Int].

Я просматривал здесь , чтобы найти способ конвертировать Gen a в a, который позволил бы вам использовать его с кандидатами. Лучшее, что я мог видеть - это функция generate.

Скажи мне, если я что-то упустил ...

...