Reference types
John Hughes
rjmh@cs.chalmers.se
Wed, 6 Feb 2002 00:10:49 +0100 (MET)
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