RealWorld
Ross Paterson
ross@soi.city.ac.uk
Mon, 8 Sep 2003 14:03:50 +0100
On Mon, Sep 08, 2003 at 12:48:26PM +0100, Simon Marlow wrote:
> > 2) For additional genericity, define a class
> >
> > class MonadST s m | m -> s where
> > liftST :: Control.Monad.ST.ST s a -> m a
> >
> [snip]
> >
> > then all the operations lift to all such monads, e.g.
> >
> > readSTRef :: MonadST s m => STRef s a -> m a
> > readSTRef r = liftST (Data.STRef.readSTRef r)
>
> Same argument as for MonadIO: I don't like the idea of generalising all
> the ST functions, and just generalising some of them would be
> inconsistent, so don't generalise any of them. Providing MonadST and
> liftST is fine, though.
The difference is that I wasn't suggesting that these replace the
existing definitions, but provide an additional more general interface
(i.e. non-destructive generalization).
However generalizing instances (like those of MArray) is a different
situation, leading to problems with overlapping instances. Once you have
instance MArray IOArray e IO
instance MArray (STArray s) e (ST s)
you can't define
instance MonadST s m => MArray (STArray s) e m
An alternative is to define functions like
readSTArray ::
(MonadST s m, MArray a e (ST s), Ix i) => a i e -> i -> m e
readSTArray arr i = liftST (readArray arr i)
but that's not ideal: you end up with two interfaces, neither of which
is more general than the other.