Szukaj…


Uwagi

Co to jest programowanie funkcjonalne?
Programowanie funkcjonalne ( FP ) to paradygmat programowania oparty na dwóch głównych koncepcjach niezmienności i bezpaństwowości . Celem programu FP jest uczynienie kodu bardziej czytelnym, wielokrotnego użytku i przenośnym.

Co to jest funkcjonalny JavaScript
Odbyła się debata, aby nazwać JavaScript funkcjonalnym językiem lub nie, jednak możemy go bezwzględnie używać ze względu na jego naturę:

Przykłady powinny szczegółowo opisywać każdą koncepcję, a zamieszczone tu linki mają jedynie charakter poglądowy i powinny zostać usunięte po zilustrowaniu koncepcji.

Akceptowanie funkcji jako argumentów

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]

Jak widać, nasza funkcja transform akceptuje dwa parametry, funkcję i kolekcję. Następnie iteruje kolekcję i wypycha wartości na wynik, wywołując fn na każdym z nich.

Wygląda znajomo? Jest to bardzo podobne do działania Array.prototype.map() !

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

Funkcje wyższego rzędu

Zasadniczo funkcje działające na innych funkcjach, przyjmując je jako argumenty lub zwracając je (lub oba), nazywane są funkcjami wyższego rzędu.

Funkcja wyższego rzędu jest funkcją, która może przyjąć inną funkcję jako argument. Podczas przekazywania wywołań zwrotnych używasz funkcji wyższego rzędu.

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);

Funkcja wyższego rzędu jest również funkcją, która zwraca inną funkcję jako wynik.

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()();

Tożsamość Monada

Jest to przykład implementacji monady tożsamości w JavaScript i może służyć jako punkt wyjścia do tworzenia innych monad.

Na podstawie konferencji Douglasa Crockforda na temat monad i gonad

Dzięki takiemu podejściu ponowne użycie funkcji będzie łatwiejsze ze względu na elastyczność, jaką zapewnia ta monada, oraz koszmary kompozycji:

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

czytelne, ładne i czyste:

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;
};

Działa z pierwotnymi wartościami

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

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

A także z przedmiotami

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'

Spróbujmy wszystkiego:

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

Czyste funkcje

Podstawową zasadą programowania funkcjonalnego jest to, że unika się zmiany stanu aplikacji (bezpaństwowość) i zmiennych poza jej zakresem (niezmienność).

Czyste funkcje to funkcje, które:

  • przy danym wejściu zawsze zwraca to samo wyjście
  • nie opierają się na żadnej zmiennej poza ich zakresem
  • nie modyfikują stanu aplikacji ( brak skutków ubocznych )

Rzućmy okiem na kilka przykładów:


Czyste funkcje nie mogą zmieniać żadnych zmiennych poza ich zakresem

Zanieczyszczona funkcja

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

Funkcja zmieniła wartość obj.a która jest poza zakresem.

Czysta funkcja

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

Funkcja nie zmieniła wartości obiektów obj


Funkcje czyste nie mogą polegać na zmiennych poza ich zakresem

Zanieczyszczona funkcja

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

Ta nieczysta funkcja opiera się na zmiennej a zdefiniowanej poza jej zakresem. Tak więc, jeśli a zostanie zmodyfikowane, wynik funkcji impure będzie inny.

Czysta funkcja

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

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

Wynik funkcji pure nie zależy od żadnej zmiennej poza jej zakresem.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow