I have another proposal, though. Introduce a new keyword, which I'll call "borrow" (the opposite of "return"), that behaves like a function of type (Monad m) => m a -> a inside of do statements. More precisely, a do expression of the form
do { ... ; ... borrow E ... ; ... }
is transformed into
do { ... ; x <- E ; ... x ... ; ... }
where x is a fresh variable. If more than one borrow form appears in the same do statement, they are pulled out from left to right, which matches the convention already used in liftM2, ap, mapM, etc.
I think this is a good idea. I like the inline "<-", or maybe something like "@". I'm not sure what you intend to do about nested "do" statements, though. If they correspond to different monads, I might want to have a 'borrow' in the inner "do" statement create a lifted expression in the outer "do" statement. Furthermore, I might want to have a lifted expression in the outer "do" create something which needs to be evaluated again in the monad of the inner "do" to produce the final value. In any case, it would certainly be good to have better support for lifting; and something which doesn't weaken the type system is likely to be implemented before something that does is, so I am in favor of investigation along the lines of your proposal. Frederik -- http://ofb.net/~frederik/