
From: Jan-Willem Maessen
Sent: Wed, March 23, 2011 8:43:14 PM
Hi all -
I've been trying to construct a class declaration with an associated type synonym, but I'd like to constrain that type to belong to a particular class.
Consider the following class:
class Monoid m => Constructs c m | c -> m where construct :: m -> c
This captures the idea that the collection c ought to be constructed using the monoid m (say if we're doing the construction using the Writer monad)--the functional dependency indicates the desire for the type c to injectively determine the choice of monoid m. For example:
newtype ListBuilder a = Builder ([a] -> [a]) deriving (Monoid)
instance Constructs [a] (ListBuilder a) where construct (Builder f) = f []
instance (Ord a) => Constructs (Set a) (Set a) where construct = id
Now I'd like to be able to do the same thing using an associated type synonym, something like this:
type GeneratorOf a :: * -> * construct :: GeneratorOf a -> a
Now, it seems I need FlexibleInstances to do this when I'm using an associated type synonym, but I don't need the flexibility when using a multiparameter type class.
The conditions in the report are quite restrictive - in particular, the context must consist only of classes applied to type variables. When you used a multiparameter type class and an FD, the type you wanted to mention was just a type variable. http://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-750004.3 The GHC user's guide suggests FlexibleContexts should be enough to allow you to declare that class: http://www.haskell.org/ghc/docs/7.0-latest/html/users_guide/type-class-exten... FlexibleInstances seems only to affect what is allowed in an instance head. I don't see how it helps at all, unless it implies some other extensions. You might still run into termination issues - as a an associated type synonym rather than an associated data type, GeneratorOf a might very well be something large, and the conditions (disabled by UndecidableInstances) don't take advantage of the acyclic superclass relationship. http://www.haskell.org/ghc/docs/7.0-latest/html/users_guide/type-class-exten...
In both cases the instance constraint involves types that can be injectively inferred (if I have my terminology straight; work with me here) from a single type mentioned in the class head. In particular, I can imagine storing the dictionary for Monoid (GeneratorOf a) in the dictionary for Generable a, and thus allowing context reduction of (Monoid (GeneratorOf tyvar)) to (Generable tyvar). Meanwhile, I think there are things that are permitted by FlexibleInstances that I'd rather *not* have creeping into my programs.
Do you have any examples? I've always found FlexibleInstances alone unproblematic - it's only when you add OverlappingInstances or worse that things can get messy. Brandon