
On Friday 03 August 2007, Sebastian Sylvan wrote:
On 03/08/07, Claus Reinke
wrote: ah, a concrete example. but isn't that the typical use case for ap?
mytransaction = foo `liftM` r xvar0 `ap` r xvar1 .. where r = readTVar
I really find it difficult to articulate why this isn't acceptable, because it seems so obvious to me! It's short yes, but I really don't think it's very clear... I have a hard time believing that anyone finds that natural. After lots and lots of mind-bending forays into various branches of mathematics, then yes maybe you can get used to it, but it's hardly as natural as saying "add this one symbol to your values to extract monadic values left-to-right".
Note that if this is the example we're using, idiom brackets solve things: mytransaction = [[ foo (r xvar0) (r xvar1) ...]] where r = readTVar and are, possibly, less fraught with peril, considering all the discussions about where the desugaring should place the implicit binding, and what happens if there isn't an enclosing do and so on (as idiom brackets desugar to the "foo `liftM` r xvar0 `ap` r xvar1 ..." mentioned above, and the entire expression is delimited, there are no such questions to be pondered, I think). Also, note, if you use the operators in Control.Applicative, then: return $ foo $(bar1) $(bar2) $(bar3) ... can be: return foo <*> bar1 <*> bar2 <*> bar3 ... or: foo <$> bar1 <*> bar2 <*> bar3 I don't (personally) see how that's any more cryptic than placing brackets around around the monadic values themselves. In either case, there's some magic going on that the user may or may not understand. In the applicative case, it's using a different kind of (Monadic/Applicative) function application via an operator. In the monad brackets case, it's doing a macro expansion. I, personally find the former clearer, but perhaps that's because I understand Applicative fairly well, but only have a vague idea of what, specifically, the macro will be doing so far. To get outside the scope of idiom brackets/applicative, you'd need a use case like: if $(mexpr) then branch1 else branch2 or (lest that be to easy): case $(mexpr) of p1 -> branch1 p2 -> branch2 ... In other words, something where you're not simply applying a pure function to a bunch of monadic arguments. I can't say I've run into such patterns much myself, but I've been told they're common in xmonad, and may be elsewhere. In general, I guess you'd need the monad brackets when you'd need to interact with other syntax (since it isn't first-class). Record update would probably be another example. But applications of pure functions to monadic values doesn't seem like a particularly compelling motivator, in my opinion. -- Dan