如何使用QuickCheck生成任意两个参数函数?

时间:2017-09-02 17:43:50

标签: haskell quickcheck

我正在尝试使用QuickCheck测试zipWith的实现。我的实现myZipWith,我希望通过与标准函数进行比较来进行QuickCheck测试。类似的东西:

main = do
  quickCheck (prop_myZipWith :: (Int -> Int -> Int) -> [Int] -> [Int] -> Bool)

prop_myZipWith :: (a -> b -> c) -> [a] -> [b] -> Bool
prop_myZipWith f x y = (myZipWith x y) == (zipWith f x y)

这不起作用,因为(Int -> Int -> Int)不是Arbitrary的实例。

使用单参数函数,可以使用Test.QuickCheck.Function' s Fun(实例化Arbitrary)来解决这个问题。例如:

main = do
  quickCheck (prop_myMap :: Fun Int Int -> [Int] -> Bool)

prop_myMap :: Fun a b -> [a] -> Bool
prop_myMap (Fun _ f) l = (myMap f l) == (map f l)

我正在尝试做类似的事情,除了生成两个 -argument任意函数。

如何生成两个参数函数的任意实例,以便对zipWith等高阶函数进行QuickCheck测试?

1 个答案:

答案 0 :(得分:4)

QuickCheck 2.9.2

使用QuickCheck 2.9.2,您可以使用Fun类型和Fn模式。你必须

import Test.QuickCheck.Function

然后,您可以使用元组作为输入来编写属性,然后使用curry函数:

prop_myZipWith :: Eq c => Fun (a, b) c -> [a] -> [b] -> Bool
prop_myZipWith (Fn f) x y = myZipWith (curry f) x y == zipWith (curry f) x y

main看起来像这样:

main =
  quickCheck (prop_myZipWith :: Fun (Int, Int) Int -> [Int] -> [Int] -> Bool)

这个编译,测试通过,在我的repro。

QuickCheck 2.10.0.1

使用QuickCheck 2.10.0.1,您可以使用Fn2模式,如下所示:

prop_myZipWith :: Eq c => Fun (a, b) c -> [a] -> [b] -> Bool
prop_myZipWith (Fn2 f) x y = myZipWith f x y == zipWith f x y

主要方法保持不变,因为prop_myZipWith的类型没有改变,但不再需要import Test.QuickCheck.Function