1
votes

Is it good style to put the instance declarations for uncommon typeclasses in extra modules?

As an example I have this simple tree type:

module Data.Tree where

data Tree a = Leaf a
            | Node (Tree a) (Tree a)

Suppose I want to use QuickCheck's Arbitrary typeclass to generate random values of type Tree (and be able to use them not only in tests).

What is best? To put them in the same module where Tree is defined

module Data.Tree where

import QuickCheck.Arbitrary

data Tree a = ...

instance Arbitrary a => Arbitrary (Tree a) where
    ...

or to outsource the instance declaration to another module to avoid the dependency to QuickCheck.Arbitrary in Data.Tree

module Data.Tree.Arbitrary where

import Data.Tree
import QuickCheck.Arbitrary

instance Arbitrary a => Arbitrary (Tree a) where
    ...

or something else entirely?

1

1 Answers

3
votes

It's generally a good idea to avoid orphan instances: those are always good for surprises, and rather hard to find.

So, yes, put the instance in the module where Tree is defined. This blows up the module a bit, but it shouldn't really be an issue. Of the total build time of the whole package it shouldn't matter much if you have one larger module or two smaller ones.

When you can completely avoid a package dependency, this might make an orphan instance worthwhile, because installing a package is obviously a much greater performance issue than importing a module from an installed package.