为什么快速检查通过这两个不同的函数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.