Reputation: 674
I'm relatively new to functional programming and libraries such as ramda.js but one thing I found very useful is the possibility of currying functions.
Using curried functions I write very often things as the following
const myFun = R.curry(
(arg1, arg2) => {
let calculated = anotherFun(arg1)
//do something with calculated and arg2
return calculated * 5 + arg2
}
)
const anotherFun = (arg) => {
console.log("calling anotherFun");
return arg + 1
}
var partial = myFun(1)
console.log(partial(2))
console.log(partial(3))
<script src="//cdn.jsdelivr.net/ramda/0.22.1/ramda.min.js"></script>
but clearly in this situation anotherFun
is called every time I call partial
even if in arg1
and as a consequence calculated
are always the same.
Is there a way to optimize this behaviour and call anotherFun
only when its args change?
The only way that crosses my mind is this
const myFun = R.curry(
(calculated, arg2) => {
return calculated * 5 + arg2
}
)
const anotherFun = (arg) => {
console.log("calling anotherFun");
return arg + 1
}
var calculated = anotherFun(1)
var partial = myFun(calculated)
console.log(partial(2))
console.log(partial(3))
<script src="//cdn.jsdelivr.net/ramda/0.22.1/ramda.min.js"></script>
but in this way I have to change the arguments passed to myFun and this complicates the external API
Upvotes: 0
Views: 191
Reputation: 307
How about useWith
and memoize
from Ramda?
const myFun = R.useWith(
(a, b) => a * 5 + b,
[R.memoize(anotherFun), R.identity]
);
Upvotes: 0
Reputation: 50807
@Bergi is right that Ramda will not offer you any help with this. If you want a Ramda-style result, where you can call with one parameter to get a function back or both to get the result you can do this:
const myFun = function(arg1, arg2) {
let calculated = anotherFun(arg1);
const newFunc = arg2 => {
return calculated * 5 + arg2
};
return (arguments.length < 2) ? newFunc : newFunc(arg2);
};
const with3 = myFun(3);
//: calling anotherFun
with3(1); //=> 21
with3(2); //=> 22
with3(4); //=> 23
myFun(2, 7);
//: calling anotherFun
//=> 22
myFun(2, 8);
//: calling anotherFun
//=> 23
This comes at the cost of not being able to use ES2015 arrow functions. But it might be worth it to you.
You can also rework this slightly to not build the internal function if both parameters are supplied, if that is important to you.
Upvotes: 1
Reputation: 665040
If you do the currying manually like this
const myFun = arg1 => arg2 => {
let calculated = anotherFun(arg1)
// do something with calculated and arg2
return calculated * 5 + arg2
};
you can also make this optimisation:
const myFun = arg1 => {
let calculated = anotherFun(arg1);
return arg2 => {
// do something with calculated and arg2
return calculated * 5 + arg2
};
};
I don't think Ramda will help you here with anything; and JavaScript compilers certainly are not doing this kind of optimisation.
Upvotes: 3