Haskell:了解具有高阶功能的QuickCheck

时间:2019-06-28 10:31:57

标签: haskell functional-programming quickcheck property-based-testing

我具有函数foo

foo :: [a] -> (a -> b) -> [b]
foo [] f = []
foo (x:xs) f = foo xs f

以及它必须满足的以下两个属性:

prop_1 :: [Int] -> Bool
prop_1 xs = foo xs id == xs 

prop_2 :: [Int] -> (Int -> Int) -> (Int -> Int) -> Bool
prop_2 xs f g = foo (foo xs f) g == foo xs (g . f)

当我尝试使用quickCheck测试功能时,出现以下错误:

 Ambiguous type variable 't0' arising from a use of '=='
      prevents the constraint '(Eq t0)' from being solved.
      Probable fix: use a type annotation to specify what 't0' should be.
      These potential instances exist:
        instance (Eq a, Eq b) => Eq (Either a b)
          -- Defined in 'Data.Either'
        instance Eq GeneralCategory -- Defined in 'GHC.Unicode'
        instance Eq Ordering -- Defined in 'ghc-prim-0.5.0.0:GHC.Classes'
        ...plus 24 others
        ...plus 107 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
      In the expression: foo (foo xs f) g == foo xs (g . f)
      In an equation for 'prop_2':
          prop_2 xs f g = foo (foo xs f) g == foo xs (g . f)
Failed, modules loaded: none.

我不确定为什么会收到此错误以及如何解决该错误。任何见解都会受到赞赏。

1 个答案:

答案 0 :(得分:1)

我能够使用以下程序复制您的错误消息。请注意,foo的签名已被注释掉:

import Test.QuickCheck
import Text.Show.Functions

-- foo :: [a] -> (a -> b) -> [b]
foo [] f = []
foo (x:xs) f = foo xs f

prop_1 :: [Int] -> Bool
prop_1 xs = foo xs id == xs

prop_2 :: [Int] -> (Int -> Int) -> (Int -> Int) -> Bool
prop_2 xs f g = foo (foo xs f) g == foo xs (g . f)

main = do
  quickCheck prop_1
  quickCheck prop_2

如果我重新插入foo签名,它会进行类型检查。测试当然会失败,因为foo并未按照您的意图进行。

问题在于您在此处使用的foo版本具有推断的签名:

foo :: [a] -> b -> [c]

因此,在prop_2中,无法推断出最前面的foo调用的列表元素的类型来解析正确的(==)操作。

如果将foo替换为正确的版本:

foo :: [a] -> (a -> b) -> [b]
foo [] f = []
foo (x:xs) f = f x : foo xs f

然后测试通过 ,实际上您可以再次注释掉签名,因为可以推断出正确的类型。