Proposal: Bounded instance for IntSet (ticket #1953)

Henning Thielemann lemming at henning-thielemann.de
Mon Dec 3 08:58:45 EST 2007


On Mon, 3 Dec 2007, Yitzchak Gale wrote:

> Henning Thielemann wrote:
> > ...it is not sensible to have different instances for the same
> > type and class, because they will collide sooner or later.
>
> True. That is why libraries should not define an instance
> at all, unless they are quite certain that it is by far the most
> important instance that anyone will ever want to use.
>
> Here is an example: Control.Monad.Error defines a Monad
> instance for Either. I understand why that seemed sensible
> at the time. But the Either type is useful for many other things,
> too, and now it can *only* be used as an exception type in
> a monadic setting. If I had to pick just one usage for Either
> as a monad, it would be as an exit monad. I would use a
> different name for the exception monad, not the other way
> around. But now I'm stuck - if I want to use Control.Monad.Error
> at all, I have to use its crippled monad instance for Either.

I think the problem here is, that library designers wanted to save work by
(ab)using Either for errors. They should have defined an Error type which
shares similarities with Either but is a distinct type and its occurence
tells the reader that it is not about arbitrary alternatives but about
error handling.

What concerns instances - after I managed to understand the "orphan
instance" warnings of GHC I learnt to like GHC's rule of warning about
instances: Instances should be defined in the module where the class or
the instance type is defined.
 If I import a standard type and a standard class with a natural instance
declaration I expect that this instance already exists.

E.g. in GHCi-6.4.1

Prelude> Test.QuickCheck.test (\xl yl -> let x = Data.Set.fromList (xl::[Int]); y = Data.Set.fromList yl in Data.Set.union x y == Data.Set.union y x)
Loading package QuickCheck-1.0 ... linking ... done.
OK, passed 100 tests.


This small example already uses several predefined instance:
  Ord instance for Int,
  Eq instance for Data.Set.Set,
  Arbitrary for Int and List,
  Show instances for them.

The first two are rather straightforward, the second two are a somehow
arbitrary, although useful.

Of course I like to write

Prelude> Test.QuickCheck.test (\x y -> Data.Set.union x y == Data.Set.union y (x::Data.Set.Set Int))

but

<interactive>:1:0:
    No instance for (Test.QuickCheck.Arbitrary (Data.Set.Set Int))
      arising from use of `Test.QuickCheck.test' at <interactive>:1:0-19
    Probable fix:
      add an instance declaration for (Test.QuickCheck.Arbitrary (Data.Set.Set Int))
    In the definition of `it':
        it = Test.QuickCheck.test (\ x y
                                       -> (Data.Set.union x y) == (Data.Set.union y (x :: Data.Set.Set Int)))


But I think, since List is an instance of Arbitrary, Set can also be one,
based on the List instance.


More information about the Libraries mailing list