0

I have the function foo:

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

And the following two properties that it must satisfy:

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)

When I tried to test the function using quickCheck, I get the following error:

 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.

I am not sure why I am getting this error and how I can solve it. Any insights are appreciated.

ceno980
  • 2,003
  • 1
  • 19
  • 37
  • DId you wrote the `prop_2` in the *shell*? Did you use `:{` and `:}` to write both the signature and the function in the same "block"? – Willem Van Onsem Jun 28 '19 at 10:38
  • No, I had prop_2 in a file with prop_1 and foo. – ceno980 Jun 28 '19 at 10:43
  • It looks as if Haskell is not able to understand the type of `foo xs (g . f)`, so that usually means the type signatures are not saying it is an `[Int]` here. – Willem Van Onsem Jun 28 '19 at 10:49
  • Can you share a compilable example to reproduce the problem? – Li-yao Xia Jun 28 '19 at 11:32
  • 2
    I tried compiling and running your properties. I couldn't reproduce your error message, but I found two other issues: Firstly, your function `foo` is equivalent to `const []`, so your first property will always fail. Secondly, `prop_2` can't be run by `quickCheck` because there is no `Show (Int -> Int)` instance (`quickCheck` requires this so it can print counter examples) – sara Jun 28 '19 at 11:38
  • @sara: the second issue was covered in the previous question: https://stackoverflow.com/questions/56805030/haskell-property-based-testing-for-higher-order-function – Willem Van Onsem Jun 28 '19 at 11:45

1 Answers1

1

I was able to duplicate your error message with the following program. Note that the signature for foo is commented out:

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

If I put the foo signature back in, it type-checks fine. The tests fail of course, since foo isn't doing what you intend it to do.

The issue is that the version of foo you have here has inferred signature:

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

so in prop_2, the type of the list elements for the top-most foo calls can't be inferred to resolve the correct (==) operation.

If you replace foo with a correct version:

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

then the tests pass and you can actually comment out the signature again because the correct type can be inferred.

K. A. Buhr
  • 45,621
  • 3
  • 45
  • 71