I am trying to learn more about using currying and composition in functional programming by using Lodash/FP to clean up some old code. However, I am repeatedly running into situations where I have a function and I want to pass it one or more functions. I then want to pass the values that will be used as the arguments to the functions that I passed to the original function.
I'm finding it difficult to explain exactly what I'm trying to do so I made a JS Fiddle that shows how I have been trying to approach this: https://jsfiddle.net/harimau777/rqkLf1rg/2/
const foo = a => `${a}${a}`
// Desired Behavior: const ans1 = (a, b) => `${foo(a)}${foo(b)}`
const ans1 = _.compose(
(a, b) => `${a}${b}`,
foo,
foo
)
// Desired Result: '1122'
console.log(ans1('1', '2'))
// Desired Behavior: const ans2 = a => a.map(a => a + 1)
const ans2 = _.compose(
_.map,
a => a + 1
)
//Desired Result: [2, 3, 4]
console.log(ans2([1, 2, 3]))
Based on Ori Drori's answer below I think that I can clarify my question (is this how people normally follow up on StackOverflow as opposed to asking a new question?): Suppose that instead of applying the same sequence of functions to both inputs I wanted to apply a sequence of functions to the first input, a different sequence to the second input, and use both results as the input to the rest of the _.compose. I could do this using:
const f1 = _.compose(<Some sequence of functions>)
const f2 = _.compose(<Some sequence of functions>)
const f3 = <A function which takes two inputs>
const ans = _.compose(
<More functions here>,
f3
)(f1(a), f2(b))
console.log(ans)
However, I'm wondering if there is a way to handle this using a single compose or if there are any patterns that tend to be used in functional programming to handle situations like this.
LodashFPs _.compose()
(_.flowRight()
in lodash) works by applying the parameters to the right most (bottom in your code) function, and passes the result to the function to it's left, and so on:
_.compose(a, b, c)(params) -> a(b(c(params)))
This means that every function, except for the right most receives only one parameter.
You can get the 1st example working by changing the methods a bit:
const ans1 = _.compose(
arr => arr.join(''), // joins the params to one string
(...args) => args.map((s) => `${s}${s}`) // returns an array of double params
)
// Desired Result: '1122'
console.log(ans1('1', '2'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash-fp/0.10.4/lodash-fp.min.js"></script>
In the 2nd example you want to create a new method that maps via a predefined callback. Since lodash/fp methods are auto curried, you can supply the callback to the _.map()
, and get a new method. Compose won't work here since _.map()
doesn't use the results of the method directly, but applies it to every item in the array:
const ans2 = _.map(a => a + 1)
//Desired Result: [2, 3, 4]
console.log(ans2([1, 2, 3]))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash-fp/0.10.4/lodash-fp.min.js"></script>
The case you've presented in your clarification can be handled by _.useWith()
(known as _.overArgs()
in lodash):
Creates a function that invokes func with its arguments transformed.
However, it's use is not recommended since it reduces readability.
Example:
const foo = a => `${a}${a}`
const ans1 = _.useWith(
(a, b) => `${a}${b}`,
[
foo,
foo
]
)
const result = ans1(1, 2)
console.log(result)
<script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With