specdrake
specdrake

Reputation: 84

No instance of Arbitrary despite defining one while using checkers to test Monoid laws

I was reading the Haskellbook and trying to test Monoid laws for a Monoid instance for a simple Bool like data type using the checkers library. But when I try to load the code in ghci, I get the following error:

BadMonoid.hs:21:20: error:
    • No instance for (QuickCheck-2.14:Test.QuickCheck.Arbitrary.Arbitrary
                         Bull)
        arising from a use of ‘monoid’
    • In the first argument of ‘quickBatch’, namely ‘(monoid Twoo)’
      In the expression: quickBatch (monoid Twoo)
      In an equation for ‘main’: main = quickBatch (monoid Twoo)
   |
21 | main = quickBatch (monoid Twoo)
   |                    ^^^^^^^^^^^
Failed, no modules loaded.

Though, I have defined an Arbitrary instance for my data type Bull. I have searched on the Internet and Stack Overflow and found a related post. I have tried the solution given there(using GHC.Generics) but it results in the same error. Here is the code:

module BadMonoid where
import Data.Monoid
import Test.QuickCheck
import Test.QuickCheck.Checkers
import Test.QuickCheck.Classes

data Bull = Fools | Twoo deriving (Eq, Show)

instance Arbitrary Bull where
  arbitrary = frequency [(1, return Fools), (1, return Twoo)]

instance Monoid Bull where
  mempty = Fools

instance Semigroup Bull where
  (<>) _ _ = Fools

instance EqProp Bull where (=-=) = eq

main :: IO ()
main = quickBatch (monoid Twoo)

Upvotes: 2

Views: 206

Answers (1)

Lambda Fairy
Lambda Fairy

Reputation: 14676

The issue is that there are two incompatible versions of QuickCheck installed. We can tell from the error message, as it mentions the version (QuickCheck-2.14) in the type:

    • No instance for (QuickCheck-2.14:Test.QuickCheck.Arbitrary.Arbitrary
                         Bull)

As Daniel mentioned, the solution is to create a Cabal project that depends on QuickCheck and checkers, and use Cabal commands (e.g. cabal repl) instead of GHC directly.


By default, GHC can see every version of every package that's installed on the machine. But it doesn't know how to choose between them. If run on its own, it will pick whatever package versions it finds first – which may not consistent with each other.

Enter Cabal. The primary feature of Cabal is its solver: it can select a consistent set of packages, and tell GHC to only use those packages. That's why creating a Cabal project fixes the issue.

In general, it is an antipattern to run cabal install --lib. (Installing executables is okay, as they're self-contained.) If you need to install libraries from Hackage, create a Cabal project which depends on the library.

Upvotes: 3

Related Questions