[project @ 2001-12-20 11:19:05 by simonpj]
authorsimonpj <unknown>
Thu, 20 Dec 2001 11:19:12 +0000 (11:19 +0000)
committersimonpj <unknown>
Thu, 20 Dec 2001 11:19:12 +0000 (11:19 +0000)
commit91c750cbd18e3d610b0db498ded38d5b3c5adfac
tree15c9c200208dc891efe4974a02ab0caef2e90ab4
parent32e08a78a4a8932369bafb9f36081a4a3a794a57
[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:
ghc/compiler/hsSyn/HsDecls.lhs
ghc/compiler/hsSyn/HsTypes.lhs
ghc/compiler/main/CmdLineOpts.lhs
ghc/compiler/main/DriverFlags.hs
ghc/compiler/main/HscTypes.lhs
ghc/compiler/parser/ParseUtil.lhs
ghc/compiler/parser/Parser.y
ghc/compiler/parser/RdrHsSyn.lhs
ghc/compiler/rename/RnEnv.lhs
ghc/compiler/rename/RnHiFiles.lhs
ghc/compiler/rename/RnHsSyn.lhs
ghc/compiler/rename/RnSource.lhs
ghc/compiler/typecheck/Inst.lhs
ghc/compiler/typecheck/TcDeriv.lhs
ghc/compiler/typecheck/TcEnv.lhs
ghc/compiler/typecheck/TcIfaceSig.lhs
ghc/compiler/typecheck/TcInstDcls.lhs
ghc/compiler/typecheck/TcMType.lhs
ghc/compiler/typecheck/TcMonad.lhs
ghc/compiler/typecheck/TcMonoType.lhs
ghc/compiler/typecheck/TcPat.lhs
ghc/compiler/typecheck/TcSimplify.lhs
ghc/compiler/typecheck/TcTyClsDecls.lhs
ghc/compiler/types/InstEnv.lhs