[Haskell-cafe] Re: monad subexpressions

apfelmus apfelmus at quantentunnel.de
Sat Aug 4 04:18:33 EDT 2007

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` ...


  pure foo <*> r xvar0 <*> r xvar1 <*> ...


  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` ...


More information about the Haskell-Cafe mailing list