At 2002-02-05 15:10, John Hughes wrote:
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.
I don't think so. Provided you have a class that represents your monads, I don't see why you can't do this: class (Monad m) => MyMonad m where ... myIntRef :: (MyMonad m) => Ref m Int; ...except that with Simon's suggested change you wouldn't be able to define your own Refs. I believe the best solution to the problem involves leaving the existing functions as is but adding something like this: data Ref m a = MkRef { get :: m a, set :: a -> m (), modify :: (a -> a) -> m () }; mkRef g s = MkRef g s (\map -> do { val <- g; s (map val); }); refBind :: (Monad m) => (m a) -> (a -> Ref m b) -> Ref m b; refBind ma arb = MkRef ( ma >>= (\a -> get (arb a) )) (\b -> ma >>= (\a -> set (arb a) b )) (\map -> ma >>= (\a -> modify (arb a) map )); class (Monad m) => RefMonad m where { newRef :: a -> m (Ref m a); -- "standard" ref for this monad }; instance RefMonad IO where { newRef a = do { r <- newIORef a; return MkRef (readIORef r) (writeIORef r) (modifyIORef r) }; }; instance RefMonad (ST s) where etc. The point is that the m -> r dependency is also unnecessary, except when you want a new "standard" ref for a monad. -- Ashley Yakeley, Seattle WA
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.
participants (2)
-
Ashley Yakeley -
Koen Claessen