javascript flexible argument for curry function - javascript

I have a question regarding curry function..
I know that if I have this simple curry function:
const greeting = (greet) => {
return (name) => {
return `${greet} ${name}`;
};
};
I can call greeting('Hello')('John') and it will return Hello John.
Is there a way to make it flexible say between 1 parameter and 2 parameters, ex: with
the above greeting function, is there a way for me to call greeting('Hello') and greeting('Hello')('John') and it will return Hello and Hello John respectively?
I know that I can do it with greeting('Hello')() and greeting('Hello')('John') but I was just trying to avoid breaking changes because I already have a greeting method and want to extend it using curry function, so I want it to also accept greeting('Hello') without the extra () at the end...
thanks

I can think of only one option that works by coercing the curried function into a string. This won't change the return value but it will allow you to get the result you want depending on context.
const greeting = greet => Object.defineProperties(
name => `${greet} ${name}`, // curried
{
toString: {
value: () => greet,
},
valueOf: {
value: () => greet
}
}
)
console.log(typeof greeting("Hello")) // function, not string
console.log(`${greeting("Hello")}`) // note the string context
console.log(`${greeting("Hello")("World")}`)
If you need the return value to actually toggle between a function and a string however, the answer is no.
In order for greeting("Hello")("John") to return a string, greeting("Hello") must return a function.
There is no way to tell within greeting() how the curried function is going to be called so you cannot detect whether or not to return a function or a string.
Think of it this way, greeting("Hello")("John") is just a short version of...
const fn = greeting("Hello")
// later or maybe never...
fn("John")
You simply don't know how, when or even if that curried function will be called.

Is there a way? Sure. But why? because won't that be "un-currying" it? And you will have to modify the function of-course.
You can always do something like this just get the output your asked for:
const greeting = (greet) => {
const split = greet.split(" ");
if(split.length > 1)
return `${split[0]} ${split[1]}`;
else return (name) => {
return `${greet} ${name}`;
};
};

If you use a helper function for currying, you can get a similar behavior automatically. For example, take the implementation at javascript.info/currying-partials
function curry(func) {
return function curried(...args) {
if (args.length >= func.length) {
return func.apply(this, args);
} else {
return function(...args2) {
return curried.apply(this, args.concat(args2));
}
}
};
}
You can define
const greeting = curry((greet, name) => `${greet} ${name}`)
and call
greeting("Hello", "John")
or
greeting("Hello")("John")

Related

I need help understanding 'Once' function by David Walsh

I'm trying to understand exactly how this Once function by David Walsh works:
`
function once(fn, context) {
var result;
return function() {
if(fn) {
result = fn.apply(context || this, arguments);
fn = null;
}
return result;
};
}
// Usage
var canOnlyFireOnce = once(function() {
console.log('Fired!');
});
canOnlyFireOnce(); // "Fired!"
canOnlyFireOnce(); // nada
`
I understand it takes a function as a argument, and returns a function that calls the passed function only once.
But I'm trying to understand what each part is doing. Can anyone help explain? especially this part:
result = fn.apply(context || this, arguments);
Why the OR sign? what is "this" and how is it getting the arguments from fn? What purpose does 'context' serve?
I wrote a similar once() function for school that returns the result of the passed function, and stores the result to return it again if the function attempts to get called again. It took a lot of trial and error, and I'm just trying to get a firm grasp on all the component parts of how this works.
`
function add(x, y) {
return x + y;
}
function once(fn) {
let timesRan = 0;
let result;
function doOnce() {
if (timesRan === 0) {
timesRan = 1;
result = fn.apply(this, arguments); //I don't understand how this gets the arguments from AddOnce
console.log(`did it once: ${result}`)
return result;
} else {
return result;
}
}
return doOnce;
}
var addOnce = once(add);
console.log(addOnce(1, 2)); // test first call, expected value: 3
console.log(addOnce(2, 5)); // test second call, expected value: 3
console.log(addOnce(8, 22)); // test third call, expected value: 3
`
The concept behind this in JavaScript is confusing, because when I write a function such as:
function getPersonName() {
return this.name
}
I expect that this be defined as a some object with a name attribute. Depending on the scope, I may have this be defined and no problems! But in order for a function such as the above to properly reference this, we need to tell it what it should reference when we use that keyword.
For example, it allows us to do the following:
var canOnlyFireOnce = once(function() {
console.log(this.name)
}, {name: "John"});
canOnlyFireOnce() // prints John
canOnlyFireOnce() // nada
It may be helpful to understand the bind function's use cases in JavaScript to understand why having this (no pun intended) is useful.
The meaning of the this context in function.apply is already explained in rb612's answer.
For the question about arguments, you need to know that
the arguments object is a local variable available within all non-arrow functions. You can refer to a function's arguments inside that function by using its arguments object. 

Currying Function with many parameters

I'm stuck on currying a function with many parameters. What I want to do is take the result of return function and pass it to the next functions.
What I want is similar to this
return this.function(
this.function(
this.function(this.data, this.filterCondition1),
this.filterCondition2),
this.filterCondition3
);
What it basically does is it takes some data, filters it by condition and then feeds it to the next filter that also takes in a second different condition
What I've tried is:
curryFunction(data, filter, filterFunction) =>{
const filteredData = filterFunction(data)
return helper( curryFilter, curryFunction) =>{
return curryFunction(filteredData, curryFilter, curryFunction)
}
}
However, this function returns a function at the end instead of a value.
Basically, it's an infinite loop. How exactly would I go about solving this problem? Thanks
Based on your comment of
take the result of the previous function and pass it to the next, similar to add([1]).add(2).add(3), which will result in 6
I think it is might be better to implement via class function.
class NumberResult {
value = 0;
constructor (value: number) {
this.value = value;
}
function add(a: number) {
this.value = this.value + a;
return this;
}
function add(a: number[]) {
// overload to handle array
}
}
const result = new NumberResult(1);
result.add(1).add(2).add(3);
console.log(result.value);

Passing arguments to a function within a function - javascript

I am trying to pass an argument to a function within a function;
function add() {
let x = arguments[0];
function s(num) {
return num + x;
}
}
add(2)(3) //second argument to be passed to 'function s'.
so im wanting the call to return 5.
What is the best approach to this? thanks in advance.
Currying is the name of the construction that allows you to partially apply the arguments of a function. It means that instead of passing multiple arguments to a function and expect a final result, you can pass a subset of this arguments and get back a function that is waiting for the rest of the arugments.
As already pointed by #KevBot, your example is missing the return of the second function and would be:
function add() {
let x = arguments[0];
return function s(num) {
return num + x;
}
}
add(2)(3);
ES6 Curryed Hello World:
curryedHelloWorld = (greeting) => (name) => `${greeting}, ${name}!`;
curryedHelloWorld("Hello")("Tygar");
You can even uncurry the curryedHelloWorld example making it the opposite way:
helloworld = (greeting, name) => curryedHelloWorld(greeting)(name);
helloworld("Hello", "Tygar");

Unknown Meaning of ES6 Syntax

Currently I am working on Learning React and Redux. I have found a boilerplate, and I am working on looking through all of the example code. My problem is I don't completely understand what a lot of this ES6 syntax means.
What I have learned so far is that hello = () => "Hello"; would be equivalent to:
hello = function hello() {
return "Hello";
};
Then changing the above to hello = name => "Hello " + name; would convert it to:
hello = function hello(name) {
return "Hello " + name;
};
That all makes perfect sense, basically it is just shortening it down so you don't have to write the function and its return statement. Yet, I have come across some syntax that I cannot rap my head around. It is as follows:
const mapActionCreators = {
increment: () => increment(1),
doubleAsync
}
The above code is converted to:
var mapActionCreators = {
increment: function (_increment) {
function increment() {
return _increment.apply(this, arguments);
}
increment.toString = function () {
return _increment.toString();
};
return increment;
}(function () {
return increment(1);
}),
doubleAsync: doubleAsync
};
I understand that () => increment(1) in this case is being turned in to:
(function () {
return increment(1);
}),
Overall I guess my question is, how does increment: get converted in to:
increment: function (_increment) {
function increment() {
return _increment.apply(this, arguments);
}
increment.toString = function () {
return _increment.toString();
};
return increment;
}
What is the meaning of the code?
Arrow functions capture the value of this from the scope they are created in.
apply lets you call a function and explicitly the value of this in it.
The rest of the code is just feeding the correct this to the function.
(And toString is making sure that the right function gets stringified if you try to stringify the generated function).

NodeJS default parameter when last parameter is the callback

I have a function like this one (simplified) :
doSmthg (name, age, callback) {
callback(name, age);
}
I'd like to have a default value for age if it's not provided.
I know I could do doSmthg(name, callback, age=42) {...} in ES6 but I've been told callback should always be the last parameter as it make the call to the function more readable.
For now the solution I found is to do the following :
doSmthg (name, age, callback) {
if (arguments.length === 2) {
age = 42;
callback = age;
}
}
But I find this solution hard to read.
Is this the good solution ? Is there a better one ?
For this kind of situation you can use something like this:
function doSmthg(name, age, callback) {
if (typeof age === 'function') {
callback = age;
age = DEFAULT_VALUE;
}
//continue
}
Or you can use a Hash of options, that i think it's better because makes the code more readable, depending of the number of parameters:
function doSmthg(options, callback) {
var name = options.name;
var age = options.age || DEFAULT_VALUE;
//continue
}
doSmthg({ name: 'batman' }, function() {});
Also you can use the underscore #extend function to merge the options with the default values.
If you have access to spread operator:
function foo(...args) {
const callback = args.pop();
const [name, age = 42] = args;
// ...
}
But I think it's time to use promises in NodeJS as well.
function foo(name, age = 42) {
return new Promise(resolve => {
setTimeout(() => resolve({name, age}), 1000);
});
}
//...
foo('Sándor').then(x => console.log(x)); // { name:"Sándor", age:42 }
Using ES6 promises you can get rid of the so called "callback pyramid", and makes it possible to use your function with ES7 async-await keywords. The future is here!
Code
function foo(args, callback){
parsed = {name:"John Doe",age:12}; //default values
for(a in args) parsed[a] = args[a];
//Arguments are accessible like parsed.name
callback(parsed);
}
function callback(args){
alert(JSON.stringify(args));
}
foo({name:"Peter",extra:2},callback);//yields {"name":"Peter","age":12,"extra":2}
foo({name:"Mark",age:92},callback); //yields {"name":"Mark","age":92}
foo({},callback); //yields {"name":"John Doe","age":12}
Explanation
Depending on the number of arguments to pass it might look too verbose to your liking. The concept should be self explanatory but to put it in words, we group the arguments in an object and inside the function have an object with the default values (if needed). Then we override the defaults with those passed leaving us a very clear and clean callback and verbose args.
Note that if extra parameters are passed, those are not lost in the process of setting the defaults.

Categories

Resources