简体   繁体   中英

Haskell: Understanding QuickCheck with higher order function

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM