Een korte introductie tot pipe () en compose () in JavaScript

Functioneel programmeren is voor mij de eye-opening reis geweest. Dit bericht, en dergelijke berichten, zijn een poging om mijn inzichten en perspectieven te delen terwijl ik door nieuwe functionele programmeerlanden trek.

Ramda is mijn favoriete FP-bibliotheek geweest vanwege het feit dat het veel eenvoudiger functioneel programmeren in JavaScript maakt. Ik raad het ten sterkste aan.

Blokken samenstellen om een ​​structuur te vormen. Vrij diepe dingen ...

Pijp

Het concept van pijp is eenvoudig - het combineert n functies. Het is een pijp die van links naar rechts stroomt en elke functie oproept met de uitvoer van de laatste.

Laten we een functie schrijven die iemands naam retourneert.

getName = (person) => person.name
getName ({name: 'Buckethead'})
// 'Buckethead'

Laten we een functie schrijven die tekenreeksen in hoofdletters plaatst.

uppercase = (string) => string.toUpperCase ()
hoofdletters ( 'Buckethead')
// 'BUCKETHEAD'

Dus als we de naam van een persoon wilden krijgen en er een hoofdletter voor willen gebruiken, kunnen we dit doen:

name = getName ({name: 'Buckethead'})
hoofdletters (naam)
// 'BUCKETHEAD'

Dat is prima, maar laten we de naam van die tussenliggende variabele elimineren.

hoofdletters (getName ({name: 'Buckethead'}))

Beter, maar ik ben niet dol op dat nestelen. Het kan te druk worden. Wat als we een functie willen toevoegen die de eerste 6 tekens van een string krijgt?

get6Characters = (string) => string.substring (0, 6)
get6Characters ( 'Buckethead')
// 'Emmer'

Met als resultaat:

get6Characters (hoofdletters (getName ({name: 'Buckethead'})))
'EMMER'

Laten we echt gek worden en een functie toevoegen om strings om te keren.

reverse = (string) => string
  .split ( '')
  .omgekeerde()
  .join ( '')
omgekeerde ( "Buckethead)
// 'daehtekcuB'

Nu hebben we:

reverse (get6Characters (hoofdletters (getName ({name: 'Buckethead'})))))
// 'TEKCUB'

Het kan een beetje ... veel krijgen.

Pijp te hulp!

In plaats van functies binnen functies te blokkeren of een aantal tussenliggende variabelen te maken, laten we alles doornemen!

pijp(
  getName,
  hoofdletters,
  get6Characters,
  omgekeerde
) ({name: 'Buckethead'})
// 'TEKCUB'

Pure kunst. Het is als een takenlijst!

Laten we er doorheen gaan.

Voor demo-doeleinden gebruik ik een pijpimplementatie uit een van Eric Elliott's functionele programmeerartikelen.

pipe = (... fns) => x => fns.reduce ((v, f) => f (v), x)

Ik hou van deze kleine one-liner.

Met behulp van rustparameters, zie mijn artikel daarover, kunnen we n functies doorgeven. Elke functie neemt de uitvoer van de vorige en het is allemaal gereduceerd tot een enkele waarde.

En u kunt het gebruiken zoals we hierboven deden.

pijp(
  getName,
  hoofdletters,
  get6Characters,
  omgekeerde
) ({name: 'Buckethead'})
// 'TEKCUB'

Ik zal pijp uitbreiden en enkele debugger-verklaringen toevoegen, en we zullen regel voor regel gaan.

pipe = (... functies) => (waarde) => {
  debugger;
  terugkeer functies
    .reduce ((currentValue, currentFunction) => {
       debugger;
       return currentFunction (currentValue);
    }, waarde)
}

Roep pijp met ons voorbeeld en laat de wonderen zich ontvouwen.

Bekijk de lokale variabelen. functies is een array van de 4 functies en waarde is {name: 'Buckethead'}.

Omdat we rustparameters gebruikten (nogmaals, zie mijn artikel ), maakt pipe het mogelijk om een ​​willekeurig aantal functies te gebruiken. Het wordt gewoon herhaald en elk wordt opgeroepen.

Bij de volgende debugger zijn we binnen verkleind. Dit is waar currentValue wordt doorgegeven aan currentFunction en wordt geretourneerd.

We zien dat het resultaat 'Buckethead' is omdat currentFunction de eigenschap .name van een willekeurig object retourneert. Dat zal in reductie worden geretourneerd, wat betekent dat dit de volgende keer de nieuwe huidige waarde wordt. Laten we naar de volgende debugger gaan en kijken.

Nu is currentValue ‘Buckethead’ omdat dat de vorige keer is teruggekeerd. currentFunction is hoofdletters, dus 'BUCKETHEAD' wordt de volgende currentValue.

Hetzelfde idee, kies de eerste 6 karakters van ‘BUCKETHEAD’ en geef ze af aan de volgende functie.

reverse (‘. aedi emaS’)

En je bent klaar!

Hoe zit het met compose ()?

Het is gewoon pijp in de andere richting.

Dus als je hetzelfde resultaat wilde als onze bovenstaande pijp, zou je het tegenovergestelde doen.

componeren(
  omgekeerde,
  get6Characters,
  hoofdletters,
  getName,
) ({name: 'Buckethead'})

Merk op hoe getName als laatste in de keten en omgekeerd als eerste is?

Hier is een snelle implementatie van componeren, opnieuw met dank aan Magical Eric Elliott, uit hetzelfde artikel.

compose = (... fns) => x => fns.reduceRight ((v, f) => f (v), x);

Ik laat het uitbreiden van deze functie met debuggers als een oefening voor jou. Speel ermee, gebruik het, waardeer het. En nog belangrijker, veel plezier!

Tot de volgende keer!

Wees voorzichtig,
Yazeed Bzadough