Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use quickcheck in main

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?

like image 411
matio2matio Avatar asked Feb 23 '23 05:02

matio2matio


2 Answers

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.

like image 76
hammar Avatar answered Feb 25 '23 19:02

hammar


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.

like image 36
Chris Smith Avatar answered Feb 25 '23 19:02

Chris Smith