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