1## lodash/fp
2
3The `lodash/fp` module promotes a more
4[functional programming](https://en.wikipedia.org/wiki/Functional_programming)
5(FP) friendly style by exporting an instance of `lodash` with its methods wrapped
6to produce immutable auto-curried iteratee-first data-last methods.
7
8## Installation
9
10In a browser:
11```html
12<script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>
13<script>
14// Loading `lodash.fp.js` converts `_` to its fp variant.
15_.defaults({ 'a': 2, 'b': 2 })({ 'a': 1 });
16// ➜ { 'a': 1, 'b': 2 }
17
18// Use `noConflict` to restore the pre-fp variant.
19var fp = _.noConflict();
20
21_.defaults({ 'a': 1 }, { 'a': 2, 'b': 2 });
22// ➜ { 'a': 1, 'b': 2 }
23fp.defaults({ 'a': 2, 'b': 2 })({ 'a': 1 });
24// ➜ { 'a': 1, 'b': 2 }
25</script>
26```
27
28In Node.js:
29```js
30// Load the fp build.
31var fp = require('lodash/fp');
32
33// Load a method category.
34var object = require('lodash/fp/object');
35
36// Load a single method for smaller builds with browserify/rollup/webpack.
37var extend = require('lodash/fp/extend');
38```
39
40## Mapping
41
42Immutable auto-curried iteratee-first data-last methods sound great, but what
43does that really mean for each method? Below is a breakdown of the mapping used
44to convert each method.
45
46#### Capped Iteratee Arguments
47
48Iteratee arguments are capped to avoid gotchas with variadic iteratees.
49```js
50// The `lodash/map` iteratee receives three arguments:
51// (value, index|key, collection)
52_.map(['6', '8', '10'], parseInt);
53// ➜ [6, NaN, 2]
54
55// The `lodash/fp/map` iteratee is capped at one argument:
56// (value)
57fp.map(parseInt)(['6', '8', '10']);
58// ➜ [6, 8, 10]
59```
60
61Methods that cap iteratees to one argument:<br>
62<%= toFuncList(_.keys(_.pickBy(mapping.iterateeAry, _.partial(_.eq, _, 1)))) %>
63
64Methods that cap iteratees to two arguments:<br>
65<%= toFuncList(_.keys(_.pickBy(mapping.iterateeAry, _.partial(_.eq, _, 2)))) %>
66
67The iteratee of `mapKeys` is capped to one argument: `(key)`
68
69#### Fixed Arity
70
71Methods have fixed arities to support auto-currying.
72```js
73// `lodash/padStart` accepts an optional `chars` param.
74_.padStart('a', 3, '-')
75// ➜ '--a'
76
77// `lodash/fp/padStart` does not.
78fp.padStart(3)('a');
79// ➜ '  a'
80fp.padCharsStart('-')(3)('a');
81// ➜ '--a'
82```
83
84Methods with a fixed arity of one:<br>
85<%= toFuncList(_.difference(mapping.aryMethod[1], _.keys(mapping.skipFixed))) %>
86
87Methods with a fixed arity of two:<br>
88<%= toFuncList(_.difference(mapping.aryMethod[2], _.keys(mapping.skipFixed))) %>
89
90Methods with a fixed arity of three:<br>
91<%= toFuncList(_.difference(mapping.aryMethod[3], _.keys(mapping.skipFixed))) %>
92
93Methods with a fixed arity of four:<br>
94<%= toFuncList(_.difference(mapping.aryMethod[4], _.keys(mapping.skipFixed))) %>
95
96#### Rearranged Arguments
97
98Method arguments are rearranged to make composition easier.
99```js
100// `lodash/filter` is data-first iteratee-last:
101// (collection, iteratee)
102var compact = _.partial(_.filter, _, Boolean);
103compact(['a', null, 'c']);
104// ➜ ['a', 'c']
105
106// `lodash/fp/filter` is iteratee-first data-last:
107// (iteratee, collection)
108var compact = fp.filter(Boolean);
109compact(['a', null, 'c']);
110// ➜ ['a', 'c']
111```
112
113##### Most methods follow these rules
114
115A fixed arity of two has an argument order of:<br>
116<%= toArgOrder(mapping.aryRearg[2]) %>
117
118A fixed arity of three has an argument order of:<br>
119<%= toArgOrder(mapping.aryRearg[3]) %>
120
121A fixed arity of four has an argument order of:<br>
122<%= toArgOrder(mapping.aryRearg[4]) %>
123
124##### Exceptions to the rules
125
126Methods that accept an array as their last, second to last, or only argument:<br>
127<%= toFuncList(_.keys(mapping.methodSpread)) %>
128
129Methods with unchanged argument orders:<br>
130<%= toFuncList(_.keys(mapping.skipRearg)) %>
131
132Methods with custom argument orders:<br>
133<%= _.map(_.keys(mapping.methodRearg), methodName => {
134  const orders = mapping.methodRearg[methodName];
135  return ' * `_.' + methodName + '` has an order of ' + toArgOrder(orders);
136}).join('\n') %>
137
138The iteratee of `reduceRight` has an argument order of: `(b, a)`
139
140#### New Methods
141
142Not all variadic methods have corresponding new method variants. Feel free to
143[request](https://github.com/lodash/lodash/blob/master/.github/CONTRIBUTING.md#feature-requests)
144any additions.
145
146Methods created to accommodate Lodash’s variadic methods:<br>
147<%= toFuncList(_.keys(mapping.remap)) %>
148
149#### Aliases
150
151There are <%= _.size(mapping.aliasToReal) %> method aliases:<br>
152<%= _.map(_.keys(mapping.aliasToReal).sort(), alias => {
153  const realName = mapping.aliasToReal[alias];
154  return ' * `_.' + alias + '` is an alias of `_.' + realName + '`';
155}).join('\n') %>
156
157## Placeholders
158
159The placeholder argument, which defaults to `_`, may be used to fill in method
160arguments in a different order. Placeholders are filled by the first available
161arguments of the curried returned function.
162```js
163// The equivalent of `2 > 5`.
164_.gt(2)(5);
165// ➜ false
166
167// The equivalent of `_.gt(5, 2)` or `5 > 2`.
168_.gt(_, 2)(5);
169// ➜ true
170```
171
172## Chaining
173
174The `lodash/fp` module **does not** convert chain sequence methods. See
175[Izaak Schroeder’s article](https://medium.com/making-internets/why-using-chain-is-a-mistake-9bc1f80d51ba)
176on using functional composition as an alternative to method chaining.
177
178## Convert
179
180Although `lodash/fp` & its method modules come pre-converted, there are times
181when you may want to customize the conversion. That’s when the `convert` method
182comes in handy.
183```js
184// Every option is `true` by default.
185var _fp = fp.convert({
186  // Specify capping iteratee arguments.
187  'cap': true,
188  // Specify currying.
189  'curry': true,
190  // Specify fixed arity.
191  'fixed': true,
192  // Specify immutable operations.
193  'immutable': true,
194  // Specify rearranging arguments.
195  'rearg': true
196});
197
198// The `convert` method is available on each method too.
199var mapValuesWithKey = fp.mapValues.convert({ 'cap': false });
200
201// Here’s an example of disabling iteratee argument caps to access the `key` param.
202mapValuesWithKey(function(value, key) {
203  return key == 'a' ? -1 : value;
204})({ 'a': 1, 'b': 1 });
205// => { 'a': -1, 'b': 1 }
206```
207
208Manual conversions are also possible with the `convert` module.
209```js
210var convert = require('lodash/fp/convert');
211
212// Convert by name.
213var assign = convert('assign', require('lodash.assign'));
214
215// Convert by object.
216var fp = convert({
217  'assign': require('lodash.assign'),
218  'chunk': require('lodash.chunk')
219});
220
221// Convert by `lodash` instance.
222var fp = convert(lodash.runInContext());
223```
224
225## Tooling
226
227Use [eslint-plugin-lodash-fp](https://www.npmjs.com/package/eslint-plugin-lodash-fp)
228to help use `lodash/fp` more efficiently.
229