Curry, or part of the application, is a technique of functional programming that can be confusing to someone familiar with writing JavaScript code in a traditional way. But if used properly, it can make your JavaScript function more readable.
More readability and flexibility
One of the advantages of functional JavaScript being touted is that it has a short, compact code style that allows you to get the right results with a minimum number of lines and less duplicated code. Sometimes this is at the expense of readability, and if you are not familiar with the methods of functional programming, the code written in this way can be difficult to read and understand.
If you've ever met the term "curry," but you don't know what it means, it's understandable to ignore it as a strange, incomprehensible technique. But in fact, it is a very simple concept, it involves some common problems when dealing with function parameters, and provides a flexible range of choices for developers.
What is currying
To put it simply, Gerty is a way to allow the use of partial function parameter constructors. This means that when you call a function, you can pass in all the parameters you want and get the results returned, or you can pass in some of the parameters and get a return function that needs to pass in the rest of the arguments. It's really that simple.
In functional programming languages like Haskell and Scala, Curry is the basic principle. JavaScript has the ability to function programmatically, but does not support the Curry function by default (at least the current version is not supported). But we already know some of the functional tricks, and we can also make it possible to curry in JavaScript.
To make you understand the principle of the curry, we start by writing the first curry JavaScript function, using the familiar syntax to create a new curry function that we want. Let's say, for example, that there is a function that regards a person's name. It's easy for me to think of creating a simple function, accepting a greeting and a name as parameters, and then printing out the entire greeting sentence in the console:
var Greet = function(greeting,name){
Console. Log(greeting + "," + name);
};
Greet("Hello","Heidi"); //"Hello, Heidi"
This function requires all two parameters of the name and greeting to be available for proper operation. But we can rewrite this function with a simple nested method of curry, so that the basic function only needs a parameter greeting and returns another method that takes the name of the greeting as the parameter.
The first of the curry functions
var greetcurried = function(greeting){
Return function(name){
Console. Log(greeting + "," + name);
};
};
The small adjustment We have just written allows us to get a new function that accepts any greeting as a parameter, and returns a new function with the name of the person we want to greet:
var Greethello = greetcurried("Hello");
Greethello("Heidi"); "Hello, Heidi."
Greethello("Eddie"); "Hello, Eddie."
We can also call the original Curry function directly, just add each parameter with parentheses, one after the other:
Greetcurried("Hi There") ("Howard"); "Hi there, Howard."
It's all currying.
Cool things come, now that we've learned how to deal with the parameters of traditional functions in this way, we can handle as many parameters as possible:
var greetdeeplycurried = function(greeting){
Return function(separator){
Return function(emphasis){
Return function(name){
Console. Log(greeting + separator + name + emphasis);
};
};
};
};
The same flexibility is available when there are four parameters compared to two parameters. No matter how many layers are nested, we are able to write a new custom greeting function, no matter how many people we choose, in how many ways we want.
var greetawkwardly = greetdeeplycurried("Hello") ("...") ("?") );
greetawkwardly("Heidi"); //"Hello ... Heidi? "
greetawkwardly("Eddie"); //"Hello ... "Eddie?"
More importantly, on the basis of the original Curry function, we can pass in the required parameters to create a new mutation function, the new function can continue to accept the remaining parameters, each parameter in a parenthesis:
var sayhello = greetdeeplycurried ( "Hello"
sayhello "Heidi" //"Hello, Heidi."
sayhello ( "Eddie" //"Hello, Eddie."
And we can easily define the next level of mutation function:
var Askhello = SayHello("?") );
Askhello("Heidi"); "Hello, Heidi?"
Askhello("Eddie"); "Hello, Eddie?"
The classical function of curry
You can see how powerful this approach is, especially when you need a lot of complex, customized functions. The only problem is grammar. When you build these curry functions, you need to guarantee nested return sub-functions, and call them with multiple sets of parentheses, each containing a separate argument. It's going to get a mess.
To solve this problem, one way is to create a new fast dirty curry function, which takes an existing function that has no nested returns as a parameter. This curry function needs to get the argument list of the incoming function and use these functions to return the curry version of the original function:
var Curryit = function(uncurried){
var Parameters = Array. Prototype. Slice. Call(arguments,1);
Return function(){
return uncurried. Apply(this,parameters. Concat(
Array. Prototype. Slice. Call(arguments,0)
));
};
};
To use this approach, we pass in the function name with any arguments, and several parameters that we want to pre-populate. What we get is a function that needs the rest of the arguments:
var greeter = function(greeting,separator,emphasis,name ){
Console. Log(greeting + separator + name + emphasis);
};
varGreethello = curryit(greeter,"Hello", " ," , " .") );
Greethello("Heidi"); "Hello, Heidi."
Greethello("Eddie"); "Hello, Eddie."
As before, we did not limit the number of parameters when building a sub-function with the curry function:
var Greetgoodbye = curryit(greeter,"Goodbye",",");
Greetgoodbye("." ,"Joe"); "Goodbye, Joe."
Think Hard currying
Our little curry function may not be able to handle all edge situations, such as missing or optional parameters, but it will work effectively as long as we pass the parameters strictly by syntax.
Some functional JavaScript libraries, such as RAMDA, have a more flexible curry function, which can disrupt the parameters required by a function and allow you to pass in parameters individually or in groups to create a custom curry transformation function. If you want to curry extensively, this may be a direction.
Regardless of how you choose to curry the program with nested parentheses or more likely to include a more robust curry function, using a uniform naming convention can help make your code more readable. Each derived function should have a name that clearly indicates its behavior and expected parameters.
Parameter order
When making a curry, it is important to remember the order of the parameters. Using the method we just talked about, you obviously want the last parameter of the original function, which is the parameter of the function that is deformed from the layer of the curry function.
The order of the parameters considered in advance makes it easier for you to apply it to your project. and in order to adapt to more situations, when designing a function, it is not a bad habit to consider the order in which the parameters are arranged according to the degree of change.
Conclusion
Curry is an extremely useful technique for functional JavaScript. It allows you to create a simple, easy-to-configure, unified library that is quick to use and readable. Adding a curry to your coding practice will motivate you to apply it on some of the functions in all your code, avoiding a lot of potential duplication and helping you develop a good habit of naming and handling function parameters.
If you like this article, you may also like other articles in this series:
An Introduction to functional JavaScript
Higher-order Functions in JavaScript
Recursion in functional JavaScript
The Curry function of JavaScript