A beginner friendly intro to functional programming
Functional programming is a highly valued approach to writing code, and it’s popularity is continuously increasing in kommercielle programmer. Funktionel programmering er et paradigme for at skrive kode og er veltalende sat i introduktionen af denne artikel:
” -en stil med opbygning af strukturen og elementerne i computerprogrammer — der behandler beregning som evaluering af matematiske funktioner og undgår ændring-tilstand og foranderlige data. Det er et deklarativt programmeringsparadigme, hvilket betyder, at programmering udføres med udtryk eller erklæringer i stedet for udsagn.”
vi vil komme ind på, hvad dette præcist betyder meget snart, men lad os først få det grundlæggende ud af vejen ved at give en vis kontekst. Denne artikel tjener formålet med forhåbentlig at introducere de grundlæggende begreber i funktionel programmering til dig, og i slutningen af den ville vi have etableret en grundlæggende forståelse af, hvorfor vi ville vælge at anvende den i vores kodningsstilarter, hvordan den vedrører JavaScript og nogle grundlæggende mønstre, som du kan begynde at implementere i din kode. Vær på udkig efter en anden artikel, der vil bygge videre på denne og grave endnu dybere ned i de ideer, der diskuteres her.
rødderne til funktionel programmering ligger i Lambda calculus, som var et system udviklet i 1930 ‘ erne til at udtrykke beregning ved hjælp af funktioner svarende til det, vi snart vil se. I et stykke tid blev funktionelle programmeringskoncepter og sprog bredt diskuteret i den akademiske verden og videnskabelige sammenhænge og til sidst blødte ind i udviklingen af kommercielle programmer. Hvad der gør et programmeringssprog funktionelt eller ej, er dets evne til at lette det funktionelle programmeringsparadigme, sprog som disse er Ruby, Python, Julia og JavaScript, hvoraf sidstnævnte har egenskaber af imperative, objektorienterede og funktionelle paradigmer.
lad os se på et eksempel på at bruge et imperativ og derefter en funktionel tilgang til at udføre en enkelt opgave.
imperativ:
const arr = function getOdds(arr){
let odds = ; for(let i = 0; i < arr.length + 1; i++){
if ( i % 2 !== 0 ){
odds.push( i )
};
};
return odds
};console.log(getOdds(arr))
// logs
funktionel:
function getOdds2(arr){
return arr.filter(num => num % 2 !== 0)
}console.log(getOdds2(arr))
// logs // this can be even shorter
const getOdds3 = arr => arr.filter(num => num % 2 !== 0)console.log(getOdds3(arr))
// logs
bortset fra de åbenlyse forbedringer, som den funktionelle tilgang gør, som kortere kode, sparer os et par tastetryk, og det faktum, at det er meget lettere at forstå med et hurtigt blik, er det også elegant, hvilket resulterer i renere kode, forenkler fejlfinding, test og vedligeholdelse.
lad os nedbryde dette lidt, så vi kan nå en klar forståelse af forskellene mellem de to tilgange og definere, hvad funktionel programmering er.
i den første tilgang beskriver vi imperativt hver begivenhed, der skal finde sted for at vi kan nå opgaven med at filtrere de ulige tal fra et array. Vi fodrer en funktion et array, inde i funktionen opretter vi et tomt array, som vi vil bruge til at gemme de ulige tal i. Vi fortæller det at løbe over arrayet, så erklærer vi en betinget, hvis det aktuelle indeks er et ulige tal, skub det til den tomme. For loop inkluderer ikke det sidste nummer i arrayet, det inkluderer kun de numre, der fører op til det, så hvis vores sidste nummer er underligt, vil det ikke blive inkluderet. Derfor tilføjer vi + 1, når vi definerer mængden af iterationer, som vores loop skal lave.
i den anden tilgang definerer vi simpelthen det resultat, vi ønsker at se ved hjælp af en metode kaldet filter, og lad maskinen tage sig af alle trin imellem. Dette er en mere deklarativ tilgang. Vi erklærer, hvad slutresultatet skal være, og vi resten håndteres for os.
nu kan vi se, hvad ovennævnte definition stræber efter at udtrykke. En måde at programmere, ved hjælp af erklæringer og udtryk, snarere end udsagn. Denne definition skraber kun overfladen af funktionel programmering, og vi vil løbende bygge videre på vores definition, når vores forståelse vokser.
nogle forskelle mellem iterative og funktionelle tilgange.
- stilistisk definerer vi et problem og de ændringer, vi gerne vil se, i modsætning til at forklare det trin for trin.
- Vi behøver ikke at styre tilstand i vores funktioner som ovenfor, hvor vi lykkedes tilstanden af vores tomme array.
- Vi behøver ikke bekymre os så meget om rækkefølgen af udførelse.
- vi bruger mindre sløjfer, betingelser og bruger mere indbyggede metoder, genanvendelige funktioner og rekursion.
ved at bruge denne tilgang skriver vi i sidste ende renere kode, som som nævnt ovenfor hjælper os med fejlfinding og vedligeholdelse. Det holder tingene modulære, og dele af vores kode er opdelt i mindre stykker, som vi let kan teste. Vi kan genbruge dele af vores kode ved hjælp af hjælpefunktioner, og endelig er det en mere effektiv, matematisk tilgang til at skrive kode.
søjlerne: Vores kodningsværktøjssæt til skrivning af funktionel kode
følgende er et par vigtige aspekter ved skrivning af funktionel kode af høj kvalitet. Når vi ser, at dette er en oversigt, dykker vi ikke for meget ind i hver, i stedet definerer vi bare et par nøgleegenskaber og et eksempel på hver.
Pure funktioner:
Pure funktioner returnerer en værdi udelukkende baseret på, hvad der blev overført til den. Ideen bag det er, at det vil være en ren funktion, hvis den altid returnerer det samme resultat, hvis de samme værdier overføres til det, og det ændrer ikke værdier uden for ts-omfanget, hvilket gør det uafhængigt af enhver tilstand i systemet. Derfor kan en ren funktion aldrig mutere data, producere ingen bivirkninger og kan let genbruges. Et eksempel på en ikke-ren funktion vil være en funktion, der foretager et API-opkald eller returnerer et uforudsigeligt resultat.
enkel uren funktion:
var tip = 0;function calculateTip( mealTotal ) {
tip = 0.15 * mealTotal;
}calculateTip( 150 )
console.log(tip)
enkel ren funktion:
function isPure(x,y) {
return x * y
}console.log(isPure(3,5));
den rene funktion returnerer det nøjagtige resultat hver gang, og det muterer ikke nogen data uden for det. Den vigtige ting at være opmærksom på er, at en ren funktion skal holde sig væk fra at mutere data overhovedet, så vær forsigtig, når du vælger, hvilke metoder der skal bruges i dine rene funktioner. For eksempel, hvis du ønsker at flette to arrays inde i din funktion, som man typisk ville gøre i en React reducer, undgå at bruge arrayet.prototype.tryk () metode. I stedet vil du gerne bruge Array.prototype.concat (), som vil bevare tilstanden af de gamle arrays og returnere en ny til din brug.
højere ordensfunktioner:
i Javascript behandles funktioner som objekter, derfor kan vi passere funktioner rundt som vi ville have nogen anden værdi. En højere ordensfunktion er simpelthen en funktion, der fungerer på andre funktioner. De kan tage en funktion som input eller returnere en som output. Vi vil se et simpelt eksempel i den følgende demonstration.
anonyme funktioner:
anonyme funktioner er meget nyttige, når vi skal definere ad hoc-logik, som vi har brug for. Som navnet antyder, en anonym funktion i navnløs, og for det meste fundet som et argument for en funktion som erstatning for en navngivet funktion, en funktion tildelt en variabel eller returneret som en funktion i en højere ordensfunktion. Det er rødder ligger tungt i Lambda calculus og er meget vigtigt for alle funktionelle programmeringssprog.
anonym funktion tildelt en variabel. Let at passere rundt og påberåbe sig, når det er nødvendigt.
const myVar = function(){console.log(‘Anonymous function here!’)}myVar()
anonym funktion som argument
setInterval(function(){console.log(new Date().getTime())}, 1000);
anonyme funktioner inden for en højere ordensfunktion
function mealCall(meal){
return function(message){
return console.log(message + " " + meal + ‘!!’)
}
}const announceDinner = mealCall(‘dinner’)
const announceLunch = mealCall(‘breakfast’)announceDinner(‘hey!, come and get your’)
announceLunch(‘Rise and shine! time for’)
rekursion
rekursion er en velkendt funktionel programmeringsteknik. En rekursiv funktion er simpelthen en funktion, der kalder sig selv, og fungerer derfor som en løkke, der udfører den samme kode flere gange. Det kommer dog med en advarsel, man skal være forsigtig med at undgå uendelige rekursioner. Derfor er der brug for en basissag for at fortælle det, hvornår man skal stoppe. Rekursive funktioner eller algoritmer kan både implementeres ved hjælp af rekursion og sløjfer, men det er bedre at bruge rekursion. Nedenfor er den velkendte algoritme til faktorisering af et tal både ved hjælp af rekursion og en løkke.
rekursiv funktion
function factorialize(num){
if (num === 0 || num === 1){return 1;}
return (num * factorialize(num — 1));
}var result = factorialize(14);console.log(result);
rekursion ved hjælp af en loop
function factorialize(num) {
if (num === 0 || num === 1){
return 1;
}
for (var i = num-1; i >= 1; i-- ) {
num *= i;
}
return num;
}
console.log(factorialize(6));
Vi har dækket et par af de væsentlige ingredienser til at skrive funktionel kode. Det er ikke muligt altid at skrive funktionel kode i en applikation, men fordelene er store, når de bruges så meget som muligt. Rammer som Angular og React er stærkt påvirket af funktionel programmering, og biblioteker som Lodash og Redouch gør det muligt for os at udnytte fordelene ved det, så der er helt sikkert en stor fordel at begynde at tænke på FP-måde.
ressourcer til at lære mere? Her er nogle gode artikler og ressourcer til videre læring.
- hvorfor lære funktionel programmering i JavaScript? af Eric Elliot
- veltalende JavaScript af Marijn Haverbeke
- så du vil være en funktionel programmør af Charles Scalfani