
On Thu, Sep 25, 2003 at 02:30:45PM +0100, Simon Peyton-Jones wrote:
Ross Paterson writes: | The proposal is to expose | | type IORef = STRef IORegion | type IOArray = STArray IORegion | type IOUArray = STUArray IORegion | | (modulo the name of IORegion) but to keep IO opaque. I think that while | IO includes state, it is not itself a state monad (because the "state" | there can be changed by other agents at the same time).
(where IORegion occurs in stToIO :: ST IORegion a -> IO a to make it safe)
Aha. I hadn't realised that you want to expose IORef as an STRef, but not the IO monad itself.
I certainly don't object to that, but I'm not sure of all the implications. For example, at the moment one could have class MRef m r | m -> r, r -> m where new :: a -> m (r a) read :: r a -> m a write :: r a -> a -> m ()
instance MRef IO IORef where ... instance MRef (ST s) (STRef s) where ...
I don't think that'll be legal if IORef = STRef IORegion, because the "r->m" dependency becomes ambiguous. So we'd have to lose the "r->m" dependency.
The reason for having an MRef class was that there were two reference types. If there's only one, but parameterized by region, you might as well parameterize on the region instead, describing a class of monads that contain a heap region: class MonadST s m | m -> s where liftST :: Control.Monad.ST.ST s a -> m a Then you can't have the s->m dependency: instance MonadST s (Control.Monad.ST.ST s) where liftST = id instance MonadST s (Control.Monad.ST.Lazy.ST s) where liftST = strictToLazyST instance MonadST IORegion IO where liftST = Control.Monad.ST.stToIO instance MonadST s m => MonadST s (ContT r m) where liftST = lift . liftST ... but you don't want it: you want to manipulate the same references in different monads (as we already do with the lazy and strict ST monads). All the operations lift to all such monads, e.g. read :: MonadST s m => STRef s a -> m a read r = liftST (Data.STRef.readSTRef r) and that handles arrays as well as refs.