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.
Here, I am new to JavaScript. I am solving questions; however, I am having a problem understanding chaining more than one method together. I have been trying to understand this solution, but it took me a lot of time, and I still don't get it.
I understand that I will input the array that I needed to change according to the specific function, which I opted. I understand all of methods functions, but I don't understand their syntax here, so can someone please explain each step to me ?
const group_By = (arr, fn) =>
arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val, i) => {
acc[val] = (acc[val] || []).concat(arr[i]);
return acc;
}, {});
In as few words as possible.
Firstly they compute a ternary expression, here they are checking if the input is a function, if it is they pass it as is, otherwise they create an anonymous function that tries to access the given property. The arrow function after the colon can seem a little confusing but it's still just a function. It takes one argument called val, and returns property which key is inside the fn variable.
typeof fn === 'function' ? fn : val => val[fn]
The next step is to create a new array with new values for each of the elements. Output of this step is just a list of values to group elements on.
For instance calling it on array ["a", "bb"] with a fn='length' would return [1,2]
arr.map(typeof fn === 'function' ? fn : val => val[fn])
Then they call the .reduce function on the output array. The purpose of the reduce function is to create a single value out of all the elements slowly iterating over it. You can tell that the last step returns accumulator value back, and that it is passed as a first argument to the function called on the next element. The empty object at the end is just an initial value of the accumulator.
.reduce((acc, val, i) => {
...
return acc;
}, {});
And finally for the step that does the accumulation. Here firstly the val from the result of the map, is used to access property of the newly created object. If the value does not exist it replaced with an empty array || []. That has the element of the initial array at the same index concatenated onto it. If there were some elements it just adds new ones to it and reassigns the value.
acc[val] = (acc[val] || []).concat(arr[i]);
Okay, what I understood from your query is that you are trying to chain multiple functions together.
function Chained() {
// this reference.
const _this_ = this
this.Function1 = () => // do something and return _this_
this.Function2 = () => // do something here and return _this_
}
Above you can see that chain is a simple object which returns "this" as context. and on context, we already have Function1 and Function2. so due to this following will be valid.
const _ExecuteChained = new Chained()
// Now you can run _ExecuteChained.Function1().Function2() and so on.
Now coming to your code.
const group_By = (arr, fn) =>
arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val,
i) => {
acc[val] = (acc[val] || []).concat(arr[i]);
return acc;
}, {});
Here you are just running a loop on arr and validating if the second param is a function or not if function then return it as is (Since you are using a map it will be stored at the given index. else just get the value of the function at the given key and return it.
Reduce.
in Reduce you are trying to accumulate a given value with (contact or merge or extend) value at a given index of arr in this case function.
I want to create a functions that returns the parameter of another function. I know I can use argument or rest operator to access parameter inside a function itself, but how can I get them outside that function?
const returnValue = (fn) => {
//How can I get the parameter of fn? Assume I know its arity.
}
For example:
const foo = 'bar'
const hello = 'world'
const returnFirstArgument = (val1, val2) => val1
const returnArgumentByPosition = (fn, num) => {
//Take fn as input, return one of its parameter by number
}
const returnSecondArgument = returnArgumentByPosition(returnFirstArgument(foo, hello), 1) //Expect it returns 'world'
What you want isn't possible to do without modifying how returnFirstArgument behaves. Take for example the below piece of code:
const x = 1 + 2;
console.log(x); // 3
Before a value is assigned to x, the expression 1 + 2 needs to be evaluated to a value. In this case 1 + 2 gets evaluated to 3, so x gets assigned to 3, that way when we print it, it prints the literal number 3 out in the console. Since it is now just a number, we can't tell how 3 was derived (it could have come from 0 + 3, 1 * 3, etc...).
Now take a similar example below:
const max = Math.max(1, 2);
console.log(max); // 2
The same idea here applies from above. First Math.max(1, 2) is evaluated to the value of 2, which is then assigned to max. Again, we have no way of telling how 2 was derived.
Now consider a function:
const add = (x, y) => x + y;
const ans = add(1 + 2, Math.max(1, 2));
console.log(ans); // 5
When we call the function, the function's arguments are first evaluated to values. The parameters within the function are then assigned to copies of these values:
const ans = add(1 + 2, Math.max(1, 2));
// ^--------^------------- both evaluate first before function is invoked
so the above function call becomes:
const ans = add(3, 2);
As a result, inside the add function, x becomes 3 and y becomes 2. Just like with the above first two examples with variables, we have no way of knowing the 3 came from the expression 1+2 and that 2 came from the function call of Math.max(1, 2).
So, relating this back to your original question. Your function call is analogous to the add function call shown above:
const returnSecondArgument = returnArgumentByPosition(returnFirstArgument(foo, hello), 1)
just like in the other examples, the arguments passed to the function can't be expressions, so they need to be evaluated first to values. returnFirstArgument(foo, hello) is evaluated to a value before the returnArgumentByPosition function is invoked. It will evaluate to the string "bar". This results in fn becoming "bar" inside of your returnArgumentByPosition. As "bar" is just a string, we again have to way of telling where it came from, and so, won't have access to the function which created it. As a result, we can't access the second argument of the function, since this information is not retained anywhere.
One approach to do what you're after is to create a recall function. The recall function is able to "save" the arguments you passed into it, and then expose them later. Put simply, it wraps your original function but is able to save the arguments and the result of calling your original function:
const recall = fn => (...args) => {
return {
args,
result: fn(...args),
}
};
const add = recall((x, y) => x + y);
const getN = ({args}, n) => {
return args[n];
}
const res = getN(add(1, 2), 1);
console.log(res);
The above approach means that add() will return an object. To get the result of calling add, you can use .result. The same idea applies to get the arguments of add(). You can use .args on the returned object. This way of saving data is fine, however, if you want a more functional approach, you can save the data as arguments to a function:
const recall = fn => (...args) => {
return selector => selector(
args, // arguments
fn(...args) // result
);
};
// Selectors
const args = args => args;
const result = (_, result) => result;
const getN = (wrapped, n) => {
return wrapped(args)[n];
}
const add = recall((x, y) => x + y);
const wrappedAns = add(1, 2);
const nth = getN(wrappedAns, 1);
console.log(nth); // the second argument
console.log(wrappedAns(result)); // result of 1 + 2
above, rather than returning an object like we were before, we're instead returning a function of the form:
return selector => selector(args, fn(...args));
here you can see that selector is a function itself which gets passed the arguments as well as the result of calling fn() (ie: your addition function). Above, I have defined two selector functions, one called args and another called result. If the selector above is the args function then it will be passed args as the first argument, which it then returns. Similarly, if the selector function above is the result function, it will get passed both the args and the result of calling fn, and will return the result the return value of fn(...args).
Tidying up the above (removing explicit returns etc) and applying it to your example we get the following:
const foo = 'bar';
const hello = 'world';
const recall = fn => (...args) => sel => sel(args, fn(...args));
const returnFirstArgument = recall((val1, val2) => val1);
const returnArgumentByPosition = (fn, num) => fn(x => x)[num];
const returnSecondArgument = returnArgumentByPosition(returnFirstArgument(foo, hello), 1);
console.log(returnSecondArgument); // world
Side note (for an approach using combinators):
In functional programming, there is a concept of combinators. Combinators are functions which can be used as a basis to form other (more useful) functions.
One combinator is the identity-function, which simply takes its first argument and returns it:
const I = x => x;
Another combinator is the K-combinator, which has the following structure:
const K = x => y => x;
You may have noticed that the first selector function args is missing an argument. This is because JavaScript doesn't require you to enter all the parameters that are passed as arguments into the function definition, instead, you can list only the ones you need. If we were to rewrite the args function so that it showed all the arguments that it takes, then it would have the following structure:
const args = (args, result) => args;
If we curry the arguments of this function, we get:
const args = args => result => args;
If you compare this function to the K-combinator above, it has the exact same shape. The K-combinator returns the first curried argument, and ignores the rest, the same applies with our args function. So, we can say that args = K.
Similarly, we can do a similar thing for the result selector shown above. First, we can curry the arguments of the results selector:
const result = _ => result => result;
Notice that this almost has the same shape as the K combinator, except that we're returning the second argument rather than the first. If we pass the identify function into the K-combinator like so K(I), we get the following:
const K = x => y => x;
K(I) returns y => I
As we know that I is x => x, we can rewrite the returned value of y => I in terms of x:
y => I
can be written as...
y => x => x;
We can then alpha-reduce (change the name of y to _ and x to result) to get _ => result => result. This now is the exact same result as the curried result function. Changing variable names like this is perfectly fine, as they still refer to the same thing once changed.
So, if we modify how selector is called in the recall function so that it is now curried, we can make use of the I and K combinators:
const I = x => x;
const K = x => y => x;
const recall = fn => (...args) => sel => sel(args)(fn(...args));
const args = K;
const result = K(I);
const getN = (fn, n) => fn(args)[n];
const add = recall((x, y) => x + y);
const addFn = add(1, 2);
const nth = getN(addFn, 1);
console.log(nth); // the second argument
console.log(addFn(result)); // result of 1 + 2
I'm having trouble understanding a solution to a coding challenge that uses arrow functions and the .every() method and was hoping someone more knowledgeable could explain what's going on. The challenge is to check a grid to see if it represents a true sudoku board. I understand the first part concatenates and multiplies a row/col/square, but can't understand the latter part...
// True, if product of #s in row is 9!
p = a => eval(a.join("*")) == (1*2*3*4*5*6*7*8*9);
// Check each row, column and 3 block grid using p()
sudoku = grid =>
grid.every((r,i) =>
p(r) &&
p(grid.map(r => r[i])) &&
p(r.map((_,j) => grid[3*(i/3|0)+(j/3|0)][3*(i%3)+(j%3)]) ) )
Thank you for the help!
Seems input data for sudoku is 2d array like this one:
let grid = [
[2,4,1,7,6,8,5,3,9],
[5,7,3,9,2,4,1,8,6],
[8,9,6,5,3,1,7,4,2],
[7,3,4,2,9,5,6,1,8],
[1,8,9,4,7,6,3,2,5],
[6,5,2,8,1,3,4,9,7],
[4,6,5,3,8,2,9,7,1],
[3,2,7,1,5,9,8,6,4],
[9,1,8,6,4,7,2,5,3]
]
To validate Sudoku we have to check all rows, columns and sub-grids
Code explanation:
p = a => eval(a.join("*")) == (1*2*3*4*5*6*7*8*9);
This is an equivalent for
p = function(a) {
return eval(a.join("*")) == (1*2*3*4*5*6*7*8*9);
}
So function "p" gets array of integers
[2,4,1,7,6,8,5,3,9]
joins all integers with "*" and as a result we have:
"2*4*1*7*6*8*5*3*9"
then evaluates this string and as a result we have:
362880
This is the same value as 1*2*3*4*5*6*7*8*9
So now we can check each row, each column and each sub-grid with this function.
sudoku = grid =>
grid.every((r,i) =>
validRows &&
validColumns &&
validSubGrids )
is the same as:
sudoku = function(grid) {
grid.every( function(r, i) {
return
validRows &&
validColumns &&
validSubGrids
})
}
The every method executes the provided callback function once for each element present in the array until it finds one where callback returns a falsy value. Otherwise it returns true.
Valid Sudoku means that our every function's callback returns true for all elements.
p(r) - validate each row
p(grid.map(r => r[i])) - validate each column
function map creates new array.
E.g. for i=0 it will provide following result:
[ grid[0][0], grid[0][1], grid[0][2],...]
p(r.map((_,j) => grid[3*(i/3|0)+(j/3|0)][3*(i%3)+(j%3)]) ) ) - validate each sub-grid
Code equivalent:
p(
r.map( function(_,j) {
let row = 3 * Math.floor(i/3) + Math.floor(j/3)
let column = 3 * (i%3) + (j%3)
return grid[row][column]
})
)
So as a result we validated all rows, all columns and all sub-grids.
For the most part, an arrow function is just a function. The only real different between the two is that this is preserved from the outer context when using an arrow function, whereas this is the this that was used to call the function with a normal function.
function A() {
this.v = 1;
this.a = () => console.log(this.v);
this.b = function () { console.log(this.v) };
}
// Both will use `obj` as `this`
const obj = new A();
obj.a();
obj.b();
// The arrow-function `a()` will keep the same `this` as above, `obj` will change.
const obj2 = { v: 2 };
obj2.a = obj.a;
obj2.b = obj.b;
obj2.a();
obj2.b();
The other difference which may be throwing you off, is with an arrow function, if it only needs one line, you can omit the curly brackets ({}) and it will return the value. I.e.,
a => 1
Is the same as:
function (a) { return 1; }
In this sample code, being an arrow function or a regular function would make no different, as this isn't being invoked.
What the code is doing is:
grid.every((r, i) =>
Look through every element in the grid, and keep going as long as it returns true. r is the current value of grid and i is the current index it is processing.
grid.map(r => r[i])
is literally just getting the i-th value from r and returning it. This would be for checking the diagonals of a two-dimensional array. (So it gets grid[0][0], grid[1][1], and so on).
r.map((_, j) => grid[math])
Is then just looping through each element in r, and getting some element (based on that math) using the current i index from the outer loop and the j index from r. Using _ as a parameter name is a common convention to indicate that you just don't care about that parameter.
sudoku = grid =>
grid.every((r,i) =>
p(r) &&
p(grid.map(r => r[i])) &&
p(r.map((_,j) => grid[3*(i/3|0)+(j/3|0)][3*(i%3)+(j%3)]) ) )
For every item r in grid, p(r) is evaluated. If its true then second part will be evaluated
grid.map(r => r[i]) will be evaluated which in turn will iterate through all grid items and return an array of their ith element.
Now after if p(grid.map(r => r[i])) is true then the latter part will be evaluated.
Finally r.map((_,j) => grid[3*(i/3|0)+(j/3|0)][3*(i%3)+(j%3)]) ) will be executed but only if previous two conditions were true.This will also return an array of grid items, depending upon values of i & j.
So key points here is the usage of &&
A && B will return B if A evaluates to true(and B will only be evaluated when A is true)
Do you have any real-world example of the use of the second and third parameters for the callback to Array.prototype.some or Array.prototype.any?
According to MDN:
callback is invoked with three arguments: the value of the element, the index of the
element, and the Array object being traversed.
I've personally never used them.
I have been working for some time on the Javascript functional programming library, Ramda, and early on we made the controversial decision not to use the index and array parameters for other similar functions that we created. There are good reasons for this, which I don't need to get into here, except to say that for some functions, such as map and filter, we find such extra parameters do have some occasional utility. So we offer a second function which supplies them to your callback. (For example, map.idx(yourFunc, list).)
But I've never even considered doing so for some or every. I never imagined a practical use of these. But there is now a suggestion that we include these functions in our list of index-supporting ones.
So my question again is whether you have ever found an actual, live, real-world callback function to some or every which actually needs these parameters? If so, could you describe it?
Answers of "No, I never do," would be helpful data too, thanks.
Quick search in our code:
function isAscending(array) {
return array.every(function (e, idx, arr) {
return (idx === 0) ? true : arr[idx-1] <= e;
});
}
I could imagine something like the following code to check whether an array is duplicate-free:
….every(function(v, i, arr) {
return arr.indexOf(v, i+1) == -1;
})
Where … is a complex expression so that you'd really have to use the arr parameter - which is no more an issue if you'd properly factor out the functionality in an own function that takes the array as an argument.
The second parameter can be useful sometimes, but I support your position that it is rather seldom used.
Yes, they are helpful
These extra parameters actually do come in handy, but not that often.
In the recent past, I had written a function to find all the permutations of a list of elements:
permute :: [a] -> [[a]]
For example permute [1,2,3] would be:
[ [1,2,3]
, [1,3,2]
, [2,1,3]
, [2,3,1]
, [3,1,2]
, [3,2,1]
]
The implementation of this function is quite simple:
If the input is [] then return [[]]. This is the edge case.
If the input is say [1,2,3]:
Add 1 to every permutation of [2,3].
Add 2 to every permutation of [1,3].
Add 3 to every permutation of [1,2].
Of course, the function is recursive. In JavaScript, I implemented it as follows:
var permute = (function () {
return permute;
function permute(list) {
if (list.length === 0) return [[]]; // edge case
else return list.reduce(permutate, []); // list of permutations
// is initially empty
}
function permutate(permutations, item, index, list) {
var before = list.slice(0, index); // all the items before "item"
var after = list.slice(index + 1); // all the items after "item"
var rest = before.concat(after); // all the items beside "item"
var perms = permute(rest); // permutations of rest
// add item to the beginning of each permutation
// the second argument of "map" is the "context"
// (i.e. the "this" parameter of the callback)
var newPerms = perms.map(concat, [item]);
return permutations.concat(newPerms); // update the list of permutations
}
function concat(list) {
return this.concat(list);
}
}());
As you can see, I have used both the index and the list parameters of the permutate function. So, yes there are cases where these extra parameters are indeed helpful.
However, they are also problematic
However these superfluous arguments can sometimes be problematic and difficult to debug. The most common example of this problematic behavior is when map and parseInt are used together: javascript - Array#map and parseInt
alert(["1","2","3"].map(parseInt));
As you can see it produces the unexpected output [1,NaN,NaN]. The reason this happens it because the map function calls parseInt with 3 arguments (item, index and array):
parseInt("1", 0, ["1","2","3"]) // 1
parseInt("2", 1, ["1","2","3"]) // NaN
parseInt("3", 2, ["1","2","3"]) // NaN
However, the parseInt function takes 2 arguments (string and radix):
First case, radix is 0 which is false. Hence default radix 10 is taken, resulting in 1.
Second case, radix is 1. There is no base 1 numeral system. Hence we get NaN.
Third case, radix is 2 which is valid. However there's no 3 in base 2. Hence we get NaN.
As you see, superfluous arguments can cause a lot of problems which are difficult to debug.
But, there is an alternative
So these extra arguments are helpful but they can cause a lot of problems. Fortunately, there is an easy solution to this problem.
In Haskell if you want to map over a list of values and the indices of each value then you use do it as follows:
map f (zip list [0..])
list :: [Foo]
[0..] :: [Int]
zip list [0..] :: [(Foo, Int)]
f :: (Foo, Int) -> Bar
map f (zip list [0..]) :: [Bar]
You could do the same thing in JavaScript as follows:
function Maybe() {}
var Nothing = new Maybe;
Just.prototype = new Maybe;
function Just(a) {
this.fromJust = a;
}
function iterator(f, xs) {
var index = 0, length = xs.length;
return function () {
if (index < length) {
var x = xs[index];
var a = f(x, index++, xs);
return new Just(a);
} else return Nothing;
};
}
We use a different map function:
function map(f, a) {
var b = [];
if (typeof a === "function") { // iterator
for (var x = a(); x !== Nothing; x = a()) {
var y = f(x.fromJust);
b.push(y);
}
} else { // array
for (var i = 0, l = a.length; i < l; i++) {
var y = f(a[i]);
b.push(y);
}
}
return x;
}
Finally:
function decorateIndices(array) {
return iterator(function (item, index, array) {
return [item, index];
}, array);
}
var xs = [1,2,3];
var ys = map(function (a) {
var item = a[0];
var index = a[1];
return item + index;
}, decorateIndices(xs));
alert(ys); // 1,3,5
Similarly you can create decorateArray and decorateIndicesArray functions:
function decorateArray(array) {
return iterator(function (item, index, array) {
return [item, array];
}, array);
}
function decorateIndicesArray(array) {
return iterator(function (item, index, array) {
return [item, index, array];
}, array);
}
Currently in Ramda you have two separate functions map and map.idx. The above solution allows you to replace map.idx with idx such that:
var idx = decorateIndices;
var arr = decorateArray;
var idxArr = decorateIndicesArray;
map.idx(f, list) === map(f, idx(list))
This will allow you to get rid of a whole bunch of .idx functions, and variants.
To curry or not to curry
There is still one small problem to solve. This looks ugly:
var ys = map(function (a) {
var item = a[0];
var index = a[1];
return item + index;
}, decorateIndices(xs));
It would be nicer to be able to write it like this instead:
var ys = map(function (item, index) {
return item + index;
}, decorateIndices(xs));
However we removed superfluous arguments because they caused problems. Why should we add them back in? Two reasons:
It looks cleaner.
Sometimes you have a function written by somebody else which expects these extra arguments.
In Haskell you can use the uncurry function to solve this problem:
map (uncurry f) (zip list [0..])
list :: [Foo]
[0..] :: [Int]
zip list [0..] :: [(Foo, Int)]
f :: Foo -> Int -> Bar
uncurry :: (a -> b -> c) -> (a, b) -> c
uncurry f :: (Foo, Int) -> Bar
map (uncurry f) (zip list [0..]) :: [Bar]
In JavaScript the uncurry function is simply apply. It is implemented as follows:
function uncurry(f, context) {
if (arguments.length < 2) context = null;
return function (args) {
return f.apply(context, args);
};
}
Using uncurry we can write the above example as:
var ys = map(uncurry(function (item, index) {
return item + index;
}), decorateIndices(xs));
This code is awesome because:
Each function does only one job. Functions can be combined to do more complex work.
Everything is explicit, which is a good thing according to the Zen of Python.
There's no redundancy. There's only one map function, etc.
So I really hope this answer helps.