
class Monad m => MonadIS m where getIS :: m IntState putIS :: IntState -> m () Most functions are generalized over this class. And to further improve
Hallo Yhc developers, While I was in a masochistic mood this week, I decided to change Yhc to use proper monads. The old State.hs 'monad' was based around the functions (>>>=) and (>>>), representing a WriterT State monad. They had some quirky features, like different output state types, and because of the writer monad, there were lots of functions taking dummy environment parameters. There was also a different State0 s type representing State s (). I have replaced this mess by usage of the mtl, in particular Control.Monad.State and Control.Monad.Writer. Usage of (>>>=) is replaced by do notation. As replacement for the (=>>>) operator I use (<*>) and (<$>) based on Control.Applicative. I also added a new class "MonadIS" for monads that carry IntState around. the readability, all state and environment types are now records. Now, I may have introduced some bugs. The code was rather fond of reusing variable names like
case liftExp exp state of (exp, state) -> ... While I tried to be careful, it is possible that somewhere there is a reference to an old value. Yhc does still pass the test suite.
I may have also removed some of the strictness, in the old code =>>> (aka. <*>) was strict in the state, after the cleanup it no longer is. This could be fixed by using a different monad. There is already a StrictState monad in State.hs which I used for debugging (to get traces in some sensible order). I also changed "case x of (a,b) -> y" into "let (a,b) = x" in do blocks. Usually either a or b is examined afterwards anyway, so it should not matter much for the strictness. Unfortunately, the code now requires -fglasgow-exts (or a LANGUAGE pragma) in some places. The only reason for this is FlexibleInstances for the instance:
instance MonadIS (State IntState) where ... If this is a problem it might be possible to work around it by changing it to: class HasIntState a instance HasIntState a => MonadIS (State a) But IMO FlexibleInstances are a noncontroversial extension, and they are supported by most compilers.
Finally, it should be noted that I kind of gave up at the end; the type checker just uses runState to get around the monads. The reason for this is that I saw a circular reference there somewhere, and I decided it was best not to mess with it. The patch is too big to send by email to this list, so it can be downloaded from http://twan.home.fmf.nl/yhc-mtl.patch.gz Twan van Laarhoven

H Twan,
While I was in a masochistic mood this week, I decided to change Yhc to use proper monads.
Something that was definately in need of doing, and I'm impressed you managed it!
I have replaced this mess by usage of the mtl, in particular Control.Monad.State and Control.Monad.Writer. Usage of (>>>=) is replaced by do notation. As replacement for the (=>>>) operator I use (<*>) and (<$>) based on Control.Applicative.
All very sensible.
Most functions are generalized over this class. And to further improve the readability, all state and environment types are now records.
Woohoo! Records was something that was definately required!
Now, I may have introduced some bugs. The code was rather fond of Yhc does still pass the test suite.
Thats enough for me, if it doesn't work now, thats a bug in our test suite.
I may have also removed some of the strictness, in the old code =>>> (aka. <*>) was strict in the state, after the cleanup it no longer is. This could be fixed by using a different monad. There is already a StrictState monad in State.hs which I used for debugging (to get traces in some sensible order).
I know the old compiler was carefully optimised for memory useage, but I'd say that clearer code wins, and I'm not convinced it was still memory efficient. Changing the strictness slightly to get better code is sensible.
Unfortunately, the code now requires -fglasgow-exts (or a LANGUAGE pragma) in some places. The only reason for this is FlexibleInstances for the instance:
instance MonadIS (State IntState) where ... If this is a problem it might be possible to work around it by changing it to: class HasIntState a instance HasIntState a => MonadIS (State a) But IMO FlexibleInstances are a noncontroversial extension, and they are supported by most compilers.
Alas but not Yhc - which will break our goal of being self-compiling at some stage. How much work is it to move to not requiring this? If that could be done, then this patch will definately be applied.
Finally, it should be noted that I kind of gave up at the end; the type checker just uses runState to get around the monads. The reason for this is that I saw a circular reference there somewhere, and I decided it was best not to mess with it.
Fair enough, I'm impressed you got as far as you did. Thanks Neil

On Wed, 11 Apr 2007 17:45:53 +0200, Neil Mitchell
Now, I may have introduced some bugs. The code was rather fond of Yhc does still pass the test suite.
Thats enough for me, if it doesn't work now, thats a bug in our test suite.
Neil
To quote Edsger Dijkstra: "testing can only reveal the presence of bugs, not their absence." -- Met vriendelijke groet, Henk-Jan van Tuyl -- http://Van.Tuyl.eu/ -- Using Opera's revolutionary e-mail client: https://secure.bmtmicro.com/opera/buy-opera.html?AID=789433

Neil Mitchell wrote:
But IMO FlexibleInstances are a noncontroversial extension, and they are supported by most compilers.
Alas but not Yhc - which will break our goal of being self-compiling at some stage. How much work is it to move to not requiring this? If that could be done, then this patch will definately be applied.
Getting rid of the requirement for FlexibleInstances should not be to hard (nor should adding support for them to Yhc). But even if I work around that, this patch relies quite havilly on the mtl, which uses multi parameter type classes and functional dependencies. Those might be a bigger problem. Hoever the mtl was already used in other parts of the compiler... Twan

Hi Twan,
Getting rid of the requirement for FlexibleInstances should not be to hard (nor should adding support for them to Yhc).
Sometimes adding support for things to Yhc is harder than you might naturally think...
But even if I work around that, this patch relies quite havilly on the mtl, which uses multi parameter type classes and functional dependencies. Those might be a bigger problem. Hoever the mtl was already used in other parts of the compiler...
There are two parts of the mtl - one provides monads, one provides monad transformers. In general the monad half is Haskell 98, the transformer half is not - we've been careful to stick to the monad half so far. The mtl is actually being split soon into a Haskell 98 half and a MPTC/FD half. How much of the transformer side do you use, and how hard would it be to remove that? From my limited knowledge of mtl, I believe you can write your own custom instance for any given combination - which removes the type class requirement. If that is so, that may be an option. Thanks Neil

Hi, Here is a patch that no longer needs flexible instances. It also includes the previous patch, it seems darcs send diffs against the only repository. Again, the patch is too big to send by email to this list, so it can be downloaded from http://twan.home.fmf.nl/yhc-mtl-no-flex.patch.gz I added a HasIntState class as suggested in my previous post. I also had to wrap a newtype around some monads that did not comply. As an added bonus ByteCode.Compiler and DotNet.Compiler now use an actual writer monad instead of manual plumbing. Neil Mitchell wrote:
How much of the transformer side do you use, and how hard would it be to remove that? From my limited knowledge of mtl, I believe you can write your own custom instance for any given combination - which removes the type class requirement. If that is so, that may be an option.
I use get, put, ask, locally, etc. rather heavily, but that could changed to something more specific using search/replace on a per module bases. I already did this partially when switching to newtypes for the renamer and import monads. Twan

On Wed, Apr 11, 2007 at 11:50:03PM +0100, Neil Mitchell wrote:
There are two parts of the mtl - one provides monads, one provides monad transformers. In general the monad half is Haskell 98, the transformer half is not - we've been careful to stick to the monad half so far. The mtl is actually being split soon into a Haskell 98 half and a MPTC/FD half.
Actually, even the transformer half is Haskell 98 - it requires higher kinds, but those have been with us since forever (Monad uses them). The trouble spot is with the automatic lifting, so if we use enough 'lift's by hand, we can stay H98. Stefan
participants (4)
-
Henk-Jan van Tuyl
-
Neil Mitchell
-
Stefan O'Rear
-
Twan van Laarhoven