[Haskell-cafe] programming style...and type classes...
Tobias Dammers
tdammers at gmail.com
Fri Nov 4 15:10:10 UTC 2016
On Fri, Nov 04, 2016 at 02:06:18PM +0000, Nicholls, Mark wrote:
> >Subject: Re: [Haskell-cafe] programming style...and type classes...
> >
> >My rule of thumb is that if there is one obvious instance (or none) for every
> >given type, then your abstraction is a good candidate for a typeclass; if multiple
> >instances make sense, then it's a judgment call; and if many instances could
> >arbitrarily make sense or not depending on the usage / circumstances, then it's
> >probably not a good candidate for a typeclass.
>
> OK, that’s a bit more prescriptive...so if many instances make sense (Ord a) then what?
>
> Seems like Ord is a "bad" typeclass?...it should really be a dictionary data type? And then you simply define which order you want?
Ord is a "bad" typeclass if you interpret it as "the ordering rules for
this type"; but it is OK if you interpret it as "the default ordering
rules for this type". Which, arguably, makes more sense for some types
(Int) and less for others (Text). However, in the case of Ord, there is
little harm in defining a default instance and using more specialized
sorting functions that take an explicit ordering functions; this stuff
is simple enough for these things to not be very intrusive at all, and
giving arguable cases the benefit of the doubt, I guess, is considered
pragmatic.
>
> There needs to be 1 (or 0) instances because this is all resolved
> compile time?....i.e. so we (the programmer/compiler) need a function
> from types, and function name into instances...if there 0
> instance...then boom...not defined..so you need to do something,
> that’s fixable....if 2...then boom...you're in trouble?
Sort of, yes. You can't have two instances of the same typeclass for the
same type. However, because instances are always global, and can be
defined separately from both the type and the typeclass, it is possible
to write instances which, when imported, break the code that imports
them by introducing conflicting instances. This is why the
recommendation is to always define instances either in the module that
defines the type, or the module that defines the typeclass. Instances
that are defined separately from both are called "orphan instances", and
people generally avoid them where possible, but occasionally practical
concerns make them necessary. The most common reason for orphan
instances is to avoid dependencies: suppose you write a library that
defines an alternative string type; and someone else writes a library
that defines useful typeclasses for string-like types. Ideally, you want
your custom string type to have instances for those typeclasses, but you
can't put them in the typeclass library (because you don't control it),
and you don't want to put them in your own library, because then your
own library has to depend on the typeclass library even though most
people won't need that functionality. In such a situation, you'd bite
the bullet and provide an extra library that contains just the
instances, peppered with warnings about orphan instances. Another
example is when you write a program that uses types from some
third-party library, and wants to marshal them to and from JSON - for
that to work, you need to implement ToJSON and FromJSON instances for
those types, but since you control neither the type nor the JSON
typeclasses, the only choice you have is to make orphan instances in
your program. In that case, the damage is limited, because you won't
expose the orphan instances to the outside world, so it's sort of
acceptable usually.
More information about the Haskell-Cafe
mailing list