0

I created my own myzipWith function and want to compare it with the original zipWith with the use of quickCheck.

myzipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
myzipWith a y [] = []
myzipWith a [] y = []
myzipWith a (x:xs) (z:zs) = [a x z] ++ myzipWith a xs zs

prop_zip x y z = myzipWith x y z == zipWith x y z  

When I run quickCheck by typing quickCheck prop_zip, it returns error:

<interactive>:69:1: error:
    * No instance for (Show (a0 -> b0 -> c0))
        arising from a use of `quickCheck'
        (maybe you haven't applied a function to enough arguments?)
    * In the expression: quickCheck prop_zip
      In an equation for `it': it = quickCheck prop_zip

<interactive>:69:12: error:
    * Ambiguous type variable `c0' arising from a use of `prop_zip'
      prevents the constraint `(Eq c0)' from being solved.
      Probable fix: use a type annotation to specify what `c0' should be.
      These potential instances exist:
        instance (Eq b, Eq a) => Eq (Either a b)
          -- Defined in `Data.Either'
        instance Eq Ordering -- Defined in `GHC.Classes'
        instance Eq Integer
          -- Defined in `integer-gmp-1.0.0.1:GHC.Integer.Type'
        ...plus 23 others
        ...plus 73 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    * In the first argument of `quickCheck', namely `prop_zip'
      In the expression: quickCheck prop_zip
      In an equation for `it': it = quickCheck prop_zip

What is the propblem here?

1 Answers1

2

There are two unrelated problems here:

  • The type is ambiguous. Hence Ambiguous type variable `c0'.
    Your function could be used as (Int -> Int -> Int) -> [Int] -> [Int] -> [Int], or just as well (Char -> Bool -> String) -> [Char] -> [Bool] -> [String] etc. etc.. It doesn't overly matter which of these you test, but you should pick one (if you don't, then even if it does work that may be due to defaulting to (), which is probably a bad idea because all () values are trivially equal, so your tests might not show up any bugs).

  • The first argument is a function. QuickCheck can generate functions automatically, but for a test case it also wants to show them, and that's generally not possible.
    The standard solution is to generate a Fun instead, and convert that using applyFun2 or Fn2. (Funnily enough, the documentation for these contains an example for zipWith...)

Another unrelated thing I would recommend is to use === for equality checking, not ==. The former will not only tell you whether or not your function gives the same result as the reference, but also which result it is in case it's different.

leftaroundabout
  • 117,950
  • 5
  • 174
  • 319
  • One ambiguity fix is to import `Test.QuickCheck.Poly` and use `A`, `B`, `C`, `OrdA`, `OrdB`, or `OrdC`. Alternatively, you can use Template Haskell stuff in `Test.QuickCheck.All`, *most* of which defaults polymorphic properties to `Integer`. – dfeuer Apr 22 '21 at 16:13