[project @ 2001-12-20 11:19:05 by simonpj]
---------------------------------------------
More type system extensions (for John Hughes)
---------------------------------------------
1. Added a brand-new extension that lets you derive ARBITRARY CLASSES
for newtypes. Thus
newtype Age = Age Int deriving( Eq, Ord, Shape, Ix )
The idea is that the dictionary for the user-defined class Shape Age
is *identical* to that for Shape Int, so there is really no deriving
work to do. This saves you writing the very tiresome instance decl:
instance Shape Age where
shape_op1 (Age x) = shape_op1 x
shape_op2 (Age x1) (Age x2) = shape_op2 x1 x2
...etc...
It's more efficient, too, becuase the Shape Age dictionary really
will be identical to the Shape Int dictionary.
There's an exception for Read and Show, because the derived instance
*isn't* the same.
There is a complication where higher order stuff is involved. Here is
the example John gave:
class StateMonad s m | m -> s where ...
newtype Parser tok m a = Parser (State [tok] (Failure m) a)
deriving( Monad, StateMonad )
Then we want the derived instance decls to be
instance Monad (State [tok] (Failure m)) => Monad (Parser tok m)
instance StateMonad [tok] (State [tok] (Failure m))
=> StateMonad [tok] (Parser tok m)
John is writing up manual entry for all of this, but this commit
implements it. I think.
2. Added -fallow-incoherent-instances, and documented it. The idea
is that sometimes GHC is over-protective about not committing to a
particular instance, and the programmer may want to say "commit anyway".
Here's the example:
class Sat a where
dict :: a
data EqD a = EqD {eq :: a->a->Bool}
instance Sat (EqD a) => Eq a where
(==) = eq dict
instance Sat (EqD Integer) where
dict = EqD{eq=(==)}
instance Eq a => Sat (EqD a) where
dict = EqD{eq=(==)}
class Collection c cxt | c -> cxt where
empty :: Sat (cxt a) => c a
single :: Sat (cxt a) => a -> c a
union :: Sat (cxt a) => c a -> c a -> c a
member :: Sat (cxt a) => a -> c a -> Bool
instance Collection [] EqD where
empty = []
single x = [x]
union = (++)
member = elem
It's an updated attempt to model "Restricted Data Types", if you
remember my Haskell workshop paper. In the end, though, GHC rejects
the program (even with fallow-overlapping-instances and
fallow-undecideable-instances), because there's more than one way to
construct the Eq instance needed by elem.
Yet all the ways are equivalent! So GHC is being a bit over-protective
of me, really: I know what I'm doing and I would LIKE it to pick an
arbitrary one. Maybe a flag fallow-incoherent-instances would be a
useful thing to add?
24 files changed: