Reference types

John Hughes [email protected]
Thu, 7 Feb 2002 11:25:12 +0100 (MET)


Simon writes:

	There were really two parts to my message:

	1.  Have a single built-in type (Ref), rather than two (IORef and
	STRef).
	I don't see how that can be anything other than a Good Thing, can it?
	The primitive operations over Refs are still non-overloaded, as before:
		newIORef :: a -> IO (Ref IO a)
		newSTRef :: a -> ST s (Ref (ST s) a)
		...etc...

	2.  Have a RefMonad type class to overload the new, read, write
	operations over Refs.   But nothing in my message precludes also
	having a RefMonad2 class with two parameters, and whatever 
	functional dependencies (or lack of them) that you like

		class RefMonad2 r m where
		   new :: a -> m (r a)
		   read :: r a -> m a
		   write :: r a -> a -> m ()

		instance RefMonad2 (Ref IO) IO where ...
		instance RefMonad2 (Ref (ST s)) (ST s) where ...

	So then it's only a question of who gets the name "RefMonad"!
	(Incidentally, so far as I know, RefMonad isn't in any of the existing
	libraries.)

It's in my libraries, and in other people's, with the same definition. Just
not in any standard ones yet. (Proposal in preparation!)

	So I conclude:
		(1) is a win	
		(2) is a question of what we name the new (and undoubtedly
		useful) class that I tendentiously called RefMonad

OK, I see your point.

However, note that your RefMonad class can only ever have two instances, since
there is no way to define creation of a reference of any type other than Ref
IO or Ref (ST s). My RefMonad class can usefully have many instances. So if
you ask me, the benefit of defining your class is rather limited.

The goal here is to write generic imperative code, that can work over either
underlying monad, right? In that case, why would you use a class which limits
you to one of the two monads IO or ST, when you can equally well use a class
which works over any monad built on top of one of these? I can't see any
reason to use SimonRefMonad when one can instead use JohnRefMonad. Hence I
suggest that I get the nice name!

The functional dependency m->r is important in practice. You get continual
hassle with ambiguous overloading otherwise.

Given that one wants JohnRefMonad( with the functional dependency) anyway, I
can't really see that (1) is much of a win. It doesn't help define instances
of the class. Maybe in some absolute sense it might be a cleaner design, but I
can't see that it's worth breaking code to make this change. (Any imperative
code with explicit type signatures will of course break if you make this
change).

John