2009-12-01 172 views
5

我正在嘗試編寫一個改變Sudoku的道具,然後檢查它是否仍然有效。如何在quickCheck(Haskell)中使用'oneof'

但是,我不知道如何正確使用「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] 

我現在這個道具struggeled 3小時,所以任何想法,歡迎!

+0

那麼,'update'的類型是什麼?你認爲'aCandidate'和'aBlank'的類型是什麼? – 2009-12-01 21:51:29

+0

我編輯了這篇文章,你能再看看嗎? – Mickel 2009-12-01 21:56:17

+0

現在,檢查'[return x |的類型是什麼x < - (blanks su)]'因此是'aBlank'。 – 2009-12-01 22:08:13

回答

5

我開車的是你有一個類型混淆。即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 BoolTestable以及(假設instance Arbitrary Sudoku)。

+0

也沒有真正的工作,但它是非常有用的,所以我會接受它作爲答案。 – Mickel 2009-12-06 09:56:46

2

在我的博客上,我寫了一個simple craps simulator與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 [email protected](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是有顯示隨機產生的野豬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

似乎aBlank :: Gen Pos不被用作candidates :: Sudoku -> Pos -> [Int]參數的方法相匹配。

我一直在尋找通過here尋找一種方法來將Gen a轉換爲a這將允許您與候選人一起使用它。我能看到的最好的是generate函數。

告訴我,如果我失去了一些東西......

+0

嗯,是的。你不需要將'Gen a'轉換爲'a';你想要「提升」候選人。 – 2009-12-02 07:44:40

+0

當然還有其他的功能。 – 2009-12-02 07:48:39

+0

是有道理的。去monadic是解決方案。 – barkmadley 2009-12-02 09:23:02