为什么快速检查通过这两个不同的函数Haskell?

我有两个功能。他们是:

f1 [] = []
f1 (x:xs) = if contains x xs then f1 xs else x:f1 xs

f6 xs = f1 (rev xs)

除了空列表和任何具有一个元素的列表之外,这两个函数返回相同的列表是没有意义的,但是在此函数上运行 quickcheck 时:

prop_sort6 xs = (f1 xs == f6 xs) == True

所有的测试都通过了。为什么会这样?

编辑:

例如这样做:(f1 [1,2,3] == f6 [1, 2, 3])显然会导致 False,但 quickcheck 仍然通过。

回答

我们可以使用verboseCheck而不是进行一些调查quickCheck

*Main Test.QuickCheck> verboseCheck prop_sort6
Passed:
[]

Passed:
[]

Passed:
[(),()]

Passed:
[(),()]

Passed:
[(),(),(),()]

... (you get the picture) ...

quickCheck(并且verboseCheck,出于同样的原因)具有签名

quickCheck :: Testable prop => prop -> IO ()

现在,我们可以沿着兔子洞往下看是什么Testable,但最重要的是,无论prop是什么,它在运行时都必须是单态的。也就是说,它不能有任何令人讨厌的挥之不去的类型变量。现在,prop_sort6推断出的类型是

prop_sort6 :: Eq a => [a] -> Bool

所以我们需要一个a满足Eq. 对于大多数类型类,这将是一个模棱两可的类型错误。如果我们写了以下内容,

class Foo a

myProp :: Foo a => a -> Bool
myProp _ = True

然后quickCheck myProp产生

<interactive>:29:1: error:
    • Ambiguous type variable ‘a0’ arising from a use of ‘quickCheck’
      prevents the constraint ‘(Arbitrary a0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘a0’ should be.
      These potential instances exist:
        instance (Arbitrary a, Arbitrary b) => Arbitrary (Either a b)
          -- Defined in ‘Test.QuickCheck.Arbitrary’
        instance Arbitrary Ordering
          -- Defined in ‘Test.QuickCheck.Arbitrary’
        instance Arbitrary Integer
          -- Defined in ‘Test.QuickCheck.Arbitrary’
        ...plus 19 others
        ...plus 61 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the expression: quickCheck myProp
      In an equation for ‘it’: it = quickCheck myProp

<interactive>:29:12: error:
    • No instance for (Foo a0) arising from a use of ‘myProp’
    • In the first argument of ‘quickCheck’, namely ‘myProp’
      In the expression: quickCheck myProp
      In an equation for ‘it’: it = quickCheck myProp

不过,Eq很特别。在 GHCi 中(并且在 GHCi 中),Eq具有类型默认规则,因此在没有任何附加信息的情况下,Eq a将假定为Eq ()(单位类型)。这仅适用于 GHCi。如果我们创建一个main调用的函数quickCheck,这是一个模棱两可的类型错误。但是,在 GHCi 中,它默认为()

现在,当然,()只有一个实例,所以我们最终只用()一遍又一遍的列表测试该函数,并且由于您的两个函数将始终生成相同长度的列表,因此测试通过。您可能想改为运行它Int

*Main Test.QuickCheck> quickCheck (prop_sort6 :: [Int] -> Bool)
*** Failed! Falsified (after 5 tests and 1 shrink):
[0,1]

请注意,编译器标志-Wtype-defaults(由 启用-Wall)将警告您有关类型默认值的信息,并让您知道出现了问题。随着-Wtype-defaults活动:

*Main Test.QuickCheck> quickCheck prop_sort6

<interactive>:11:1: warning: [-Wtype-defaults]
    • Defaulting the following constraints to type ‘()’
        (Arbitrary a0)
          arising from a use of ‘quickCheck’ at <interactive>:11:1-21
        (Show a0)
          arising from a use of ‘quickCheck’ at <interactive>:11:1-21
        (Eq a0)
          arising from a use of ‘prop_sort6’ at <interactive>:11:12-21
    • In the first argument of ‘GHC.GHCi.ghciStepIO ::
                                  forall a. IO a -> IO a’, namely
        ‘(quickCheck prop_sort6)’
      In a stmt of an interactive GHCi command:
        it <- GHC.GHCi.ghciStepIO :: forall a. IO a -> IO a
              (quickCheck prop_sort6)
+++ OK, passed 100 tests.


以上是为什么快速检查通过这两个不同的函数Haskell?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>