Utilizziamo i cookie per migliorare la tua esperienza sul sito
CodeWorlds

Kompozycja funkcji: compose i pipe

W laboratorium genetycznym Parku Jurajskiego DNA dinozaura przechodzi przez serię etapów przetwarzania - ekstrakcja, oczyszczanie, sekwencjonowanie, walidacja. Każdy etap to oddzielna operacja, a ich połączenie w łańcuch daje kompletny proces. Dokładnie tak działa kompozycja funkcji - łączenie prostych funkcji w bardziej złożone operacje.

Czym jest kompozycja funkcji?

Kompozycja funkcji polega na łączeniu dwóch lub więcej funkcji, gdzie wynik jednej staje się wejściem następnej. Matematycznie:

f(g(x))
- najpierw stosujemy
g
, potem
f
.

1// Pojedyncze operacje na danych dinozaura
2const normalize = (name) => name.trim().toLowerCase();
3const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
4const addPrefix = (name) => 'DINO-' + name;
5
6// Bez kompozycji - zagniezdzone wywolania (trudne do czytania)
7const result = addPrefix(capitalize(normalize('  rex  ')));
8// 'DINO-Rex'
9
10// Z kompozycja - czytelny pipeline
11const formatDinoName = (name) => addPrefix(capitalize(normalize(name)));
12formatDinoName('  rex  '); // 'DINO-Rex'

Funkcja compose

compose
łączy funkcje od prawej do lewej - ostatnia funkcja w liście jest wykonywana pierwsza. To odwzorowanie matematycznej notacji
f(g(x))
.

1function compose(...fns) {
2  return (value) => fns.reduceRight(
3    (acc, fn) => fn(acc),
4    value
5  );
6}
7
8// Funkcje przetwarzajace probe DNA
9const extractDNA = (sample) => ({ ...sample, dna: sample.tissue + '-DNA' });
10const sequenceDNA = (sample) => ({ ...sample, sequence: sample.dna + '-SEQ' });
11const validateDNA = (sample) => ({ ...sample, valid: sample.sequence.length > 5 });
12
13// Compose: od prawej do lewej (extractDNA -> sequenceDNA -> validateDNA)
14const processSample = compose(validateDNA, sequenceDNA, extractDNA);
15
16const result = processSample({ tissue: 'TREX-001' });
17// { tissue: 'TREX-001', dna: 'TREX-001-DNA', sequence: 'TREX-001-DNA-SEQ', valid: true }

Funkcja pipe

pipe
to odwrotność
compose
- łączy funkcje od lewej do prawej. Czyta się jak naturalny przepływ danych, co wielu programistów uważa za bardziej intuicyjne.

1function pipe(...fns) {
2  return (value) => fns.reduce(
3    (acc, fn) => fn(acc),
4    value
5  );
6}
7
8// Pipe: od lewej do prawej (naturalny kierunek czytania)
9const processSample = pipe(extractDNA, sequenceDNA, validateDNA);
10// Identyczny wynik, ale bardziej czytelna kolejnosc
11
12// Praktyczny przyklad - przetwarzanie danych parku
13const processReport = pipe(
14  (data) => data.filter((d) => d.status === 'active'),
15  (data) => data.map((d) => ({ name: d.name, zone: d.zone })),
16  (data) => data.sort((a, b) => a.name.localeCompare(b.name)),
17);
18
19const parkData = [
20  { name: 'Rex', zone: 'A', status: 'active' },
21  { name: 'Stego', zone: 'B', status: 'inactive' },
22  { name: 'Blue', zone: 'A', status: 'active' },
23];
24processReport(parkData);
25// [{ name: 'Blue', zone: 'A' }, { name: 'Rex', zone: 'A' }]

Compose vs Pipe - kiedy którego używać?

Obie funkcje robią to samo, ale w odwrotnej kolejności. Wybór zależy od preferencji:

1// compose: od prawej do lewej (jak w matematyce)
2const process1 = compose(validate, transform, parse);
3// Czytaj: validate(transform(parse(x)))
4
5// pipe: od lewej do prawej (jak naturalny przeplyw)
6const process2 = pipe(parse, transform, validate);
7// Czytaj: x -> parse -> transform -> validate

W praktyce

pipe
jest częściej używany, bo odwzorowuje naturalny kierunek przetwarzania danych - od wejścia do wyjścia, od góry do dołu.

Vai a CodeWorlds