## DEV Community is a community of 867,901 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

# FP serves the most delicious abstractions

For instance, if we try to combine two composed applicatives of type `Task<Option<number[]>, E>` - an async computation that may fail or yields any number of numbers - it gets pretty soon pretty ugly:

``````// tAp/tMap     = Task functor/applicative
// optAp/optMap = Option functor/applicative
// arrAp/arrMap = Array functor/applicative

tAp(
tMap(x_ => y_ =>
optAp(
optMap(x => y =>
arrAp(
(tttx))
``````

We can get rid of the anonymous functions by using point-free style, but the computation still remains hideous and confusing:

``````const comp = f => g => x => f(g(x));

tAp(
tMap(
comp(optAp)
(optMap(
(tttx))
``````

The problem seems to be the common applicative pattern `ap(map(f) (x)) (y)`. Let's abstract it:

``````const liftA2 = ({map, ap}) => f => tx => ty =>
ap(map(f) (tx)) (ty);

const tLiftA2 = liftA2({map: tMap, ap: tAp});
const optLiftA2 = liftA2({map: optMap, ap: optAp});
const arrLiftA2 = liftA2({map: arrMap, ap: arrAp});

comp3(
tLiftA2)
(optLiftA2)
(arrLiftA2)
This is much better. `comp3` takes three functions and the resulting composed function takes `add` and two composed values `tttx`/`ttty` and applies `add` to the inner values. Since applicative computation of the `Array` type means to calculate the cartesian product this is what we get. Nice.