[Haskell-cafe] Type constraints and classes

Neil Brown nccb2 at kent.ac.uk
Sun Apr 26 07:21:21 EDT 2009


Hi,

I have a Haskell problem that keeps cropping up and I wondered if there 
was any solution/work-around/dirty-hack that could help.  I keep wanting 
to define class instances for things like Functor or Monad, but with 
restrictions on the inner type.  I'll explain with an example, because I 
find explaining this in words a bit difficult.  Let's say I want to 
create a Monad instance for Set akin to that for lists:

==
import Data.Set
import Prelude hiding (map)

instance Monad Set where
  return = singleton
  m >>= f = fold union empty (map f m)

-- Error: Could not deduce (Ord a, Ord b) from the context (Monad Set)
==

Everything fits (I think) -- except the type-class constraints.  
Obviously my Monad instance won't work if you have things inside the set 
that aren't Ord, but I can't work out how to define a restricted 
instance that only exists for types that have Ord instances.  I can't 
express the constraint on the instance because the a and b types of 
return and >>= aren't visible in the class header.  Shifting the 
constraint to be present in the type doesn't seem to help either (e.g. 
newtype Ord a => MySet a = MySet (Set a)...).

Is there any way to get such instances as the one for Set working?  I 
cannot carry around a compare function myself in a data type that wraps 
Set, because return cannot create such functions without the original 
type-class instance.  I don't actually need a Monad for Set, but it 
neatly demonstrates my problem of wanting constraints on the type inside 
a Monad (or a Functor, or an Applicative, etc).

I worked around a similar problem with Functor by opting for a new 
Functor-like type-class with the constraints, but doing that with Monad 
rules out using all the monad helper functions (liftM, mapM, etc), and 
the do notation, which would be a step too far.  All suggestions are 
welcome, no matter how hacky, or how many GHC extensions are required 
:-) (provided they don't break all the other monads, e.g. redefining the 
signature of Monad).

Thanks,

Neil.


More information about the Haskell-Cafe mailing list