
More suggestions:
1) Pursuing the view that this thing identifies a special ST-style state included in the IO monad, we could view the IO state stuff as a special case of the ST stuff, changing
newtype IORef a = IORef (STRef IOState a) newtype IOArray i e = IOArray (STArray IOState i e) newtype IOUArray i e = IOUArray (STUArray RealWorld i e)
(currently exported opaquely) to
type IORef = STRef IOState type IOArray = STArray IOState type IOUArray = STUArray IOState
so that there would only be one type of reference.
This constrains the implementations of IORef and STRef to be the same (obviously). I can't immediately see any benefit from using different implementations for these two types, so maybe it's not an issue.
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. Cheers, Simon

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.

This constrains the implementations of IORef and STRef to be the same (obviously). I can't immediately see any benefit from using different implementations for these two types, so maybe it's not an issue.
I could be a bit out of date but I think Hugs uses different implementations because IO has concurrency and exceptions and ST doesn't. Apart from effort required, I don't know if there is any cost in switching. -- Alastair

On Thu, Sep 11, 2003 at 04:40:07PM +0100, Alastair Reid wrote:
This constrains the implementations of IORef and STRef to be the same (obviously). I can't immediately see any benefit from using different implementations for these two types, so maybe it's not an issue.
I could be a bit out of date but I think Hugs uses different implementations because IO has concurrency and exceptions and ST doesn't. Apart from effort required, I don't know if there is any cost in switching.
I think IORef and STRef have both been MUTVAR as far back as I can see. The IO and (strict) ST monads used to be very different, and no longer are (so they both use the same state primitives now), but I don't think this affects the IORef = STRef IOState question.
participants (3)
-
Alastair Reid
-
Ross Paterson
-
Simon Marlow