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