[Haskell-cafe] Restricted type classes

Ivan Lazar Miljenovic ivan.miljenovic at gmail.com
Fri Sep 3 00:16:29 EDT 2010

When I released the first version of container-classes (which I hacked
on during AusHac), some people said I should split out the various
folding, etc. into duplicates of the current Foldable class, etc.
rather than having large monolithic classes.

I've been working on this (see my more recent email with the subject
along the lines of "fighting the type system"), and I think I've
worked out how to do this:

* Have one version of the class (when this makes sense) for values of kind *

* Have another version that's closer to the original class for kind *
-> *  but allowing restrictions (e.g. allowing Set to be an instance
of Functor).  This is based upon Ganesh Sittampalam's rmonad package

Rather than my original goal of forcing all kind * -> * values to be
instances of the kind * classes, my new approach is to write instances
that automatically make all instances of a * ->  * class to also be an
instance of the kind * class, and to use a newtype wrapper with a
phantom type value to allow lifting/promotion of a kind * value to a
kind * -> * value (e.g. "foo :: (Word8 -> Word8) -> ByteString ->
ByteString; foo f = unpromote . fmap f . Promote" is a valid usage,
rather than using the kind * function of rigidMap).

My goal with this is that if I have duplicated a class Foo to allow
restricted values, then it should be a drop-in replacement for the
original in terms of _usage_ (i.e. the class and method/function names
are the same, but the type signatures are not).  However, I would
appreciate the communities advice on a few matters:

1) How should I name the kind * versions?  For example, the kind *
version of Functor is currently called Mappable with a class method of
rigidMap.  What should I call the kind * version of Foldable and its
corresponding methods?  Is there a valid system I can use for these?

2) How far should I go?  Should I restrict myself to the
"data-oriented" classes such as Functor, Traversable, etc. or should I
try to make restricted versions of Applicative and Monad?  Assuming I

2a) Which namespace to use?  Should Monad go in Data.Restricted.Monad
to keep it in the same namespace as the other classes, or should I
make it closer to base with Control.Restricted.Monad?

2b) Is it OK to promote functions that use a class to being class
methods?  When I was discussing this in #haskell several people
mentioned that defining something like liftA2 for the Set instance of
(restricted) Applicative would make more sense than the default <*>
(since (a -> b) isnt' an instance of Ord).

2c) Should I keep the classes as-is, or should I explicitly put in the
constraints mentioned in the Typeclassopedia (e.g. make Applicative an
explicit superclass of Monad, and define return = pure for
compatability reasons)?  If so, should I bring over Pointed, etc. from
category-extras to round out the set or just stick with classes that
are already in base?

3) Am I wasting my time with this?

Ivan Lazar Miljenovic
Ivan.Miljenovic at gmail.com

More information about the Haskell-Cafe mailing list