Поиск…


замечания

Что такое функциональное программирование?
Функциональное программирование или FP - это парадигма программирования, основанная на двух основных понятиях неизменности и безгражданства . Цель FP - сделать ваш код более читаемым, многоразовым и переносимым.

Что такое функциональный JavaScript
Прозвучала дискуссия о том, чтобы назвать JavaScript функциональным языком или нет. Однако мы можем абсолютно использовать JavaScript как функциональный по своей природе:

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

Принятие функций в качестве аргументов

function transform(fn, arr) {
    let result = [];
    for (let el of arr) {
        result.push(fn(el)); // We push the result of the transformed item to result
    }
    return result;
}

console.log(transform(x => x * 2, [1,2,3,4])); // [2, 4, 6, 8]

Как вы можете видеть, наша функция transform принимает два параметра, функцию и коллекцию. Затем он перебирает коллекцию и передает значения на результат, вызывая fn для каждого из них.

Выглядит знакомо? Это очень похоже на то, как работает Array.prototype.map() !

console.log([1, 2, 3, 4].map(x => x * 2)); // [2, 4, 6, 8]

Функции более высокого порядка

В общем, функции, которые работают с другими функциями, либо путем принятия их в качестве аргументов, либо путем их возврата (или обоих), называются функциями более высокого порядка.

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

function iAmCallbackFunction() {
    console.log("callback has been invoked");
}

function iAmJustFunction(callbackFn) {
    // do some stuff ...

    // invoke the callback function.
    callbackFn();
}

// invoke your higher-order function with a callback function.
iAmJustFunction(iAmCallbackFunction);

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

function iAmJustFunction() {
    // do some stuff ...

    // return a function.
    return function iAmReturnedFunction() {
        console.log("returned function has been invoked");
    }
}

// invoke your higher-order function and its returned function.
iAmJustFunction()();

Идентичность Монады

Это пример реализации идентичной монады в JavaScript и может служить отправной точкой для создания других монадов.

Основываясь на конференции Дугласа Крокфорда о монадах и гонадах

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

f(g(h(i(j(k(value), j1), i2), h1, h2), g1, g2), f1, f2)

читаемый, красивый и чистый:

identityMonad(value)
    .bind(k)
    .bind(j, j1, j2)
    .bind(i, i2)
    .bind(h, h1, h2)
    .bind(g, g1, g2)
    .bind(f, f1, f2);

function identityMonad(value) {
    var monad = Object.create(null);
    
    // func should return a monad
    monad.bind = function (func, ...args) {
        return func(value, ...args);
    };

    // whatever func does, we get our monad back
    monad.call = function (func, ...args) {
        func(value, ...args);

        return identityMonad(value);
    };
    
    // func doesn't have to know anything about monads
    monad.apply = function (func, ...args) {
        return identityMonad(func(value, ...args));
    };

    // Get the value wrapped in this monad
    monad.value = function () {
        return value;
    };
    
    return monad;
};

Он работает с примитивными значениями

var value = 'foo',
    f = x => x + ' changed',
    g = x => x + ' again';

identityMonad(value)
    .apply(f)
    .apply(g)
    .bind(alert); // Alerts 'foo changed again'

А также с объектами

var value = { foo: 'foo' },
    f = x => identityMonad(Object.assign(x, { foo: 'bar' })),
    g = x => Object.assign(x, { bar: 'foo' }),
    h = x => console.log('foo: ' + x.foo + ', bar: ' + x.bar);

identityMonad(value)
    .bind(f)
    .apply(g)
    .bind(h); // Logs 'foo: bar, bar: foo'

Давайте попробуем все:

var add = (x, ...args) => x + args.reduce((r, n) => r + n, 0),
    multiply = (x, ...args) => x * args.reduce((r, n) => r * n, 1),
    divideMonad = (x, ...args) => identityMonad(x / multiply(...args)),
    log = x => console.log(x),
    substract = (x, ...args) => x - add(...args);

identityMonad(100)
    .apply(add, 10, 29, 13)
    .apply(multiply, 2)
    .bind(divideMonad, 2)
    .apply(substract, 67, 34)
    .apply(multiply, 1239)
    .bind(divideMonad, 20, 54, 2)
    .apply(Math.round)
    .call(log); // Logs 29

Чистые функции

Основным принципом функционального программирования является то, что он позволяет избежать изменения состояния приложения (безгражданства) и переменных вне его (неизменяемости).

Чистые функции - это функции, которые:

  • с заданным входом, всегда возвращают один и тот же выход
  • они не полагаются на какую-либо переменную за пределами их возможностей
  • они не изменяют состояние приложения ( без побочных эффектов )

Давайте рассмотрим несколько примеров:


Чистые функции не должны изменять какую-либо переменную за пределами их возможностей

Нечистая функция

let obj = { a: 0 }

const impure = (input) => {
  // Modifies input.a
  input.a = input.a + 1;
  return input.a;
}

let b = impure(obj)
console.log(obj) // Logs { "a": 1 }
console.log(b) // Logs 1

Функция изменила значение obj.a которое находится за пределами его области.

Чистая функция

let obj = { a: 0 }

const pure = (input) => {
  // Does not modify obj
  let output = input.a + 1;
  return output;
}

let b = pure(obj)
console.log(obj) // Logs { "a": 0 }
console.log(b) // Logs 1

Функция не меняла значения объекта obj


Чистые функции не должны полагаться на переменные за пределами их возможностей

Нечистая функция

let a = 1;

let impure = (input) => {
  // Multiply with variable outside function scope
  let output = input * a;
  return output;
}

console.log(impure(2)) // Logs 2
a++; // a becomes equal to 2
console.log(impure(2)) // Logs 4

Эта нечистая функция зависит от переменной a которая определяется вне ее области. Таким образом, если a изменен, результат функции impure функции будет отличаться.

Чистая функция

let pure = (input) => {
  let a = 1;
  // Multiply with variable inside function scope
  let output = input * a;
  return output;
}

console.log(pure(2)) // Logs 2

Результат функции pure не зависит от какой-либо переменной вне ее.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow