The basic bind operations etc are overloaded for IO and ST, but to overload the Ref operations one needs to add
class RefMonad r m | r -> m, m -> r where newRef :: a -> m (r a) readRef :: r a -> m a writeRef :: r a -> a -> m () instance RefMonad IORef IO where ... instance RefMonad (STRef s) (IO s) where ... A multi-paramter type class is needed. Notice particularly the bidirectional functional dependencies. This is the only convincing example I know with functional dependencies going both ways. Or at least it was. But in a recent conversation with Peter Thiemann I realised that this is all baloney. There's a much easier type structure: data Ref m a -- References in monad m, values of type a newIORef :: a -> IO (Ref IO a) readIORef :: Ref IO a -> IO a writeIORef :: Ref IO a -> a -> IO () newSTRef :: a -> ST s (Ref (ST s) a) readSTRef :: Ref (ST s) a -> ST s a writeSTRef :: Ref (ST s) a -> a -> ST s () class RefMonad m where newRef :: a -> m (Ref m a) readRef :: Ref m a -> m a writeRef :: Ref m a -> a -> m () instance RefMonad IO where ... instance RefMonad (ST s) where ... No functional dependencies. No multi-parameter classes. Pure Haskell 98. All of this works for mutable arrays too, of course. Oh no, please don't do this! I use the RefMonad class, but *without* the dependency r -> m. Why not? Because I want to manipulate (for example) STRefs in monads built on top of the ST monad via monad transformers. So I use the same reference type with *many different* monads! Your change would make this impossible. John _______________________________________________ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell