Reference types

Koen Claessen koen@cs.chalmers.se
Wed, 6 Feb 2002 09:33:33 +0100 (MET)


John Hughes despaired:

 | 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.

Ashley Yakeley soothingly suggested:

 | I don't think so. [...]
 :
 |     data Ref m a = MkRef
 |         {
 |         get :: m a,
 |         set :: a -> m (),
 |         modify :: (a -> a) -> m ()
 |         };

Hm... this looks nice. With slight name changes this
becomes:

  data Ref m a =
    MkRef
      { readRef  :: m a
      , writeRef :: a -> m ()
      }

(such that:

  readRef  :: Ref m a -> m a
  writeRef :: Ref m a -> a -> m ()

)

Further, Ashley writes:

 | The point is that the m -> r dependency is also
 | unnecessary, except when you want a new "standard" ref
 | for a monad.

Not really, the m -> r is still there in practise, since you
want to be able to use the 'readRef' and 'writeRef'
operators, which work on the monad m, and you want them to
work on the monad (t m).

In this case one can simply lift the reference, like this:

  liftRef :: MonadTrans t => Ref m a -> Ref (t m) a
  liftRef ref =
    MkRef
      { readRef  = lift (readRef ref)
      , writeRef = \a -> lift (writeRef ref a)
      }

Look, ma, no type classes!

/Koen.

--
Koen Claessen
http://www.cs.chalmers.se/~koen
Chalmers University, Gothenburg, Sweden.