Sebastian Sylvan wrote: > Claus Reinke wrote: >>> mytransaction = do { >>> x0 <- readTVar xvar0 >>> x1 <- readTVar xvar1 >>> : >>> xn <- readTVar xvarn >>> return $ foo x0 x1 .. xn >>> } >> >> 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.
I think it's entirely natural :) Applicative functors (Control.Applicative) are the pattern behind this. The notation may seem a little weird first, but in the end, `ap` is a kind of explicit function application and similar to $. With the notation from Control.Applicative, the line return foo `ap` r xvar0 `ap` r xvar1 `ap` ... reads pure foo <*> r xvar0 <*> r xvar1 <*> ... or foo <$> r xvar0 <*> r xvar1 <*> ... In other words, instead of using juxtaposition to apply an argument to a function, we use <*>. The type of `ap` is ap :: m (a -> b) -> m a -> m b so that it can be thought of as a generalized function application where the function is "under" a monad. The difference to $ is that <*> is left associative and allows for currying. I.e. <*> is like $ used in the following way ((foo $ x0) $ x1) $ x2 Note that you can even incorporate the TVar by defining your own generalized function application: apT :: STM (a -> b) -> TVar a -> STM b apT f x = f `ap` readTVar x Then, mytransaction reads mytransaction = return foo `apT` xvar0 `apT` xvar1 `apT` ... Regards, apfelmus _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe