Curry

Currization is the technique of transforming a function that takes multiple arguments into a function that takes a single argument (the first argument of the original function), and returning a new function that takes the remaining arguments and returns the result. — from wiki

Why Curry?

Theoretical basis: I learned the Lamda calculus in high school mathematics, and it is likely to prove that functions with too many parameters can be replaced by functions with single parameters. Similarly, in Haskell syntax, a multi-parameter function is the syntactic sugar of a single argument, and in other languages that support first-class citizen functions, it is possible to replace a multi-parameter function with a single argument.

Practical implications: Instead of getting stuck in a dominant mindset, we first ask “Why do we need multiple parameters?” In the context of functional programming, multiple parameters only complicate functions that can be combined flexibly. In fact the multi-parameter function is just for the definition and function call we flatter, but many parameters of the function in the function of reuse for the function of each parameter are some limitations, such as in the support function is the language of first class citizens, higher-order functions for multi-parameter of incoming treatment compared with the single parameter function will be a lot of trouble.

Currization also practices the idea of point-free, which can be better applied to the code style of point-free. Without currified functions, parameters need to be passed in manually, which makes us need to pay attention to data and behavior at the same time, and such functions are difficult to be applied to the combination of functions.

For example, I think single arguments can be better used in arr.map, filter functions, and in higher-order functions such as compose, pipe, etc.

What is point-free? See Nguyen Yifeng’s blog

Curry makes functions more fine-grained and easy to combine;

Realize the curry

Interview questions is often met the add function, the add (1, 2), (), add (1) (2) (), add (1, 2) (3, 4) (a)

Method 1: Use the property of the function object, save the incoming and outgoing parameters in an array property of the object, check whether the function is executed without parameters, then select execute, and clean the function property

function curryAdd() {
  curryAdd.store = [...arguments, ...(curryAdd.store || [])];
  if (!arguments.length) {
    const temp = [...curryAdd.store];
    curryAdd.store = [];
    return temp.reduce((pre, curr) = > pre + curr);
  }else {
    returncurryAdd; }}Copy the code

Method 2: Using closures, the variables in the closure are still cleaned up after the function is executed

function curryAdd() {
  curryAdd.store = [...arguments, ...(curryAdd.store || [])];
  if (!arguments.length) {
    const temp = [...curryAdd.store];
    curryAdd.store = [];
    return temp.reduce((pre, curr) = > pre + curr);
  }else {
    returncurryAdd; }}Copy the code

Print the result:

const Mres = curryAdd(1.2.3) (4.5) (6) ()console.log('----curry1');
console.log(Mres);
console.log(curryAdd(1) ());const res2 = curryAdd2(1.2.3) (4.5) (6) ()const res3 = curryAdd2(1) ()console.log('---curry2');
console.log(res2);
console.log(res3)
// ----curry1
/ / 21
/ / 1
// ---curry2
/ / 21
/ / 1
Copy the code

How do you convert a multi-argument function into a curried function?

Such as:

function myCurry() {
  // ...
}
function addAll(a, b, c) {
  return a + b + c;
}

function joinName(firstName, lastName) {
  return firstName + ' ' + lastName
}

const currAddAll = myCurry(addAll)
const curryJoinName = myCurry(joinName)
console.log('-----my curry');
console.log(currAddAll(1) (2) (3));
console.log(curryJoinName('zhang'.'shuang'));
console.log(curryJoinName('zhang') ('shuang'));
// -----my curry
/ / 6
// zhang shuang
// zhang shuang
Copy the code

Let’s implement this function:

Note that the closure feature is still used here. You need a reset closure at the exit of the function’s final execution, otherwise there will be a residue from multiple executions

function myCurry(fn) {
  let store = [];
  function resFn(. rest) {
    store = [...store, ...rest];
    if (store.length === fn.length) {
      const temp = [...store]
      store = [];
      return fn.apply(null, temp);
    }else {
      returnresFn; }};return resFn;
} 
Copy the code