haskell - 在 QuickCheck 中使用自定义生成器与任意实例

标签 haskell quickcheck

这是一个简单的函数。它需要一个输入 Int并返回一个(可能是空的)列表 (Int, Int)对,其中输入 Int是任何对的立方元素的总和。

cubeDecomposition :: Int -> [(Int, Int)]
cubeDecomposition n = [(x, y) | x <- [1..m], y <- [x..m], x^3 + y^3 == n] 
  where m = truncate $ fromIntegral n ** (1/3)

-- cubeDecomposition 1729
-- [(1,12),(9,10)]

我想测试上述内容为真的属性;如果我对每个元素进行立方并将任何返回元组求和,那么我会得到我的输入:
import Control.Arrow 

cubedElementsSumToN :: Int -> Bool
cubedElementsSumToN n = all (== n) d
    where d = map (uncurry (+) . ((^3) *** (^3))) (cubeDecomposition n)

出于运行时的考虑,我想限制输入 Int当使用 QuickCheck 测试时,s 到一定大小。我可以定义一个合适的类型和 Arbitrary实例:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

import Test.QuickCheck

newtype SmallInt = SmallInt Int
    deriving (Show, Eq, Enum, Ord, Num, Real, Integral)

instance Arbitrary SmallInt where
    arbitrary = fmap SmallInt (choose (-10000000, 10000000))

然后我想我必须定义使用 SmallInt 的函数和属性的版本而不是 Int :
cubeDecompositionQC :: SmallInt -> [(SmallInt, SmallInt)]
cubeDecompositionQC n = [(x, y) | x <- [1..m], y <- [x..m], x^3 + y^3 == n] 
  where m = truncate $ fromIntegral n ** (1/3)

cubedElementsSumToN' :: SmallInt -> Bool
cubedElementsSumToN' n = all (== n) d
    where d = map (uncurry (+) . ((^3) *** (^3))) (cubeDecompositionQC n)

-- cubeDecompositionQC 1729
-- [(SmallInt 1,SmallInt 12),(SmallInt 9,SmallInt 10)]

这工作正常,标准的 100 次测试按预期通过。但是当我真正需要的只是一个自定义生成器时,似乎没有必要定义新的类型、实例和函数。所以我试过这个:
smallInts :: Gen Int
smallInts = choose (-10000000, 10000000)

cubedElementsSumToN'' :: Int -> Property
cubedElementsSumToN'' n = forAll smallInts $ \m -> all (== n) (d m)
    where d =   map (uncurry (+) . ((^3) *** (^3)))
              . cubeDecomposition

现在,我运行它的前几次,一切正常,并且所有测试都通过了。但是在随后的运行中,我观察到了失败。可靠地增加测试大小可以找到一个:
*** Failed! Falsifiable (after 674 tests and 1 shrink):  
0
8205379

由于从 QuickCheck 返回的两个缩小的输入 - 0 和 8205379 的存在,我在这里有点困惑,我直觉上希望有一个。此外,这些输入按预期工作(至少在我的可展示属性(property)上):
*Main> cubedElementsSumToN 0
True
*Main> cubedElementsSumToN 8205379
True

因此,使用自定义 Gen 的属性显然存在问题。我定义。

我做错了什么?

最佳答案

我很快意识到我所写的属性(property)显然是不正确的。这是正确的方法,使用原始 cubedElementsSumToN属性(property):

quickCheck (forAll smallInts cubedElementsSumToN)

读起来很自然。

关于haskell - 在 QuickCheck 中使用自定义生成器与任意实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13354726/

相关文章:

haskell - 使用 `ghc -e` 运行 Haskell 代码时是否可以传递命令行参数?

haskell - 在 Haskell 中实现一个高效的滑动窗口算法

haskell - 如何实现 index-core 风格的索引状态单子(monad)?

postgresql - Yesod persistent-postgresql rawSql 查询与列列表通配符产生语法错误

scala - Scala 和 Frege 之间的主要区别(在编程范式中)是什么?

haskell - 如何使我的类型成为 Arbitrary 的实例?

scala - 在 ScalaCheck 中从语法生成字符串

haskell - 如何正确限制 `arbitrary` UUID生成?

haskell - 使用 QuickCheck 为给定函数生成多个任意参数

javascript - 快速检查 Javascript