to illustrate why some of us are concerned about this extension,
a few examples might help. consider:

   f (g (<- mx))

does this stand for
   (a) mx >>= \x-> f (g x)
   (b) f (mx >>= \x-> (g x))
   (c) none of the above, because there's no do
   (d) something else entirely

if (a/b), does the decision depend on the type of g (if g is pure,
then (a), if g is monadic itself, then (b))? if (d), what?

if (a/b), then this is no longer preprocessing, but depends on the
types, which means that the type system must work in the presence
of this extension, rather than its pre-processed form. if you want to
avoid that, you're left with (c), but is that any better?

if (c), then the following are no longer equivalent

   1. return ...
   2. do return ...

in particular,
   do return ..

is no longer a unit of the monad (in (a/b), even return .. isn't). so
if you write

   f (do g (<- mx))

you mean (b), while if you write
   do f (g (<- mx))

you mean (a), and if you write
   f (g (<- mx))

you mean either an error, if there is no surrounding 'do', or something else, if there is a surrounding 'do'. and woe to those who think they can insert some 'do' notation whereever they like - they need to check the subexpressions for (<-) first!

now, consider nesting monadic subexpressions:

   f (<- g (<- mx))

surely means the same as f =<< (g =<< mx), namely
   mx >>= \x-> g x >>= \gx-> f gx

right? wrong! we forgot the 'do'. without a 'do'-context, this means
nothing in (c). so if you have

do ..
       fx <- f (<- g (<- mx))
       ..
       fx <- f (<- g (<- mx))
       ..

and there are no free variables, then you can do the usual sharing to
improve readability, right?

   let fgmx = f (<- g (<- mx)) in
do ..
       fx <- fgmx
       ..
       fx <- fgmx
       ..

wrong again! this is syntax, not expression, so the latter variant
changes the scope the (<-)s refer to (some outer 'do', if one exists).
you could have written do let fgmx = f (<- g (<- mx))
       ..
       fx <- fgmx
       ..
       fx <- fgmx
       ..

perhaps, and at this stage you might no longer be surprised that
do and let no longer commute. or were you? if you weren't, here's
a quick question: we've already seen the left- and right-identity
laws in danger, so what about associativity?

do { do { a; b}; c }
is still the same as
do { a; do { b; c } }

yes? no? perhaps? sometimes? how long did it take you?

could someone please convince me that i'm painting far too
gloomy a picture here?-)
claus

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to