簡體   English   中英

為什么快速檢查這兩個不同的功能 Haskell 會通過?

[英]Why does quickcheck pass for these two different functions Haskell?

我有兩個功能。 他們是:

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

f6 xs = f1 (rev xs)

除了空列表和任何具有一個元素的列表之外,這兩個函數返回相同的列表是沒有意義的,但是在此 function 上運行快速檢查時:

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 中是正確的。 如果我們創建一個調用quickCheckmain function ,這是一個模棱兩可的類型錯誤。 但是,在 GHCi 中,它默認為()

現在,當然, ()只有一個實例,所以我們只用()列表一遍又一遍地測試 function,並且由於您的兩個函數將始終生成相同長度的列表,因此測試通過了。 您可能想在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.

指定您的 function 應在例如整數列表上進行測試:

prop_sort6 :: [Int] -> Bool
prop_sort6 xs = (f1 xs == f6 xs) == True

如果您不指定類型,QuickCheck 會將[a]填寫為[()]並且[(), (), (), (), (), ...]不會在您的案例中發現任何錯誤.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM