I have 4 functions calling one after another:
var res = f1(f2(f3(f4(f5(a, b), 1, 2, true))))
Is there any cleaner way to refactor this.
I want to be able to see the parameters and the code should be minimal.
I can do it like this:
let s1 = f5(a, b);
let s2 = f4(s1, 1, 2, true);
let res = f1(f2(f3(s2)))
But i dont want to introduce another variables.
can i do it short and easy to read/refactor.
Thanks
var res = f1(f2(f3(f4(f5(a, b), 1, 2, true))))
Is there any cleaner way to refactor this. I want to be able to see the parameters and the code should be minimal.
That seems pretty minimal to me.
since f1, f2 and f3 have only their result as parameter, you could merge them into one function f123.
But I don't see how this would be really helpful for you as a developer.
5 functions calls is not that horrible.
I can do it like this:
let s1 = f5(a, b);
let s2 = f4(s1, 1, 2, true);
let res = f1(f2(f3(s2)))
But i dont want to introduce another variables.
I very much like the way with additional intermediate variables. this make the code easy to read for another developer (including yourself 2 weeks later from now)
I don't understand why it is a problem for you. Could you elaborate more ?
Another possiblity is to use some pipelining machinery. That would absolutely not be minimal code, but that could make the code clearer by making the logical order of operations more apparent.
For instance : Observable (RxJS)
Observable.of(f5(a,b))
.map(r5 => f4(r5, 1, 2, true))
.map(r4 => f3(r4))
.map(r3 => f2(r3))
.map(r2 => f1(r2))
.subscribe(r => console.log(r))
But in a sense, you would have some "intermediate variables" represented by the parameter of the lambda expressions.
var res = f1(
f2(
f3(
f4(
f5(a, b),
1,
2,
true
)
)
)
);
or just save the results in vars...
var result_f5 = f5(a, b);
var result_f4 = f4(result_f5, 1, 2, true);
var result_f3 = f3(result_f4);
var result_f2 = f2(result_f3);
var result_f1 = f1(result_f2);
I prefer the second way...
There is no other "quicker" or "cleaner" way
You could reduce from the right side, but it needs the nested function f4 with f5 as start value.
var x = [f1, f2, f3].reduceRight((x, f) => f(x), f4(f5(a, b), 1, 2, true));
// ^^^^^^^^^^^^^^^^^^^^^^^^ start value
// ^^^^^^^^^^^^ functions
IMHO the most readable and clean way is to add another function that makes this sequence of function calls. I.e:
function f0 (a, b, c, d, e) { return f1(f2(f3(f4(f5(a, b), c, d, e)))); }
then simply call:
var res = f0(a, b, 1, 2, true);
// consider this function as small library or hidden part.
// it's composition/high-order function
var f = (func, ...rest) => {
if(typeof func === "function") {
if(this.__res)
this.__res = func(this.__res, ...rest)
else
this.__res = func(...rest)
return f
} else {
var result = this.__res
this.__res = undefined
return result
}
}
// the real part you want is here
var res = f(f5, a, b)(f4, 1,2,true)(f3)(f2)(f1)()
I know you don't want to introduce another variables.
but when you consider function f as hidden part of a library or module/package, f(f5, a, b)(f4, 1,2,true)(f3)(f2)(f1)() is more readable and clean, isn't it?
Related
I am reading right now the source code of Ramda and don't understand the point of _curry1().
function _curry1(fn) {
return function f1(a) {
if (arguments.length === 0 || _isPlaceholder(a)) {
return f1;
} else {
return fn.apply(this, arguments);
}
};
}
Functions that are curried with this function can be called without arguments.
const inc = (n) => n + 1
const curriedInc = _curry1(inc)
// now it can be called like this
curriedInc(1) // => 2
curriedInc()(1) // => 2
// but it works only with no arguments provided
const add = (a, b) => a + b
const curriedAdd = _curry1(add)
curriedAdd(1) // => NaN
curriedAdd(1)(1) // => TypeError: curriedAdd(...) is not a function
curriedAdd() // => function f1(a)
Question:
It seems to me that you can't chain arguments with this function at all. What are use cases for this function? How different is curriedInc()(1) from inc(1)?
_curry1, _curry2, and _curry3 are performance-boosting tricks that can't be used in the public curry function. Ramda (disclaimer: I'm an author) uses them to perform several tasks, clearly mostly doing the currying, but also checking for placeholders so that we can properly do some partial application. The other magic thing about Ramda's currying is the way that you can apply all, some, or even none of the required arguments, and so long as we're not complete, you get back another function looking for the remaining ones.
Obviously _curry1 theoretically shouldn't be necessary, but it makes it easier to add this sort of consistency:
const a = curry ((a, b, c) => ...)
a (1, 2, 3) == a (1, 2) (3) == a (1) (2, 3) == a (1) (2) (3) == a () () (1, 2) () (3)
Notice that last one. When you call a curried function still looking for arguments with no arguments at all, you get back the same function.
curry1 is what makes that happen; it adds consistency. But that's all it's for.
I have a function with a required parameter (A), some optional parameters (B,C) and a rest parameter (Z)
const doTheThing = (a, b = 'B', c = 'C', ...z) => {
console.log(a, b, c, z);
}
I have cases where I would like to call the function without specifying the optional parameters, but still specify the rest parameter "Z"
doTheThing('A', ...'Z');
Expected Output:
'A', 'B', 'C', 'Z'
Unfortunately, I get the following:
Parsing error: Shorthand property assignments are valid only in destructuring patterns
How do I go about solving this?
JavaScript doesn't allow supplying named parameters or any sort of parameter skipping, so it's not possible to do what you want with the function in its current form. Here are some alternatives, though:
Plain JavaScript approach: a configuration Object as parameter
Instead of accepting multiple parameters
func = (a, b, c) => { /* operate with parameters */ }
func("One", "Two", "Three")
your function will instead accept an object
func = config => { /* operate with config */ }
func({a: "One", b: "Two", c: "Three"})
This is a common pattern in JavaScript because it allows you to almost name your variables and doesn't require you pass them in the correct order.. It makes it easy to pass a large quantity of them and it can also make it easy to default them, too.
const doTheThing = (config) => {
const defaultProperties = {
b: "B",
c: "C"
}
const {a, b, c, ...rest} = Object.assign({}, defaultProperties, config);
const z = Object.values(rest); //extract their values, otherwise you get an object
console.log(a, b, c, z);
}
doTheThing({a: "A", x: "X", y: "Y", z: "Z"});
It is slightly clunky to use with rest parameters but not unworkable.
However, it does mean that it may be harder to see what parameters you can pass and what is required, if you have a large number of them.
Object Oriented approach: Builder pattern
You create a builder object - it serves to hold values until you call the final method at which point it takes all parameters and constructs an object in one go.
This is how more Object Oriented languages handle having a multitude of parameters where you can even have some of them optional. It's not really common to see builders defined like this in JavaScript but it's not too strange, either. If you use classes already or even TypeScript, then this is probably a better fit.
class DoTheThingBuilder {
constructor() {
this.a = null;
this.b = "B";
this.c = "C";
this.z = null;
}
withA(a) {
this.a = a;
return this;
}
withB(b) {
this.b = b;
return this;
}
withC(c) {
this.c = c;
return this;
}
withEverythingElse(...z) {
this.z = z;
return this;
}
doTheActualThing() {
const {a, b, c, z} = this;
console.log(a, b, c, z);
}
}
const builder = new DoTheThingBuilder();
builder
.withA("A")
.withEverythingElse("X", "Y", "Z")
.doTheActualThing();
As you can see, this can be pretty verbose for some simple tasks. It is a big overkill for this example, but perhaps in actual usage, you might find it helps.
I've deviated a bit from the usual approach - normally, you would set all parameters needed with the builder and finally call .build() which constructs an object. In this case, I basically renamed build to doTheActualThing and it's executing the function.
Functional approach: Currying
The concept of currying is quite simple - instead of having one function that accepts several parameters
func = (a, b, c) => { /* operate with parameters */ }
you have a function that takes one parameter, that returns a function that takes the second parameter, that returns another function, etc., until all parameters are satisfied, at which point the full function is executed.
func = a => b => c => { /* operate with parameters */ }
In many ways, this is the functional equivalent of the OO Builder pattern.
const doTheThing = (a) =>
(b = "B") =>
(c = 'C') =>
(...z) => console.log(a, b, c, z);
doTheThing("A")()()("X", "Y", "Z");
This way you can skip the second and third parameter by not supplying them and you'd get the defaults. It's also way shorter than a builder. However, reading the function can be a bit weird.
That is not possible and very error-prone. The point of naming your parameters is to know what they are and in what order they are coming.
You could achieve something similar using object as a function parameter:
const doTheThing = ({ a, b = "B", c = "C", others = {} }) => {
const params = { a, b, c, ...others }; // this will merge your parameters into one object
console.log(params);
}
doTheThing({ a: "A", others: { z: "Z" }});
This will log A, B, C, Z. Demo: https://codepen.io/tomekbuszewski/pen/jQqmNL?editors=0011
Is there way to get my own custom function in a chain of lodash. So for example like this:
var l = [1,2,3]
var add = function(a, b){return a+b}
var r =_.chain(l).find(function(a){return a>1}).add(5).value()
=>r = 7
What you look for is a way to extend the lodash prototype. It so nicely turns out that you can do it easily with a mixin utility function. Check here the docs:
http://lodash.com/docs#mixin
In your example it will look like:
var l = [1,2,3];
var add = function(a, b){return a+b}
_.mixin({
add: add
});
var r =_.chain(l).find(function(a){return a>1}).add(5).value()
console.log(r); ==> 7
and here is live sample on fiddle: http://jsfiddle.net/g2A9C/
After #stride anwswer I came up with a more generic solution using _.mixin:
function add(a, b, c) {
return a + b + c
}
function sub(a, b, c) {
return a - b - c
}
_.mixin({
run: function (v, f) {
var args = Array.prototype.slice.call(arguments, 2)
args.unshift(v)
return f.apply(this, args)
}
})
var r = _.chain(1).run(add, 1, 1).run(sub, 2, 2).value()
console.log(r) -> -1
1 + 1 + 1 - 2 - 2 = -1
http://jsbin.com/iyEhaMa/1/
After all I wonder why this not a build in function in lodash.
Another option is to just drop chaining and leverage function composition through _.flow.
From the DOCS:
[Flow] Creates a function that returns the result of invoking the given
functions with the this binding of the created function, where each
successive invocation is supplied the return value of the previous.
This means that every function inside Flow will receive as input the output of the previous one. In practice this means we are not limited to using only Lodash API methods, but we can mix and match whatever function we fancy, as long as the next one is able to handle that return value.
var l = [1,2,3]
var add = _.curry((a, b) => a + b);
_.flow(
_.find(a => a > 1),
add(5),
)(l);
// => 7
NB - This example is using the Functional version of Lodash, if you don't want or can't use that one you can still achieve the same result, check my other answer to another question about Lodash.
Maybe it's too late but _.tap is another chance
Many times I face the same problem: I want to filter an array with a simple condition e.g. check for non/equality, greater than, less than, contains...
My code looks like this:
var result = [1, 2, 3, 4].filter(function(i) {
return i > 2;
});
console.log(result); // [3, 4]
It would by nice to have shortcuts to such a simple operations so
I created some helper functions:
function isGreaterThan(value) {
return function(original) {
return value < original;
}
}
[1, 2, 3, 4].filter(isGreaterThan(2)); // [3, 4]
or:
function isGreaterThan(value, original) {
return value < original;
}
[1, 2, 3, 4].filter(isGreaterThan.bind(null, 2)); // [3, 4]
Is there a better way how to do this in javascript? Does javascript have any built-in functions to support these simple comparisions?
Madox, what you've stumbled upon is the concept of currying! And you'll be glad to hear that there is an entire JavaScript community built around that idea. With Ramda your code would look like:
var filterSmallNumbers = filter(gte(3));
var smallNumbers = filterSmallNumbers([1,2,3,4,5,6]);
And it works.
All Ramda provides, is a list of "curried helper functions" like the one you showed. If you'd rather curry your own helper functions, then you might want a curry helper function which reduces the boilerplate: var isGreaterThan = curry(function(a, b){ return a > b }). This curry function is provided by most utility libraries like Underscore, Lodash or Ramda.
I'll expand on #Avaq's answer a little bit here. You don't need a lib like Rambda to start using currying. You can start doing this with ES6 today.
It seems you already understand the concept here. This is already a curried function. (Each sequenced function takes only one argument)
function isGreaterThan(value) {
return function(original) {
return value < original;
}
}
With ES6 arrow functions, this gets a lot easier.
const gt = x => y => y > x;
Notice how you flipped the the operator > to a < in your function to make the usage seem more natural? It's very common with curried functions to first take the operand that is least likely to change. With gt, I think it's better to use > here since that's the name of our function, but instead flip the operands. That's why you see me returning y > x instead of x > y. gt(5) returns a function y => y > 5, which feels very natural to me.
Without further ado, let's see it work in a filter
[1,2,3,4,5,6].filter(gt(3)); //=> [4,5,6]
If you need this to work in an ES5 environment, you can transpile it with babel very easily. The result should look very familiar
"use strict";
var gt = function gt(x) {
return function (y) {
return y > x;
};
};
And with that, you're at the doorstep of functional programming. There's a ton of fun stuff to learn. With the kind of problem we discussed here, I think you'd be interested in learning about function composition next.
Here's a basic composition to whet your appetite
// filter out odd numbers
const mod = x => y => y % x;
const eq = x => y => y === x;
const comp = f => g => x => f(g(x));
const isEven = comp (eq (0)) (mod (2));
[1,2,3,4,5,6].filter(isEven); //=> [2,4,6]
you were almost there, here is the correct one:
var original = 2;
function isGreaterThan(value) {
return value > original;
}
var result = [1, 2, 3, 4].filter(isGreaterThan);
// result is [3, 4]
reference
I've written a CoffeeScript function that resembles this contrived example:
my_func = (a, b, use_args = false) ->
if use_args?
other_func 'foo', a, b, 'bar'
else
other_func 'foo', 'bar'
This compiles to the following JavaScript:
var my_func;
my_func = function(a, b, use_args) {
if (use_args == null) {
use_args = false;
}
if (use_args != null) {
return other_func('foo', a, b, 'bar');
} else {
return other_func('foo', 'bar');
}
};
Is there a DRY approach to this function that would eliminate the duplicate call to other_func? Something like:
my_func = (a, b, use_args = false) ->
other_func 'foo', a if use_args?, b if use_args?, 'bar'
but that's actually syntactically correct? Hopefully I'm not missing something obvious here. I'm not sure if CoffeeScript provides a handy way to do this, or if there's just a better JavaScript pattern I should be using.
Incidentally, I can't modify other_func to use different parameters, since it's actually _gaq.push(), part of the Google Analytics library that adds tracking information to a queue.
First off, I think the code in your original question is fine (other than the = false in the argument list—see my comment). It's perfectly efficient and readable. But if the repetition really bothers you, read on.
Chris is on the right track in his answer. Since this is CoffeeScript, there are some syntactic sugars you can take advantage of:
Instead of arr.splice(1, 0, [a, b]), you can write arr[1...1] = [a, b].
Instead of func.apply(null, arr), you can simply write func arr....
So, combining those, you can get your function down to 3 short, repetition-free lines:
my_func = (a, b, use_args) ->
args = [foo, bar]
args[1...1] = [a, b] if use_args
other_func args...
Notice that you don't have to do a use_args? check; if it's null or undefined, it'll be coerced to false automatically (by JavaScript) for if use_args.
Use a combination of:
Array.splice() to inject the additional parameters in to an array of params, and
apply() to call the function with an array of parameters.
Here's a demo:
http://jsfiddle.net/ZSVtB/
var my_func = function(a, b, use_args) {
var args = []
args.push('foo')
use_args && args.push(a, b)
args.push('bar')
return other_func.apply(null, args)
}
Okay, no with from now on.