
On Thursday, 2003-06-26, 23:57, CEST, Derek Elkins wrote:
[...]
not deeply understanding the use of Haskell extensions in the State source,
I'm assuming Control.Monad.State's source in which case -no- extensions are used for -State- (well, at least I don't see any quickly glancing). Extensions are used for the -MonadState class-. For the MonadState class they are pretty much necessary. Multiparameter type classes are necessary because the state type depends on the monad (get would have type forall s.Monad m => m -> s otherwise which is rather meaningless), the function dependencies tell the type checker that the state type is completely determined by the monad type.
Hello, why not swap the state and the monad parameter of StateT? The definition would become something like the following: newtype StateT m s a = StateT (s -> m (a,s)) With this we could create a MonadState class which doesn't use type system extensions. It could be defined like this: class MonadState m where get :: m s s put :: s -> m s () Note that m now has kind * -> * -> *. Note also that this restricts the MonadState class because only state transformers which can work with every state type are now possible as instances. But, at least, State and our modified StateT can be instantiated without problem. The problem arises when we try to make a MonadTrans instance for our new StateT because MonadTrans needs a type of kind * -> * -> * whoose first argument is a monad. But we can create a different MonadTrans class based on the kind of functional dependency usage we just dropped for MonadState. We just write: class MonadTrans (Monad m, Monad tm) => m tm | tm -> m where lift :: m a -> tm a Instead of writing instance MonadTrans T where ... we would now write instance Monad m => MonadTrans m (T m) where ... and for our new StateT type we would write instance Monad m => MonadTrans m (StateT m s) where ... The new MonadTrans class would be more powerful. This would have the nice effect that we don't need MonadIO anymore. Instead of writing MonadIO m we could just use MonadTrans IO m Changing MonadTrans this way would help me with my parser module.¹ I have a type Parser which needs three parameters, a "base monad", a token type and an output type. The base monad parameter has the same purpose as the monad parameter in ReaderT, WriterT, StateT etc. The lift function makes sense for my parser type, so I want a MonadTrans instance. This would restrict me to the parameter order token - base monad - output which is rather unfortunate for me. The reason is that there are parser functions which fulfill the arrow axioms. The arrow type is a parser applied to a specific base monad. So I want to write something like instance Monad baseMonad => Arrow (Parser baseMonad) where ... which implies that the base monad must be the first parameter. This brings me to another point. One year ago we had a discussion on The Haskell Mailing List concerning arrows. (The subject of the mails was just "arrows".) The point was that it seemed strange to me that first and second are included in the basic arrow class Arrow while left and right have their extra class ArrowChoice. Not only that it seemed strange to me but it made it impossible to make Parser baseMonad an instance of Arrow. Parser baseMonad has nice implementations of pure and (>>>) but none of first or second. Currently, I use my own Arrow module which provides an arrow class, that doesn't include first and second. I'm really not happy with using a replacement for a module from the hierarchical libraries. Is there any chance of changing the class structure of Control.Arrow?
[...]
Wolfgang ¹ The parser module is part of Seaweed. It's the module Seaweed.Core.Parsing. The source code of Seaweed can be accessed via this URI: http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/seaweed/code/ There is also the module Seaweed.Core.Parsing.Utilities which provides several useful things implemented on top of the core parsing module.