如何使用“oneof”在快速检查(Haskell)中

发布于 2024-08-12 15:10:52 字数 691 浏览 3 评论 0原文

我正在尝试编写一个更改数独的道具,然后检查它是否仍然有效。

但是,我不确定如何正确使用“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 个小时,所以欢迎任何想法!

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

寄人书 2024-08-19 15:10:52

我的意思是你的类型混淆了。也就是说,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 也是可测试(假设实例任意数独)。

What I was driving at is that you have a type mix-up. Namely, aBlank is not a Pos, but a Gen Pos, so update 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 function

similarSudoku :: 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 is Testable as well (assuming instance Arbitrary Sudoku).

谜兔 2024-08-19 15:10:52

在我的博客上,我编写了一个简单的双骰子模拟器,其中包含 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

您可以使用 trace 生成一个超级简单的数独

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)

,以显示随机生成的棋盘:

*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.

On my blog, I wrote a simple craps simulator with QuickCheck tests that use oneof to generate interesting rolls.

Say we have a super-simple 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 super-simple 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 super-simple 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.
踏月而来 2024-08-19 15:10:52

似乎 aBlank :: Gen Pos 与用作 candidates :: Sudoku -> 的参数的方式不匹配位置 -> [整数]

我一直在此处查找转换方法Gen aa 这将允许您将其与候选人一起使用。我能看到的最好的是 generate 函数。

告诉我我是否遗漏了什么...

it seems that aBlank :: Gen Pos which does not match the way it is used as an argument of candidates :: Sudoku -> Pos -> [Int].

I've been looking through here to find a way to convert Gen a to a which would allow you to use it with candidates. The best i could see is the generate function.

Tell me if I'm missing something...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文