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.