
On Fri, 11 May 2001, Lauri Alanko wrote:
Yep, but in hugs +o the latter overrides the first one. Which is quite convenient.
I doubt that it works predictably in all cases (when state types are not known statically). I can try to construct an example if you wish.
translift :: (MonadTrans t, Monad m, Monad (t m)) => (m a -> m b) -> t m a -> t m b
translift f m = m >>= lift . f . return
instance (MonadTrans t, MonadReader r m, Monad (t m)) => MonadReader r (t m) where ask = lift ask local = translift . local
instance (MonadTrans t, MonadWriter w m, Monad (t m), Monoid w) => MonadWriter w (t m) where tell = lift . tell listen = translift listen pass = translift pass
This gives wrong results (but I haven't checked). For example listen :: Monoid w => ReaderT r (Writer w) a -> ReaderT r (Writer w) (a, w) doesn't listen what the action tells, but listens to 'return' which always tells mempty. Similarly 'local' first runs the action in the original environment and then provides a new environment to 'return' which doesn't look at it. I did most monad transformer forwarding instances in ghc-5.00 and hope that I got them right, but I haven't tested them much. It's not that mechanical (except MonadState), and some combinations can't be done at all. It could be advantageous to put something like translift in an extension of MonadTrans. AFAIR many liftings of this type are similar (but the function must be provided separately for each state transformer), so it would simplify making forwarding instances.
Is it inconceivable that m might actually have multiple ParsingStates, and thus you really have to specify which one you want to use to get the input?
The idea is to use a single state and abstract over the way in which interesting components are contained in it. It has these advantages: * It works. I doubt that automatic recognition of the state type would work. * It allows to have multiple components of the same type in the state. Now I see that my simulation of a fundep without the fundep (an extra class which generates the dependency, instantiated separately for each monad transformer, with MonadError as a superclass) doesn't work that well: throwError would still be ambiguous so it needs a wrapper with a type which tells how to determine the error type using the new class. So I'm now convinced that MonadError should have the fundep too. Some other mechanism could be invented to make it easier to embed various components in the same type (for MonadReader & MonadState) or various alternatives (for MonadError). I have a rather heavy proposal for the first case (a language extension which redesigns records). OCaml has a dual mechanism for the second (polymorphic variants). If my records succeed, I will try to cover variants too. -- Marcin 'Qrczak' Kowalczyk