I am writing a test for a binary search function I wrote.
module Tests where
import Data.List (sort)
import Test.QuickCheck
import BinarySearch (binarySearch)
prop_equals_elem x xs = (binarySearch x $ sort xs) == (x `elem` xs)
args = Args {replay = Nothing, maxSuccess = 200, maxDiscard=200, maxSize=200, chatty = False}
main = do
quickCheck (prop_equals_elem :: (Ord a) => a -> [a] -> Bool)
It works well using quickCheck in ghci but when I try to run main it gives the error
Tests.hs:12:5:
Ambiguous type variable `a0' in the constraints:
(Arbitrary a0) arising from a use of `quickCheckWith'
at Tests.hs:12:5-18
(Show a0) arising from a use of `quickCheckWith'
at Tests.hs:12:5-18
(Ord a0) arising from an expression type signature
at Tests.hs:12:26-72
Why does this not work in main but does in ghci?
This is likely caused by the extended defaulting rules in GHCi.
When testing a function like this, you need to use a concrete element type. GHCi will default the element type to ()
because of the extended rules, but this will not happen when compiling the code normally, so GHC is telling you that it cannot figure out which element type to use.
You can for example use Int
instead for the test. ()
is pretty useless for testing this function, as all elements would be the same.
quickCheck (prop_equals_elem :: Int -> [Int] -> Bool)
If it works for Int
, it should work for any type due to parametricity.
When you run a QuickCheck test, QuickCheck needs to know how to generate data. Here, you've told it only that your code should work with an arbitrary type of the Ord
type class, which isn't enough for it to start testing. Hence the error about ambiguous type classes.
If you just need an arbitrary Ord
instance, as it appears here, then something like Int
would be a good choice for your testing. It's a simple type with a linear order. So try fixing your type to Int
in main
, as in:
quickCheck (prop_equals_elem :: Int -> [Int] -> Bool)
As for why it works in GHCi, the answer is defaulting. GHCi defaults type variables to ()
whenever possible, just to avoid giving spurious errors in situations where you really don't care about a value. Actually that's an awful choice: you won't test anything interesting by only testing with the ()
type! So again, the explicit type signature is better.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With