# Why using `_.chain` is a mistake.

`import _ from "lodash";_.chain([1, 2, 3])  .map(x => [x, x*2])  .flatten()  .sort()  .value();`
`import map from "lodash/fp/map";import flatten from "lodash/fp/flatten";import sortBy from "lodash/fp/sortBy";import flow from "lodash/fp/flow";flow(  map(x => [x, x*2]),  flatten,  sortBy(x => x) )([1,2,3]);`

## Prior Art

`(_.flatten(_.map([1, 2, 3], x => [x, x*2]))).slice().sort();`
`_.chain([1, 2, 3])  .map(x => [x, x*2])  .flatten()  .sort()  .value();`

# The Problem

## It Can Get Big

`_.chain = (array) => wrap(array, _); // Rough concept of chain`
`import _ from "lodash"; // Import everything._.chain([1,2,3]).map(x => x+1).value(); // Use the methods.`
`import chain from "lodash/chain";import value from "lodash/value";import map from "lodash/map";import mixin from "lodash/mixin";import _ from "lodash/wrapperLodash";// Add the methods you want. The object generated by chain() will// now have these methods.mixin(_, {map: map, chain: chain, value: value});_.chain([1,2,3]).map(x => x+1).value(); // Use the methods.`

## It’s Not Nice to Extend

`import filter from "lodash/filter";const vowels = (array) => filter(array, str => /[aeiou]/i.test(str)`
`import _ from "lodash";_.mixin({vowels: vowels});_.chain(['ab','cd','ef']).vowels().value(); // Use the methods.`
`import chain from "lodash/chain";import value from "lodash/value";import map from "lodash/map";import mixin from "lodash/mixin";import _ from "lodash/wrapperLodash";mixin(_, { chain: chain,  value: value, map: map, // Add existing lodash methods you need. vowels: vowels, // Add your own lodash methods.});_.chain(['ab','cd','ef']).vowels().value(); // Use the methods.`
`import _ from "lodash";_.chain(['ab','cd','ef']).thru(vowels).value();`
`import chain from "lodash/chain";import value from "lodash/value";import mixin from "lodash/mixin";import thru from "lodash/thru";import _ from "lodash/wrapperLodash";// Have one file that only imports core lodash methods you need.mixin(_, { chain: chain,  value: value, thru: thru,});chain(['ab','cd','ef']).thru(vowels).value();`

# The Solution

## Currying

`const add = (a, b) => a + b;const add5 = _.partial(add, 5); // now `a` is bound (locked-in) to 5const add5 = (b) => 5 + b; // this is what it looks like insideadd5(3); // equivalent to invoking add(5, 3);`
`const add = (a) => (b) => a + b;add(1)(2); // Repeated partial application.`
`const add5 = add(5); // Implicit partial application!`

## Composition

`const add8 = (x) => add5(add3(x));`
`const add8 = compose(add5, add3);`

## All Together Now

`import "map" from "lodash/map";map([1, 2, 3], (x) => x*2);`
`const double = map((x) => x*2); // We want this!double([1, 2, 3]); // It now operates on just the input array!`
`import map from "lodash/fp/map";map((x) => x*2)([1, 2, 3]); // We have this!`
`import _ from "lodash";_.chain([1, 2, 3])  .map(x => [x, x*2])  .flatten()  .sort()  .value();`
`import map from "lodash/fp/map";import flatten from "lodash/fp/flatten";import sortBy from "lodash/fp/sortBy";import compose from "lodash/fp/compose";compose(  sortBy(x => x),   flatten,   map(x => [x, x*2]))([1,2,3]);`

# Caveats

## Argument Ordering

`compose(  sortBy(x => x),   flatten,   map(x => [x, x*2]));`
`sortBy(x => x)(  flatten(    map(x => [x, x*2])  ))([1, 2, 3]);`
`import map from "lodash/fp/map";import flatten from "lodash/fp/flatten";import sortBy from "lodash/fp/sortBy";import flow from "lodash/fp/flow";flow(  map(x => [x, x*2]),   flatten,   sortBy(x => x))([1, 2, 3]);`

## No Wrapper Object

“In fact our composition with flow/flowRight uses chaining internally (when monolithic) to support shortcut fusion in composed methods”

## Careful with Currying

`_.chain([1, 6, 2]).sortBy().value();`
`flow(sortBy)([1, 6, 2]);`
`const sortBy = (sorter = _.identity) => (array) => ...`
`sortBy([1, 6, 2]);`
`sortBy(/* _.identity */)([1, 6, 2]);`
`flow(sortBy())([1, 6, 2]);`

# Further Exploration

`add :: Num -> Num -> Numadd = x y = x + yadd 2 4`
`//          Num -> Num -> Numconst add = (a) => (b) => a + b;add(2)(4)`
`add8 = add5 . add3`
`//                   add5 . add3const add8 = compose(add5,  add3);`
`[1, 2, 3]  |> map(x => [x, x*2])  |> flatten,   |> sortBy(x => x);`

# What does it all mean?

by the author.

--

--

--

## More from Bootstart

This will go. Things.

## The Iterator Pattern ## The case against Non Null Assertion Operator ! ## Eight Queens Puzzle in TypeScript’s Type System 