## DEV Community

Brian Berns

Posted on • Updated on

# Background

Previously, we learned about applicative functors, which are souped-up functors that support multi-argument mapping functions. In this post, I'd like to dive deeper into the practical usage of applicatives in F#.

We described an applicative as a type that:

• Is a functor, which means that it has a unary (i.e. single-argument) `map` function (and, thus, an infix version of the same function, called `<!>`).
• Provides a way to apply arguments one at a time, via a `<*>` function.
• Provides a way to "`lift`" values into the applicative.

# Example

F#'s `Option<'t>` type is an applicative:

``````let (<!>) = Option.map

let (<*>) fOpt xOpt =
match fOpt, xOpt with
| Some f, Some x -> Some (f x)
| _ -> None

let lift x = Some x
``````

This allows us, for example, to use multiplication to "map" over two options at once:

``````let mult = (*)

// functor: times3 takes one argument
let times3 = mult 3
Option.map times3 (Some 4)   // Some 12
Option.map times3 None       // None

// applicative: mult takes two arguments
mult <!> Some 3 <*> Some 4   // Some 12
mult <!> None   <*> Some 4   // None
mult <!> Some 3 <*> None     // None
``````

# Pipes

Applying arguments one at a time with `<*>` is certainly a legitimate way to think about applicatives, but (IMHO) it's not the most intuitive, nor is it used often in F#. I think it's easier to conceptualize applicatives with the lifted function (e.g. `mult`) at the end of a computation, instead of the beginning. Following the FParsec library, we'll call this "pipes" style:

``````let pipe2 a b f = f <!> a <*> b
``````

In the case of options, `pipe2` has the following signature:1

``````Option<'a> -> Option<'b> -> ('a -> 'b -> 'c) -> Option<'c>
``````

So `pipe2` is a function that sends the result of computations `a` and `b` to function `f`, producing a new computation. We can see it in action with options here:

``````pipe2 (Some 3) (Some 4) mult   // Some 12
pipe2 None (Some 4) mult       // None
``````

We can define `pipe3`, `pipe4`, etc. similarly.

Using pipes style, we can think of applicatives as performing computations in parallel at the same time, with no dependencies between them. For example, consider:

``````let runMult getOptA getOptB =
pipe2
(getOptA ())
(getOptB ())
mult
``````

Note that `getOptB` is executed even if `getOptA` returns `None`. There's no way to short-circuit the computation before `getOptB` is invoked.

Contrast this with monads, which are a way of performing computations in series, so that the result of one computation flows into the next. In fact, instead of thinking of applicatives as souped-up functors, it's often easier to think of them as a "lite" version of monads.2 Let's see where this notion takes us, starting with a basic computation builder for options:

``````type OptionBuilder() =
member __.Return(x) = Some x
member __.Bind(opt, binder) = Option.bind binder opt

let option = OptionBuilder()
``````

Using this builder, we can create monadic computation expressions, such as:

``````option {
let! a = optA
let! b = optB
return a * b
}
``````

Note that the computation of `b` does not depend in any way on the value of `a`, so a monad is overkill for this computation - it is merely applicative. We can enforce this limitation by removing the `Bind` method from the computation builder, but then the expression doesn't compile at all.

# F# 5 enhancements

Fortunately, F# now supports applicative computation expressions directly. There are two new core builder methods:

• `BindReturn`: Corresponds to `<!>`, which is just `map`.
• `MergeSources`: Similar to `<*>` and `pipe2`, except that it always produces a 2-tuple (instead of calling a function).

For our `option` builder, their implementation looks like this:

``````member __.BindReturn(opt, f) =
Option.map f opt

member __.MergeSources(optA, optB) =
match optA, optB with
| Some a, Some b -> Some (a, b)
| _ -> None
``````

Now that these two methods are present in the builder, `and!` can be used instead of `let!` to create an applicative expression:

``````option {
let! a = optA
and! b = optB   // OK because b does not depend on a
return a * b
}
``````

Because the applicative computations are independent, they can potentially be parallelized by the compiler, resulting in more efficient code. So be on the lookout for opportunities to use `and!` instead of `let!` in your F# code!

# References

1. Haskell calls this function `liftA2` instead of `pipe2`, where the `A` stands for "applicative".

2. So, just as every applicative is also a functor, every monad is also an applicative. However, not every applicative is a monad, which is what makes the applicative pattern useful on its own, situated between its two better-known cousins.