
From: Ivan Lazar Miljenovic
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 (http://hackage.haskell.org/package/rmonad).
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?
You could prefix (or postfix) classes with an 'R' similar to RMonad, but that would conflict with the rmonad package. For just Foldable, maybe Reduceable? Do you have a kind * implementation of Foldable? I'd be interested in seeing it, because I was unable to create a usable implementation (based upon the RMonad scheme) on my last attempt.
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 should:
I don't have a strong opinion either way, but could you re-use RMonad and RFunctor from the rmonad package?
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?
+1 for using the proper constraints, and especially for bringing over Pointed (and anything else that applies).
3) Am I wasting my time with this?
I would find it useful, and I appreciate all the care you're putting into the design. Cheers, John