Skip to content

Instantly share code, notes, and snippets.

@YozhEzhi
Created July 9, 2018 20:51
Show Gist options
  • Save YozhEzhi/bf4f5f0b05e818e16cb8efd5bac8cbc7 to your computer and use it in GitHub Desktop.
Save YozhEzhi/bf4f5f0b05e818e16cb8efd5bac8cbc7 to your computer and use it in GitHub Desktop.
Каррирование.

Каррирование - это способ конструирования функций, позволяющий частичное применение аргументов функции. Т.е. мы можем передать все аргументы, ожидаемые функцией и получить результат, или же передать часть этих аргументов и получить обратно функцию, которая ожидает остальные аргументы.

// Обычная функция приветствия:
var greet = function(greeting, name) {
  console.log(greeting + ", " + name);
};
greet("Hello", "Heidi"); // "Hello, Heidi"

// Каррируем:
var greetCurried = function(greeting) {
  return function(name) {
    console.log(greeting + ", " + name);
  };
};
var greetHello = greetCurried("Hello");
greetHello("Heidi"); // "Hello, Heidi"
greetHello("Eddie"); // "Hello, Eddie"
greetCurried("Hi there")("Howard"); // "Hi there, Howard"

// Каррируем глубже:
var greetDeeplyCurried = function(greeting) {
  return function(separator) {
    return function(emphasis) {
      return function(name) {
        console.log(greeting + separator + name + emphasis);
      };
    };
  };
};

var greetAwkwardly = greetDeeplyCurried("Hello")("...")("?");
greetAwkwardly("Heidi"); // "Hello...Heidi?"
greetAwkwardly("Eddie"); // "Hello...Eddie?"

var sayHello = greetDeeplyCurried("Hello")(", ");
sayHello(".")("Heidi"); // "Hello, Heidi."
sayHello(".")("Eddie"); // "Hello, Eddie."

При создании каррированных функций нам надо сохранять вложенность возвращаемых функций и вызывать их с помощью новых функций, требующих многочисленные наборы скобок, в каждом из которых содержится свой изолированный аргумент. Это может стать запутанным.

Одним из путей решения этой проблемы является создание быстрой и грязной каррирующей функции, которая будет принимать имя существующей функции, написанной без всех вложенных возвращений. Каррирующая функция должна вытащить список аргументов для этой функции и использовать их для возврата каррированной версии оригинальной функции.

// ES5:
function curryIt(uncurriedFn) {
  var params = [].slice.call(arguments, 1);
  return function() {
    return uncurriedFn.apply(this, params.concat(
      [].slice.call(arguments, 0)
    ));
  };
};

// ES6:
function curryIt(uncurriedFn, ...params) {
  return (...args) => uncurriedFn.apply(this, [...params, ...args]);
}

// ES6 alt:
const curryIt = (uncurriedFn, ...params) => (...args) => uncurriedFn.apply(this, [...params, ...args]);

var greeter = function(greeting, separator, emphasis, name) {
  console.log(greeting + separator + name + emphasis);
};
var greetHello = curryIt(greeter, "Hello", ", ", ".");
greetHello("Heidi"); // "Hello, Heidi."
greetHello("Eddie"); // "Hello, Eddie."


// Add numbers example:
function add(...args) {
  return (args.length > 0) ? args.reduce((a, b) => a + b) : 0;
}

function curry(func) {
  return function(...nextArgs) {
    // run function
    if (nextArgs.length === 0) return func.apply(this, [...nextArgs]);

    // else return a partially applied function
    return curry(func.bind.apply(func, [this, ...nextArgs]));
  };
}

const sum = curry(add);
console.log(sum(), 0);
console.log(sum(3)(2)(5)(8)(3)(), 21);

const sum10 = sum(2)(4)(4); // ==> Function
console.log(sum10(), 10); // ==> 10

const sum13 = sum10(3); // ==> Function
console.log(sum13(), 13); // ==> 13
console.log(sum13(-4)(), 9); // ==> 9
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment