4

Can anyone share a good real life situation when a function with the following signature would be useful?

f (a -> b) -> f a -> f b

I can't really see where I would need something like the schoolbook examples from learn-you-a-haskell [(+),(*)] <*> [1,2] <*> [3,4]

leftaroundabout
  • 117,950
  • 5
  • 174
  • 319
Trident D'Gao
  • 18,973
  • 19
  • 95
  • 159
  • 1
    Gabriel Gonzalez's [series](http://www.haskellforall.com/2012/08/the-category-design-pattern.html) [of](http://www.haskellforall.com/2014/04/scalable-program-architectures.html) [articles](http://www.haskellforall.com/2014/04/model-view-controller-haskell-style.html) on `Monoid`s demonstrates [very useful properties of `Applicative`s](http://www.haskellforall.com/2014/07/equational-reasoning-at-scale.html). – Cirdec Feb 04 '15 at 02:45
  • 1
    One common idiom is [applicative parsing](https://github.com/pcapriotti/optparse-applicative). – user2407038 Feb 04 '15 at 05:20
  • possible duplicate of [What are practical uses of applicative style?](http://stackoverflow.com/questions/7103864/what-are-practical-uses-of-applicative-style) – DNA Feb 04 '15 at 11:02
  • 1
    yeah, might be, too bad we got some nice answers here already – Trident D'Gao Feb 04 '15 at 14:10
  • 1
    Partial application! I use `(<*>) :: f (a -> b) -> f a -> f b` with infix `fmap`, `(<$>) :: (a -> b) -> f a -> f b` so that if `f :: a -> b -> c -> d` and `fa :: f a` etc then `f <$> fa <*> fb <*> fc :: f d`. Notice that `f <$> fa :: f (b -> c -> d)` and `f <$> fa <*> fb :: f (c -> d)` so that finally `f <$> fa <*> fb <*> fc :: f d`. I almost never use `<*>` without `<$>`. Your question arises because you don't usually think to make things of type `f (a -> b)`, but these exist as intermediate values. I could have `(+) <$> readLn :: IO (Int -> Int)` so that `(+) <$> readLn <$> readLn :: IO Int` – AndrewC Feb 04 '15 at 17:32

4 Answers4

6

Applicatives can be used for lots of stuff that you might also do with a monad, but that don't really need the stronger features of that class. (More precisely, whenever the “shape” of the functor doesn't depend on values within, then Applicative is sufficient.) For instance, an action like

foobar :: IO [String]
foobar = do
   fooTxt <- readFile "foo.txt"
   barTxt <- readFile "bar.txt"
   return $ zip (lines fooTxt) (lines barTxt)

could as well be written

foobar = zip <$> (lines <$> readFile "foo.txt")
             <*> (lines <$> readFile "bar.txt")

In this case, that makes it merely a tad shorter, but in other cases it may also improve performance (because Applicative is less general, more optimisations are possible) or allow you to make code more generic than when you use the Monad interface.

leftaroundabout
  • 117,950
  • 5
  • 174
  • 319
5

The most common use I have of it is to use multiple Monadic (or in this case Applicative) values for a function. A really common way I use it is for constructors.

Consider:

randomAge :: Rand StdGen Int
randomHeight :: Rand StdGen Double
randomWeight :: Rand StdGen Double

data Person = Person { age :: Int, height :: Double, weight :: Double }

randomPerson :: Rand StdGen Person
randomPerson = Person <$> randomAge <*> randomHeight <*> randomWeight

-- If we only had Monads...
randomPerson' :: Rand StdGen Person
randomPerson' = liftM3 Person randomAge randomHeight randomWeight
-- or worse...
randomPerson'' = randomAge >>= \ra -> randomHeight >>= \rh -> randomWeight >>= \rw -> return $ Person ra rh rw

Or this example from FPComplete's tutorial on the JSON parser Aeson:

instance FromJSON Person where
 parseJSON (Object v) =
    Person <$> v .: "firstName"
           <*> v .: "lastName"
           <*> v .: "age"
           <*> v .: "likesPizza"
 parseJSON _ = mzero

Or this example from the Real World Haskell chapter on Parser Combinators:

ghci> let parser = (++) <$> string "HT" <*> (string "TP" <|> string "ML")

For the most part Applicatives are useful when you have f :: a -> b -> c and you have m a and m b and you want an m c.

Edit: That said there are other uses. For example, Applicative can be used as a really good way to modify traversable data structures. E.g. applying a tree to a value, by having a tree of functions, thereby turning a value into a tree. Or doing non-deterministic list operations without list comprehension syntax.

It can have some unexpected applications. For example, using the -> Monad:

> (<*>) (+) (+1) 2
5

That last one was a bit more esoteric and isn't likely to be used in a practical circumstance but it shows that you can use Applicatives in many ways.

TheCriticalImperitive
  • 1,457
  • 1
  • 10
  • 23
3

It's the basic building block (along with pure) for other very useful functions like liftA2 (which you could think of as "fmap over two containers" and not be too far off the mark):

liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
liftA2 f fa fb = pure f <*> fa <*> fb

So suppose you want to add all combinations of values of two lists xs, ys :: [Integer], you could do it this way:

liftA2 (+) xs ys

Though more commonly we write this:

(+) <$> xs <*> ys

You are right to be puzzled why would somebody ever write [(+),(*)] <*> [1,2] <*> [3,4]—I think it's a very artificial example. 99% of the time, Applicative is used, you fundamentally have one function that takes two or more arguments, and are looking to apply it to the values inside a functor that implements Applicative.

One way of looking at it is that we could alternatively define Applicative and associated functions like this:

-- Not the real definition
class Functor f => Applicative f where
    pure :: a -> f a

    -- Like `fmap` but for two-argument functions:
    liftA2 :: (a -> b -> c) -> f a -> f b -> f c

-- `<*>` and `liftA2` are interdefinable, as shown further up and just here:
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
ff <*> fa = liftA2 ($) ff fa

But the reason <*> is picked as the class method is that it makes it very easy to write liftA2, liftA3, etc.:

liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
liftA2 f fa fb = pure f <*> fa <*> fb

liftA3 :: Applicative f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d
liftA3 f fa fb fc = pure f <*> fa <*> fb <*> fc

liftA4 :: Applicative f => (a -> b -> c -> d -> e) -> f a -> f b -> f c -> f d -> f e
liftA4 f fa fb fc fd = pure f <*> fa <*> fb <*> fc <*> fd

The Applicative class is very nearly the minimum functionality needed to support this "map with a function of multiple arguments" pattern, which is a useful thing in tons of cases.

Luis Casillas
  • 29,802
  • 7
  • 49
  • 102
  • 1
    It also seems to me that the `Applicative` laws are easier to express and at least somewhat more intuitive using `<*>` than using `liftA2`. – dfeuer Feb 04 '15 at 06:14
  • 2
    @dfeuer: But perhaps even easier if we used `<,> :: Applicative f -> f a -> f b -> f (a, b)` as the basic operator instead. The associative law becomes `(x <,> y) <,> z == x <,> (y <,> z)`. But the problem with that is that we don't want `Applicative` instances allocating useless pairs at runtime... – Luis Casillas Feb 04 '15 at 07:24
1

As leftaroundabout mentioned, whenever the "shape" of each "action" doesn't depend on the values "produced" by the previous one, Applicative is sufficient.

This may be a shape in a very literal way. For example, one context for >>= is that t >>= f takes values stored in the leaves of a tree t, applies f to each value to produce a new subtree, and grafts each subtree onto the tree in place of its corresponding leaf. This operation, however, doesn't work for a balanced tree, because there's no telling how large/deep a tree f will produce each time. However, <*> may still make sense, because the grafted trees will all have the same shape, maintaining balance.

dfeuer
  • 48,079
  • 5
  • 63
  • 167