Einführung in die Kombinatoren

Kombinatoren sind Funktionen auf höherer Ebene, mit denen Sie Funktionen, Variablen oder andere Kombinatoren kombinieren können. Normalerweise enthalten sie keine Deklarationen ihrer eigenen Variablen oder Geschäftslogik. Sie sind die einzigen, die die Steuerung in einem Funktionsprogramm spülen.

In diesem Artikel werde ich versuchen, einige von ihnen zu behandeln:

Tippen Sie auf .

Ein Kombinator ist sehr nützlich für Funktionen, die nichts zurückgeben. Er nimmt die Funktion, an die der Parameter geht, und gibt sie dann zurück.

Erklärung

const tap = (fn) => (Wert) => {
fn(Wert);
return value;
};

Imperatives Beispiel

const [items, setItems] = useState(() => [])

axios
.get('http://localhost')
.then({ Daten } => {
setItems(daten)
console.log(daten)
onLoadData(daten)
}).then(...) // gibt undefiniert zurück - die Daten im Versprechen wurden geändert

Deklaratives Beispiel

const [items, setItems] = useState(() => [])

axios
.get('http://localhost')
.then(({ Daten }) => Daten)
.then(tap(setItems)) // (data) => { setItems(data); return data }
.then(tap(console.log)) // eine dann = eine Funktion = eine Verantwortung
.then(tap(onLoadData))
.then(...) // weiterhin Zugriff auf Originaldaten
// einfaches Öffnen/Schließen-Prinzip beibehalten

Currying

Sie teilt die Argumente einer Funktion auf und ermöglicht es, sie nacheinander aufzurufen.

Erklärung

const curry = (fn) => {
const curried = (...args) => {
if (fn.length !== args.length){
return curried.bind(null, ...args)
}
return fn(...args);
};

return curried

};


Beispiel

const curry = (fn) => {
const curried = (...args) => {
if (fn.length !== args.length){
return curried.bind(null, ...args)
}
return fn(...args);
};

return curried

};
const sum = (a, b, c) => a + b + c

const currySum = curry(sum)
/*
mögliche Aufrufe
currySum(a)(b)(c),
currySum(a)(b,c),
currySum(a,b)(c),
currySum(a,b,c)
*/

currySum(1) // (b, c) => 1 + a + b oder (b) => (c) => 1 + a + b
currySum(5)(10) // (c) => 5 + 10 + b
currySum(5, 10) // (c) => 5 + 10 + b
currySum(5)(10)(20) // 35
currySumme(5, 10)(20) // 35
currySumme(5)(10, 20) // 35

const divideBy = curry((a, b) => b / a)
const multiplyBy = curry((a, b) => a * b)

const divideByTwo = divideBy(2)
divideByTwo(10) // ergibt 5

const multiplyByFive = multiplyBy(5)
multiplyByFive(10) // ergibt 50

Pfeifen/Komponieren

Durch Komposition ist es möglich, Daten von einer Funktion an eine andere zu übergeben. Dabei ist es wichtig, dass die Funktionen die gleiche Anzahl von Argumenten annehmen. Der Unterschied zwischen pipe und compose besteht darin, dass erstere die Funktion vom Anfang bis zum Ende ausführt, während compose sie vom Ende her aufruft.

Erklärung

const pipe = (...fns) => (Wert, ...args) =>
fns.reduce((v, f, i) =>
i === 0
? f(v, ...args)
: f(v),
value);

const compose = (...fns) => (value, ...args) =>
fns.reduceRight((v, f, i) =>
i === (fns.length - 1)
? f(v, ...args)
: f(v),
value);
const pipe = (...fns) => (Wert, ...args) =>
fns.reduce((v, f, i) =>
i === 0
? f(v, ...args)
: f(v),
value);

const compose = (...fns) => (value, ...args) =>
fns.reduceRight((v, f, i) =>
i === (fns.length - 1)
? f(v, ...args)
: f(v),
value);

Imperatives Beispiel

const sine = (val) => Math.sin(val * Math.PI / 180) // nicht lesbar
 sine(90) // liefert 1

Deklaratives Beispiel

const sine = pipe(
multiplyBy(Math.PI) // ↓ val * Math.PI
divideBy(180), // ↓ val * Math.PI / 180
Math.sin, // ↓ Math.sin(val * Math.PI / 180)
)

const sine = compose(
Math.sin, // ↑ Math.sin(val * Math.PI / 180)
divideBy(180), // ↑ val * Math.PI / 180
multiplyBy(Math.PI) // ↑ val * Math.PI
)

Sinus(90) // ergibt 1

Gabel

Der Fork Combiner ist in Situationen nützlich, in denen Sie einen Wert auf zwei Arten verarbeiten und das Ergebnis kombinieren möchten.

Erklärung

const fork = (join, fn1, fn2) => (Wert) => join(fn1(Wert), fn2(Wert));

Beispiel

const length = (array) => array.length
const sum = (array) => array.reduce((a, b) => a + b, 0)
const divide = (a, b) => a / b

const arithmeticAverage = fork(divide, sum, length)

arithmetischerDurchschnitt([5, 3, 2, 8, 4, 2]) // ergibt 4

Abwechslung

Dieser Kombinator nimmt zwei Funktionen und gibt das Ergebnis der ersten zurück, wenn es wahr ist. Andernfalls gibt er das Ergebnis der zweiten Funktion zurück.

Erklärung

const alt = (fn, orFn) => (Wert) => fn(Wert) || orFn(Wert)

Beispiel

const users = [{
uuid: '123e4567-e89b-12d3-a456-426655440000',
name: 'William'
}]

const findUser = ({ uuid: searchesUuid }) =>
users.find(({ uuid }) => uuid === searchesUuid)

const newUser = data => ({ ...data, uuid: uuid() // neue uuid erstellen })

const findOrCreate = alt(findUser, newUser)

findOrCreate({ uuid: '123e4567-e89b-12d3-a456-426655440000' }) // liefert William-Objekt
findOrCreate({ name: 'John' }) // gibt John-Objekt mit neuer uuid zurück

Sequenz

Es akzeptiert viele unabhängige Funktionen und übergibt an jede von ihnen denselben Parameter. In der Regel geben diese Funktionen keinen Wert zurück.

Erklärung

const seq = (...fns) => (val) => fns.forEach(fn => fn(val))

Beispiel

const appendUser = (id) => ({ Name }) => {
document.getElementById(id).innerHTML = name
}

const printUserContact = pipe(
findOrCreate, // gibt Benutzer zurück
seq(
appendUser('#contact'), // Benutzer => ungültig
console.log, // Benutzer => ungültig
onContactUpdate // benutzer => void
)
)

printUserContact(userData)
Kooperationsbanner
de_DEGerman