Lassen Sie uns über das Thema der funktionalen Komposition phantasieren und die Bedeutung des Kompositions- / Pipeline-Operators klären.
TL; DR
Verfassen Sie Funktionen wie ein Chef:

Beliebte Implementierungen von compose
- wenn sie aufgerufen werden, erstellen sie neue und neue Funktionen basierend auf der Rekursion, was sind die Nachteile und wie man dies umgeht.
Sie können die Compose-Funktion als reine Funktion betrachten, die nur von den Argumenten abhängt. Wenn wir also dieselben Funktionen in derselben Reihenfolge zusammenstellen, sollten wir eine identische Funktion erhalten, aber in der JavaScript-Welt ist dies nicht der Fall. Jeder Aufruf zum Verfassen - gibt eine neue Funktion zurück. Dies führt dazu, dass immer mehr neue Funktionen im Speicher erstellt werden und dass Probleme beim Auswendiglernen, Vergleichen und Debuggen auftreten.
Es muss etwas getan werden.
Motivation
- Erhalten Sie assoziative Identität:
Es wird dringend empfohlen, keine neuen Objekte zu erstellen und die vorherigen Ergebnisse der Compose-Funktion wiederzuverwenden. Eines der Entwicklerprobleme von React ist die Implementierung von flatCompare, die mit dem Ergebnis der Funktionszusammensetzung funktioniert. Beispielsweise wird durch die Zusammensetzung des Sendens eines Ereignisses mit einem Rückruf immer eine neue Funktion erstellt, die zu einer Aktualisierung des Eigenschaftswerts führt.
Beliebte Implementierungen einer Komposition haben keine Rückgabewertidentität.
Teilweise kann das Problem der Songidentität durch Auswendiglernen der Argumente gelöst werden. Die Frage der assoziativen Identität bleibt jedoch:
import {memoize} from 'ramda' const memoCompose = memoize(compose) memoCompose(a, b) === memoCompose(a, b)
- Vereinfachen Sie das Debuggen von Kompositionen:
Die Verwendung von Tap-Funktionen hilft natürlich beim Debuggen von Funktionen, die einen einzelnen Ausdruck im Körper haben. Es ist jedoch wünschenswert, einen möglichst flachen Aufrufstapel zum Debuggen zu haben.
- Befreien Sie sich von rekursionsbedingtem Overhead:
Die rekursive Implementierung der funktionalen Zusammensetzung ist mit einem Overhead verbunden, wodurch neue Elemente im Aufrufstapel erstellt werden. Wenn Sie eine Komposition mit 5 oder mehr Funktionen aufrufen, ist dies deutlich erkennbar. Unter Verwendung funktionaler Ansätze in der Entwicklung ist es notwendig, Kompositionen aus Dutzenden sehr einfacher Funktionen zu erstellen.
Lösung
Machen Sie ein Monoid (oder ein Semigroupoid mit Unterstützung für die Kategoriespezifikation) in Bezug auf Fantasy-Land:
import compose, {identity} from 'lazy-compose' import {add} from 'ramda' const a = add(1) const b = add(2) const c = add(3) test('Laws', () => { compose(a, compose(b, c)) === compose(compose(a, b), c) // compose(a, identity) === a //right identity compose(identity, a) === a //left identity }
Anwendungsfälle
- Nützlich beim Speichern von zusammengesetzten Kompositionen bei der Arbeit mit Editoren. Zum Beispiel für redux / mapStateToProps und
erneut auswählen. - Die Zusammensetzung der Linsen.
Sie können streng gleichwertige Objektive erstellen und wiederverwenden, die an derselben Stelle fokussiert sind.
import {lensProp, memoize} from 'ramda' import compose from 'lazy-compose' const constantLens = memoize(lensProp) const lensA = constantLens('a') const lensB = constantLens('b') const lensC = constantLens('c') const lensAB = compose(lensB, lensA) console.log( compose(lensC, lensAB) === compose(lensC, lensB, lensA) )
- Gespeicherte Rückrufe mit der Fähigkeit, bis zur endgültigen Funktion des Sendens eines Ereignisses zu komponieren.
In diesem Beispiel wird derselbe Rückruf an die Listenelemente gesendet.
```jsx import {compose, constant} from './src/lazyCompose' // constant - returns the same memoized function for each argrum // just like React.useCallback import {compose, constant} from 'lazy-compose' const List = ({dispatch, data}) => data.map( id => <Button key={id} onClick={compose(dispatch, makeAction, contsant(id))} /> ) const Button = React.memo( props => <button {...props} /> ) const makeAction = payload => ({ type: 'onClick', payload, }) ```
Faule Zusammensetzung von React-Komponenten, ohne Komponenten höherer Ordnung zu erzeugen. In diesem Fall reduziert die verzögerte Komposition das Funktionsfeld, ohne zusätzliche Abschlüsse zu erstellen. Diese Frage beunruhigt viele Entwickler, die die Bibliothek zum erneuten Erstellen verwenden.
import {memoize, mergeRight} from 'ramda' import {constant, compose} from './src/lazyCompose' const defaultProps = memoize(mergeRight) const withState = memoize( defaultState => props => { const [state, setState] = React.useState(defaultState) return {...props, state, setState} } ) const Component = ({value, label, ...props)) => <label {...props}>{label} : {value}</label> const withCounter = compose( ({setState, state, ...props}) => ({ ...props value: state, onClick: compose(setState, constant(state + 1)) }), withState(0), ) const Counter = compose( Component, withCounter, defaultProps({label: 'Clicks'}), )
Monaden und Applikative (in Bezug auf Fantasieland) mit strikter Äquivalenz durch Zwischenspeichern des Ergebnisses der Komposition. Wenn Sie im Typkonstruktor auf das Wörterbuch zuvor erstellter Objekte zugreifen, erhalten Sie Folgendes:
type Info = { age?: number } type User = { info?: Info } const mayBeAge = LazyMaybe<Info>.of(identity) .map(getAge) .contramap(getInfo) const age = mayBeAge.ap(data) const maybeAge2 = LazyMaybe<User>.of(compose(getAge, getInfo)) console.log(maybeAge === maybeAge2) // , //
Ich habe diesen Ansatz für eine lange Zeit verwendet, ich habe das Repository hier entworfen .
NPM-Paket: npm i lazy-compose
.
Es ist interessant, Feedback zum Schließen des Cache von Funktionen zu erhalten, die zur Laufzeit abhängig von den Schließungen erstellt wurden.
UPD
Ich sehe offensichtliche Fragen voraus:
Ja, Sie können Map durch WeakMap ersetzen.
Ja, Sie müssen es ermöglichen, einen Cache eines Drittanbieters als Middleware zu verbinden.
Sie sollten keine Debatte zum Thema Caches arrangieren, da es keine ideale Caching-Strategie gibt.
Warum Schwanz und Kopf, wenn alles in der Liste steht - Schwanz und Kopf, Teil der Implementierung mit Memoisierung basierend auf Teilen der Komposition, und nicht jede Funktion separat.