I don't quite understand how this would work. For example, would it work for these examples?
do x <- blah let foo = return foo (f x) -- Using an alias of return/pure do x <- Just blah Just (f x) -- another form of aliasing do x <- blah return (g x x) -- could perhaps be turned into: -- (\x -> g x x) <$> blah do x <- blah y <- return x return (f y) -- = f <$> blah ? do x1 <- foo1 -- effect order must not be reversed x2 <- foo2 return (f x2 x1) -- note reversed order -- multiple uses of applicative do x1 <- foo1 y <- return (f x1) x2 <- foo2 y2 <- return (g y x2) return y2 So I guess it's possible to detect the pattern: do x1 <- foo1; ...; xN <- fooN; [res <-] return (f {x1..xN}) where {x1..xN} means "x1..xN" in some order" and turn it into: do [res <-] (\x1..xN -> f {x1..xN}) <$> foo1 <*> ... <*> fooN Open issues would be detection of the correct "return"-like thing. This is why using monad comprehensions would help somewhat, but not fully because it's still possible to put "x <- return y" in the generators part. The current desugaring of do-notation is very simple because it doesn't even need to know about the monad laws. They are used implicitly by the optimiser (e.g., "foo >>= \x -> return x" is optimised to just "foo" after inlining), but the desugarer doesn't need to know about them. On 4 September 2011 03:34, Daniel Peebles <pumpkin...@gmail.com> wrote: > Hi all, > > I was wondering what people thought of a smarter do notation. Currently, > there's an almost trivial desugaring of do notation into (>>=), (>>), and > fail (grr!) which seem to naturally imply Monads (although oddly enough, > return is never used in the desugaring). The simplicity of the desugaring is > nice, but in many cases people write monadic code that could easily have > been Applicative. > > For example, if I write in a do block: > > x <- action1 > y <- action2 > z <- action3 > return (f x y z) > > that doesn't require any of the context-sensitivty that Monads give you, > and could be processed a lot more efficiently by a clever Applicative > instance (a parser, for instance). Furthermore, if return values are > ignored, we could use the (<$), (<*), or (*>) operators which could make the > whole thing even more efficient in some instances. > > Of course, the fact that the return method is explicitly mentioned in my > example suggests that unless we do some real voodoo, Applicative would have > to be a superclass of Monad for this to make sense. But with the new default > superclass instances people are talking about in GHC, that doesn't seem too > unlikely in the near future. > > On the implementation side, it seems fairly straightforward to determine > whether Applicative is enough for a given do block. Does anyone have any > opinions on whether this would be a worthwhile change? The downsides seem to > be a more complex desugaring pass (although still something most people > could perform in their heads), and some instability with making small > changes to the code in a do block. If you make a small change to use a > variable before the return, you instantly jump from Applicative to Monad and > might break types in your program. I'm not convinced that's necessary a bad > thing, though. > > Any thoughts? > > Thanks, > Dan > > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe > > -- Push the envelope. Watch it bend.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe