2009-12-01 12 views
5

Sto provando a scrivere un supporto che cambia un Sudoku e poi controlla se è ancora valido.Come utilizzare "oneof" in quickCheck (Haskell)

Tuttavia, non sono sicuro di come utilizzare correttamente la funzione "oneof". Puoi darmi qualche suggerimento, per favore?

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

Qui ci sono alcuni più informazioni ...

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] 

ho struggeled con questo puntello per 3 ore, in modo che tutte le idee sono i benvenuti!

+0

Bene, qual è il tipo di "aggiornamento"?E cosa pensi che saranno i tipi di "aCandidate" e "aBlank"? –

+0

Ho modificato il post, puoi dare un'occhiata di nuovo? – Mickel

+0

Ora, controlla quale è il tipo di '[return x | x <- (blanks su)] 'e quindi di' aBlank'. –

risposta

5

Quello che stavo guidando a è che avete un tipo di mix-up. Vale a dire, aBlank non è un Pos, ma uno Gen Pos, quindi update su aBlank aCandidate non ha senso! In realtà, quello che vuoi è un modo per generare un nuovo sudoku dato un sudoku iniziale; in altre parole una funzione

similarSudoku :: Sudoku -> Gen Sudoku 

Ora possiamo scrivere:

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) 

o ancora più semplice:

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

e la proprietà si presenta come

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

Dal momento che ci sono istanze

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

Sudoku -> Gen Bool è Testable così (supponendo instance Arbitrary Sudoku).

+0

Non funziona davvero, ma è stato molto utile quindi accetterò come risposta. – Mickel

2

Sul mio blog, ho scritto un simple craps simulator con test QuickCheck che utilizza oneof per generare rotoli interessanti.

Dire che abbiamo un super-semplice Sudoku di una singola riga:

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

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

Nessun super-Simple Sudoku avrebbe dovuto ripetuti:

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

si potrebbe generare un super-semplice Sudoku con

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) 

il trace è lì per mostrare il cinghiale generata casualmente ds:

*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

sembra che aBlank :: Gen Pos, che non corrisponde al modo in cui viene utilizzato come argomento di candidates :: Sudoku -> Pos -> [Int].

Ho cercato tramite here di trovare un modo per convertire Gen a in a che consentirebbe di utilizzarlo con i candidati. Il meglio che ho potuto vedere è la funzione generate.

Dimmi se mi manca qualcosa ...

+0

Beh, sì. Non vuoi _want_ convertire un 'Gen a' in' a'; vuoi "sollevare" i "candidati" invece. –

+0

E le altre funzioni coinvolte, ovviamente. –

+0

ha senso. andare monadico è la soluzione. – barkmadley