Wprowadzenie
Często utrzymanie niemodyfikowalności jest trudne do utrzymania. Wzorzec zawijania dane do kontenera przychodzi na ratunek. Zabezpiecza on wartości, dzięki czemu korzystanie z nich jest bezpieczne i nie powoduje skutków ubocznych.
Jeśli jesteś tu nowy, koniecznie sprawdź moje ostatnie 2 części dotyczące programowania funkcjonalnego na The Codest blog o:
Funktor
Nie ma złożonej logiki. Jego głównym zadaniem jest opakowywanie kontekstu i wykonywanie na nim funkcji, które otrzymuje z zewnątrz. Za każdym razem, gdy zmienia się wartość, nowa instancja kontenera jest przepakowywana i zwracana. Podczas wywoływania funkcji mapa która wykonuje określoną akcję, zwraca nową instancję kontenera z wartością zwróconą przez przekazaną funkcję, zachowując zasadę niemodyfikowalności.
Deklaracja
const Functor = value => ({
map: fn => Functor(fn(value)),
chain: fn => fn(value),
of: () => value
});
mapa - przydatna, gdy chcesz zmienić stan wartości w kontenerze, ale nie chcesz jej jeszcze zwracać.
łańcuch - używany, jeśli chcesz przekazać wartość do funkcji bez modyfikowania stanu kontenera. Zwykle na końcu mapa połączenia.
z - zwraca bieżącą wartość
Przykład imperatywu
const randomInt = (max) => Math.floor(Math.random() * (max + 1))
const randomNumber = randomInt(200) // zwraca liczbę pomiędzy 0 a 200
decrease(randomNumber) // zwraca (liczbę pomiędzy 0 a 200) - 1
Przykład deklaratywny
const randomIntWrapper = (max) =>
Functor(max)
.map(increase) // max + 1
.map(multiplyBy(Math.random())) // Math.random() * (max + 1)
.map(Math.floor) // Math.floor(Math.random() * (max + 1))
const randomNumber = randomIntWrapper(200)
randomNumber.of() // zwraca liczbę pomiędzy 0 a 200
randomNumber.chain(decrease) // zwraca (liczbę między 0 a 200) - 1
Monada
Czasami, oprócz funkcji wywołujących nowy stan wartości, potrzebna jest dodatkowa logika ukryta w kontenerze. Tutaj przydaje się monada, która jest rozszerzeniem funkcji funktor. Może na przykład zdecydować, co powinno się stać, gdy wartość ma określoną wartość lub jaką ścieżkę mają obrać kolejne działania.
Monada może
Monada być może rozwiązuje problem wartości, które nie zwracają prawdy. Kiedy tak się dzieje, kolejne mapa są ignorowane, ale umożliwia zwrócenie alternatywy poprzez wywołanie funkcji getOr method. Pozwala to uniknąć stosowania operatorów if / else, które są popularne w metodach imperatywny programowanie. Monada ta składa się z trzech kontenerów:
Nic - uruchamia się, gdy wartość, która nie jest prawdziwa, wpada do kontenera lub filtr zwraca wartość false. Służy do symulacji wykonania funkcji. Oznacza to, że ten kontener odbiera funkcję, ale jej nie wykonuje.
Po prostu - jest to główny kontener, który wykonuje wszystkie funkcje, ale jeśli wartość zmieni się na wartość false lub filtr zwróci wartość false, przekaże ją do metody Nic pojemnik.
Może - Biorę wartość początkową i decyduję, który kontener wywołać na początku.
Deklaracja
const Just = value => ({
map: fn => Maybe(fn(value)),
chain: fn => fn(value),
of: () => value,
getOr: () => value,
filter: fn => fn(value) ? Just(value) : Nothing(),
type: 'just'
});
const Nothing = () => ({
map: fn => Nothing(),
chain: fn => fn(),
of: () => Nothing(),
getOr: substitute => substitute,
filter: () => Nothing(),
type: 'nothing'
});
const Maybe = value =>
value == null || value == undefined || value.type == 'nothing'
? Nothing()
: Just(value)

Rozbudujmy teraz poprzedni przykład o warunek. Jeśli wartość max jest większa od zera, funkcja zostanie wykonana. W przeciwnym razie funkcja zwróci 0.
Przykład imperatywu
const randomInt = (max) => {
if(max > 0) {
return Math.floor(Math.random() * (max + 1))
} else {
return 0
}
}
const bookMiddlePage = 200
const randomPage = randomInt(10) || bookMiddlePage // zwraca losową wartość
const randomPage = randomInt(-10) || bookMiddlePage // zwraca 200
Przykład deklaratywny
const randomIntWrapper = (max) =>
Maybe(max)
.filter(max => max > 0) // wartość false ignoruje dalsze wywołania
.map(increase)
.map(multiplyBy(Math.random()))
.map(Math.floor)
const bookMiddlePage = 200
// Tylko kontener
const randomPage = randomIntWrapper(10).getOr(bookMiddlePage) // zwraca losową wartość
// Kontener bez niczego
const randomPage = randomIntWrapper(-10).getOr(bookMiddlePage) // zwraca 200
