Ramda: Confused about pipe - javascript

I'm learning functional programming in JS and I'm doing it with Ramda.
I'm trying to make a function that takes parameters and returns a list. Here is the code:
const list = R.unapply(R.identity);
list(1, 2, 3); // => [1, 2, 3]
Now I tried doing this using pipe:
const otherList = R.pipe(R.identity, R.unapply);
otherList(1,2,3);
// => function(){return t(Array.prototype.slice.call(arguments,0))}
Which returns a weird function.
This:
const otherList = R.pipe(R.identity, R.unapply);
otherList(R.identity)(1,2,3); // => [1, 2, 3]
works for some reason.
I know this might be a newbie question, but how would you construct f(g(x)) with pipe, if f is unapply and g is identity?

Read the R.unapply docs. It's a function that gets a function and returns a function, which can take multiple parameters, collect it to a single array, and pass it as the parameter for the wrapped function.
So in the 1st case, it converts R.identity to a function that can receive multiple parameters and return an array.
In the 2nd case, R.unapply gets the result of R.identity - a single value, and not a function. If you pass R.identity as a parameter to the pipe, R.unapply gets a function and return a function, which is similar to the 1st case.
To make R.unapply work with R.pipe, you need to pass R.pipe to R.unapply:
const fn = R.unapply(R.pipe(
R.identity
))
const result = fn(1, 2, 3)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>

It looks as though you really are thinking of pipe incorrectly.
When you use unapply(identity), you are passing the function identity to unapply.
But when you try pipe(identity, unapply), you get back a function that passes the results of calling identity to unapply.
That this works is mostly a coincidence: pipe(identity, unapply)(identity). Think of it as (...args) => unapply(identity(identity))(...args). Since identity(identity) is just identity, this turns into (...args) => unapply(identity)(...args), which can be simplified to unapply(identity). This only means something important because of the nature of identity.

You would use unapply to transform a function that would normally take its arguments as an array into a function that can take any number of positional arguments:
sum([1, 2, 3]); //=> 6
unapply(sum)(1, 2, 3) //=> 6
This allows you to, among many other things, map over any number of positional arguments:
unapply(map(inc))(1, 2) //=> [2, 3]
unapply(map(inc))(1, 2, 3) //=> [2, 3, 4]
unapply(map(inc))(1, 2, 3, 4) //=> [2, 3, 4, 5]
identity will always return its first argument. So unapply(identity)(1,2) is the same as identity([1,2]).
If your end goal was to create a function that returns a list of its arguments, I don't think you needed pipe in the first place. unapply(identity) was already doing that.
However, if what you need to do is to make sure that your pipe gets its parameters as a list, then you simply need to wrap pipe with unapply:
const sumplusplus = unapply(pipe(sum, inc, inc));
sumplusplus(1, 2, 3); //=> 8

Related

Array of numbers to Array of one string

I need to [1, 2, 3] over to ['123'].
I must return [1, 2, 3] over to ['123'] while using an arrow function (no regex):
Must be used:
const functionOne = (arrayOne) => {
};
console.log(functionOne([1, 2, 3]));
So, I tried the following:
First, I created a string. This gave me 1,2,3
Then, I removed the commas, so, I could join the numbers. This gave me 123.
Finally, I tried to put back the number as a string into the array but this didn't work. This gave me ['1', '2', '3'] instead of ['123']. I think the .split method is what is wrong in my code but I cannot find another one (currently learning JavaScript).
const functionOne = (arrayOne) => {
let stepOne = arrayOne.toString(arrayOne => arrayOne.toString());
console.log(stepOne);
stepOne = stepOne.split(',').join('');
console.log(stepOne);
return stepOne.split('');
};
console.log(functionOne([1, 2, 3]));
You can join using "" as the delimiter (it will automatically convert the elements to strings as it produces the output string), then put the result in an array as its only element ([____]):
const functionOne = (array) => [array.join("")];
console.log(functionOne([1, 2, 3]));
Issues with your original approach:
Array's toString completesly ignores the argument you're giving it, instead using its default behavior of join(",").
Splitting it on , again just gives you back an array, but this time of strings.
Rejoining that with join('') does give you "123", but doesn't put it in an array.
You could take a recursive function.
const
fn = ([v, ...rest]) => rest.length
? [v + fn(rest)]
: [v];
console.log(fn([1, 2, 3]));
const functionOne = (arrayOne) => {
let stepOne = arrayOne.toString();
stepOne = stepOne.split(',').join('');
return [stepOne];
};
console.log(functionOne([1, 2, 3]));
The .toString() method will convert the array [1, 2, 3] to the string "1,2,3", then .split(',').join('') removes the commas and joins the numbers as a single string "123". Finally, return [stepOne]; returns the string "123" inside an array ['123'].

