9

Consider the following tests for the distributivity law between reverse and ++,

import Test.QuickCheck

test :: [Int] -> [Int] -> Bool
test xs ys = reverse (xs ++ ys) == reverse xs ++ reverse ys

test2 :: (Eq a) => [a] -> [a] -> Bool
test2 xs ys = reverse (xs ++ ys) == reverse xs ++ reverse ys

Note for lists of Int that

*Main> quickCheck test
*** Failed! Falsifiable (after 5 tests and 3 shrinks):    
[1]
[0]

However the test for lists of equatable items,

*Main> quickCheck test2
+++ OK, passed 100 tests.

What makes the second test pass ?

Update On compiling with main = quickCheck test2, the subsequent error on ambiguous type variable hints the problem (as already depicted in answers),

No instance for (Eq a0) arising from a use of `test2'
The type variable `a0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
elm
  • 20,117
  • 14
  • 67
  • 113

2 Answers2

14

When you actually evaluate test2, GHCi has to pick a type a to use. Without more information, GHCi's extended default rules make it default to (), for which the law is true.

Ørjan Johansen
  • 18,119
  • 3
  • 43
  • 53
13
> verboseCheck test2 

Passed:
[]
[]
Passed:
[]
[]
Passed:
[(),()]
[()]
Passed:
[(),(),()]
[()]
Passed:
[()]
[(),(),(),()]
...

The polymorphic parameter defaults to (), and of course all such values are equal.

András Kovács
  • 29,931
  • 3
  • 53
  • 99