Reference types

John Hughes rjmh@cs.chalmers.se
Wed, 6 Feb 2002 12:38:50 +0100 (MET)


Ashley Yakeley wrote:

	At 2002-02-06 01:09, John Hughes wrote:

	>No no no! This still makes the reference type depend on the monad type, which
	>means that I cannot manipulate the same reference in two different monads! 

	Yes you can. Consider:

	    -- m somehow uses 'rep' internally
	    class (Monad rep, Monad m) => LiftedMonad rep m where
	        {
	        lift :: rep a -> m a;
	        }

	    instance LiftedMonad (ST s) (ST s) where
	        {
	        lift = id;
	        }

	    instance LiftedMonad (ST s) TransformedMonad where
	        ...

	    liftRef :: (LiftedMonad rep m) => Ref rep a -> Ref m a;
	    liftRef ref = ...

	    newSTRef :: a -> Ref (ST s) a;
	     
	    newSTLiftedRef :: (LiftedMonad (ST s) m) => a -> Ref m a;
	    newSTLiftedRef = liftRef . newSTRef;

	With me so far? Now here's the clever bit: Refs created with 
	newSTLiftedRef are of type '(LiftedMonad (ST s) m) => Ref m a'. This 
	means they will work equally well as 'Ref (ST s) a' as they will as 'Ref 
	TransformedMonad a'.

Well, I'm still not convinced. A reference *value* can't have the type

      (LiftedMonad (ST s) m) => Ref m a

This is the type of a function, which given a dictionary returns a reference.
Moreover, since when I write

      do r <- newSTLiftedRef x
         ...

then I am effectively lambda-binding r, then r cannot have this type. It can only
have an instance of it ... which ties r to the monad m.

Am I missing something here?  Seems to me, to do what you're suggesting I
would have to put the context inside the Ref type itself:

      data Ref s a = Ref 
         { readRef :: forall m. LiftedMonad (ST s) m => m a,
	   writeRef :: forall m. LiftedMonad (ST s) m => a -> m () }

But now the s had to go back in the type of the reference...

Are you really in Seattle? If so, you must be a real nightbird or a
tremendously early riser!

John