Iterating inside JavaScript filter method

I am trying to compare two given parameters of a function. The exact problem is as follows:
You will be provided with an initial array (the first argument in the destroyer function), followed by one or more arguments. Remove all elements from the initial array that are of the same value as these arguments.
Note
You have to use the arguments object.
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3)); // expected output: [1,1]
I am using filter method to iterate over the array but I couldn't compare the args with the elements of the array inside the callback of the filter.
function destroyer(arr, ...args) {
let result = arr.filter(num => {
for (let i = 0; i<=args.length; i++ ){
num !== args[i]
}
});
return result;
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));
I can iterate with for loop but I cannot use the output of for loop to do filter iteration.
Any ideas?
Probably an easier way to achieve the goal using .filter() with .includes(). Additionally you can use ...rest so called rest parameters for you function, see form the documentation:
The rest parameter syntax allows us to represent an indefinite number of arguments as an array.
Try as the following:
const destroyer = (arr, ...rest) => {
return arr.filter(num => !rest.includes(num));
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));
I hope this helps!
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
Example:
const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
const result = words.filter(word => word.length > 6);
console.log(result);
// expected output: Array ["exuberant", "destruction", "present"]
via MDN
Filter iterates over all elements of some array and returns a new array. It puts an element in the new array only if callback (your function invoked as a parameter of filter) return true otherwise it's omitted.
Next it's worth to use rest parameters to achieve two arrays (initial and values to exclude).
The rest parameter syntax allows us to represent an indefinite number of arguments as an array.
function sum(...theArgs) {
return theArgs.reduce((previous, current) => {
return previous + current;
});
}
console.log(sum(1, 2, 3));
// expected output: 6
console.log(sum(1, 2, 3, 4));
// expected output: 10
Solution with explanation:
//Declare your function, first parameter is initial array, the second one is also array created by using rest parameters
function destroyer(initialArray = [], ...toExclude) {
// filter initialArray, if el (single element) is NOT included in "toExclude" it returns true
// and add this particular element to the result array
let result = initialArray.filter(el => toExclude.includes(el) == false);
//return result
return result;
}

Weird function syntax

I saw a weird function that looked something like:
const x = (a) => (b) => a + b;
console.log(x(1)(2))
The output is 3, I understand that it's a function returning a function and both a and b are in the same scope but the questions I have are:
How could this be used in real life?
What's the advantage of not using a function with 2 parameters and using this instead (for a one-line function)?
With this closure, you could get a function with a constant value for later adding.
How could this be used in real life?
You could take the returned function for a mapping of an array.
What's the advantage of not using a function with 2 parameters and using this instead (for a one-line function)?
It's a cleaner and functional approach.
const
x = a => b => a + b,
add5 = x(5);
console.log([1, 2, 3].map(add5));
Let's give that function a better name:
const add = (a) => (b) => a + b
Then later you can write
[1, 2, 3, 4] .map (add (5)) //=> [6, 7, 8, 9]
which is nicer to read than
[1, 2, 3, 4] .map ((n) => 5 + n) //=> [6, 7, 8, 9]
This is handy in a chain of .then() calls on Promises:
return fetchList (param)
.then (map (add (5)))
.then (filter (lessThan (8)))
.then (average)
(This of course requires curried functions add, lessThan, map, and filter, and some simple average function.)
Compare this to
return fetchList (param)
.then (xs => xs.map (x => add (5, x)))
.then (xs => xs.filter (x => lessThan (8, x)))
.then (average)
Note that the reason that average works the same in both versions of this is that it
takes a single parameter. One major point of currying is to turn a function into one that takes a single parameter. It makes a certain style of coding much easier to perform.
Nina gave an excellent answer. I will provide another, a little more advanced example where such closures help a lot with the clarity of the code. Let's combine functions together into a prefix-checker as below and then re-use it as many times as we want:
//given a word, check if a string s starts with this word
const literal = word => s => s && s.startsWith(word);
//allow to combine 2 literals with OR
const either = (p1, p2) => s => p1(s) || p2(s);
//allow to combine N literals
const any = (...parsers) => parsers.reduce(either);
//create a parser
const check = any(literal('cat'),literal('dog'),literal('cow'));
console.log('cat: ' + check('cat'));
console.log('dog: ' + check('dog is smart'));
console.log('cow: ' + check('cow 123'));
console.log('banana: ' + check('banana'));
In reality, it is a simplified parser-combinator (nope, not yet monadic). Extending this approach, you can create parsers for your own programming language, and it would be maintainable and fast.

How to navigate and pull from an object in JavaScript

I am being given the function call destroyer([1, 2, 3, 1, 2, 3], 2, 3);. I want to be able to pull from the last 2, 3 part after the initial object, but I do not know how to go about this.
return arr[6]; and return arr[1][0] both return nothing. I am expecting to see 2 or 2, 3 (Last two numbers)
I tried researching Property Accessors, but I think I was looking in the wrong place for my answer.
Here's my full code:
function destroyer(arr) {
return arr;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
Instead of getting the first array [1,2,3,1,2,3]
I want to get the parts after the array:
[1,2,3,1,2,3],2,3
You're destroyer function is only taking one argument, but you're passing it 3.
You have two options:
Use arguments to get an array-like of all the passed arguments, you'll then need to combine that with a method like slice to get only the second and third arguments. Additionaly since arguments isn't technically an array, you need to convert it to one before you can call a method like slice. My example uses Array.from however that is only available on newer browsers.
function destroyer(arr) {
return Array.from(arguments).slice(1,3);
}
console.log('Result: ', destroyer([1, 2, 3, 1, 2, 3],2,3));
Add additional parameters to your function definition. This is probably easier if you know you'll have exactly 3 arguments. And there are far fewer gotchas compared to using the magic arguments variable.
function destroyer(a, b, c) {
return [b, c];
}
console.log('Result: ', destroyer([1, 2, 3, 1, 2, 3], 2, 3));
try use arguments
example
function destroyer(){var arr = []; arr.push(arguments[1]);arr.push(arguments[2]); return arr};

Someone please explain the Function.apply.bind(Math.max, null) algorithm

suppose we have this code
function largestOfFour(arr) {
return arr.map(Function.apply.bind(Math.max, null));
}
where arr is an array of arrays.
first,why must i use apply()?
I understand that when using the method Math.max() to operate on an array i must add the apply() method also. So i'll have something like this Math.max.apply(null, arr) why? what does apply() do?
In this code arr.map(Function.apply.bind(Math.max, null)) what does bind() really do?
Please give an explanation i can understand,i really appreciate this.
Looking at the entire expression:
arr.map(Function.apply.bind(Math.max, null));
map expects its first argument to be a function, which is returned by:
Function.apply.bind(Math.max, null);
Function.apply is a shorter version of Function.prototype.apply.
Calling bind on it returns a special version of apply whose this is set to Math.max and when called, will have as it's first parameter (i.e. the value that would normally be used as this) set to null, since it's not going to be used.
So each element in arr will effectively be called using:
Math.max.apply(null, member);
The use of apply means the values in member are passed as parameters, as if:
Math.max(member[0],member[1] ... member[n]);
So the expression returns the maximum value in each array. Those values are returned to map, which puts them into a new array.
var arr = [[1,2,3],[4,5,6]];
console.log(
arr.map(Function.apply.bind(Math.max, null)) //[3, 6]
);
and is effectively the same as:
var arr = [[1, 2, 3],[4, 5, 6]];
console.log(
arr.map(function(a) {return Math.max.apply(null, a)}) //[3, 6]
);
Though using recent features you might use destructing with rest parameter syntax:
var arr = [[1, 2, 3],[4, 5, 6]];
console.log(
arr.map(a => Math.max(...a)) // [3, 6]
);
Simply put, .apply calls a function with the set of arguments(array-like) passed to it.
EG:
const add = (...args) => args.reduce((acc, next) => acc + next);
I can call the add function with any number of arguments using the .apply method like this.
add.apply(null, [4, 2, 6, 76, 9]) // => 97.
You call also use .call but instead of passing in array-like arguments, you simply pass in the values
add.call(null, 4, 2, 6, 76, 9) // => 97.
With .bind, the difference is that it creates a new function with call be called later.
const addFunc = add.bind(null, 4, 2, 6, 76, 9);
addFunc() // -> 97.
So, as it applies to the function we defined, it also applies to inbuild functions like Math.max, Math.min, etc.
Hope this helps!
The Function.apply.bind(Math.max, null) creates a function definition when invoked takes null as the first parameter by default and any provided parameters will come second. So as a callback to arr.map this function (due to bind statement) will be bound to Math.max however the Function.apply's first parameter will be null and second is going the be the sub array item of the main array (of which the items are to be passed as arguments to Math.max function).
This is an old trick and in ES6 terms arr.map(s => Math.max(...s)); would do the same job much more clearly.

Categories

Resources