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 aplicații software comerciale. Programarea funcțională este o paradigmă de scriere a codului și este pusă elocvent în introducerea acestui articol Wikipedia:
” -un stil de construire a structurii și elementelor programelor de calculator — care tratează calculul ca evaluare a funcțiilor matematice și evită schimbarea stării și a datelor mutabile. Este o paradigmă de programare declarativă, ceea ce înseamnă că programarea se face cu expresii sau declarații în loc de declarații.”
vom intra în ceea ce înseamnă exact acest lucru foarte curând, dar mai întâi, să scoatem fundamentele din drum oferind un anumit context. Acest articol servește scopului de a vă introduce, sperăm, conceptele fundamentale ale programării funcționale și, până la sfârșitul acesteia, am fi stabilit o înțelegere de bază a motivului pentru care am alege să o aplicăm în stilurile noastre de codificare, cum se referă la JavaScript și câteva modele de bază pe care le puteți începe implementarea în codul dvs. Fiți în căutarea unui al doilea articol care se va baza pe acesta și va săpa și mai adânc în ideile discutate aici.
rădăcinile programării funcționale se află în calculul Lambda, care a fost un sistem dezvoltat în anii 1930 pentru a exprima calculul folosind funcții similare cu ceea ce vom vedea foarte curând. De ceva timp, conceptele și limbajele de programare funcționale au fost discutate pe scară largă în mediul academic și în contexte științifice și, în cele din urmă, au sângerat în dezvoltarea software-ului comercial. Ceea ce face un limbaj de programare funcțional sau nu este capacitatea sa de a facilita paradigma de programare funcțională, limbaje ca acestea sunt Ruby, Python, Julia și JavaScript, acesta din urmă având proprietăți De paradigme imperative, orientate pe obiecte și funcționale.
Să analizăm un exemplu de utilizare a unui imperativ și apoi o abordare funcțională pentru finalizarea unei singure sarcini.
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
funcțional:
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
pe lângă îmbunătățirile evidente pe care le face abordarea funcțională, cum ar fi Codul mai scurt, economisind câteva apăsări de taste și faptul că este mult mai ușor de înțeles dintr-o privire rapidă, este și elegant, ceea ce duce la un cod mai curat, simplifică depanarea, testarea și întreținerea.
să detaliem puțin, astfel încât să putem ajunge la o înțelegere clară a diferențelor dintre cele două abordări și să definim ce este programarea funcțională.
în prima abordare descriem imperativ fiecare eveniment care trebuie să aibă loc pentru ca noi să realizăm sarcina de a filtra numerele impare dintr-o matrice. Alimentăm o funcție o matrice, în interiorul funcției creăm o matrice goală pe care o vom folosi pentru a stoca numerele impare. Îi spunem să treacă peste matrice, apoi declarăm un condițional, dacă indicele curent este un număr impar, împingeți-l la cel gol. Bucla for NU include ultimul număr din matrice, include doar numerele care duc la acesta, deci dacă ultimul nostru număr este impar, acesta nu va fi inclus. Prin urmare, adăugăm +1 atunci când definim cantitatea de iterații pe care bucla noastră trebuie să o facă.
în a doua abordare, definim pur și simplu rezultatul pe care dorim să-l vedem folosind o metodă numită filtru și permitem mașinii să aibă grijă de toți pașii dintre ei. Aceasta este o abordare mai declarativă. Noi declarăm ceea ce rezultatul final trebuie să fie, iar noi restul este manipulat pentru noi.
acum putem vedea ce se străduiește să exprime definiția menționată mai sus. Un mod de programare, folosind declarații și expresii, mai degrabă decât declarații. Această definiție zgârie doar suprafața programării funcționale și vom construi continuu pe definiția noastră pe măsură ce înțelegerea noastră crește.
unele diferențe între abordările iterative și funcționale.
- stilistic, definim o problemă și schimbările pe care am dori să le vedem, spre deosebire de explicarea ei pas cu pas.
- nu trebuie să gestionăm starea în funcțiile noastre, cum ar fi mai sus, unde am gestionat starea matricei noastre goale.
- noi nu trebuie să vă faceți griji la fel de mult despre ordinea de execuție.
- folosim mai puține bucle, condiții și folosim mai multe metode încorporate, funcții reutilizabile și recursivitate.
prin utilizarea acestei abordări, vom scrie în cele din urmă cod curat care, după cum sa menționat mai sus, ne ajută în depanare și întreținere. Păstrează lucrurile modulare, iar secțiunile codului nostru sunt împărțite în bucăți mai mici pe care le putem testa cu ușurință. Putem reutiliza părți ale codului nostru folosind funcții de ajutor și, în cele din urmă, este o abordare matematică mai eficientă pentru a scrie cod.
stâlpii: Setul nostru de instrumente de codificare pentru scrierea codului funcțional
următoarele sunt câteva aspecte importante pentru scrierea codului funcțional de înaltă calitate. Văzând că aceasta este o imagine de ansamblu, nu ne vom scufunda prea mult în fiecare, în schimb vom defini doar câteva caracteristici cheie și un exemplu din fiecare.
funcții Pure:
funcțiile Pure returnează o valoare bazată exclusiv pe ceea ce a fost transmis în ea. Ideea din spatele ei este că va fi o funcție pură dacă returnează întotdeauna același rezultat dacă aceleași valori sunt transmise în ea și nu modifică valori în afara domeniului ts, ceea ce îl face independent de orice stare din sistem. Prin urmare, o funcție pură nu poate muta niciodată datele, nu produce efecte secundare și poate fi refolosită cu ușurință. Un exemplu de funcție non pure va fi o funcție care face un apel API sau returnează un rezultat imprevizibil.
funcție impură simplă:
var tip = 0;function calculateTip( mealTotal ) {
tip = 0.15 * mealTotal;
}calculateTip( 150 )
console.log(tip)
funcție pură simplă:
function isPure(x,y) {
return x * y
}console.log(isPure(3,5));
funcția pură va returna rezultatul exact de fiecare dată și nu va muta date în afara acesteia. Cel mai important lucru pe care trebuie să-l acordați este că o funcție pură trebuie să stea departe de orice fel de date mutante, așa că aveți grijă atunci când selectați ce metode să utilizați în interiorul funcțiilor dvs. pure. De exemplu, dacă doriți să îmbinați două matrice în interiorul funcției dvs., așa cum s-ar face de obicei într-un reductor React, evitați utilizarea matricei.prototip.push () metodă. În schimb, ați dori să utilizați matrice.prototip.concat (), care va păstra starea matricelor vechi și va returna una nouă pentru utilizarea dvs.
funcții de ordin superior:
în Javascript, funcțiile sunt tratate ca obiecte, prin urmare, putem transmite funcții în jurul valorii de orice altă valoare. O funcție de ordin superior este pur și simplu o funcție care funcționează pe alte funcții. Ele pot prelua o funcție ca intrare sau pot returna una ca ieșire. Vom vedea un exemplu simplu în următoarea demonstrație.
funcții anonime:
funcțiile anonime sunt foarte utile atunci când trebuie să definim logica ad-hoc așa cum avem nevoie. După cum sugerează și numele, o funcție anonimă în nameless și găsită mai ales ca argument la o funcție ca înlocuitor pentru o funcție numită, o funcție atribuită unei variabile sau returnată ca funcție într-o funcție de ordin superior. Rădăcinile sale se află foarte mult în calculul Lambda și sunt foarte importante pentru toate limbajele de programare funcționale.
funcție anonimă atribuită unei variabile. Ușor să treacă în jurul și invoca atunci când este necesar.
const myVar = function(){console.log(‘Anonymous function here!’)}myVar()
funcția anonimă ca argument
setInterval(function(){console.log(new Date().getTime())}, 1000);
funcțiile anonime într-o funcție de ordin superior
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’)
recursivitatea
recursivitatea este o tehnică de programare funcțională bine cunoscută. O funcție recursivă este pur și simplu o funcție care se numește și, prin urmare, acționează ca o buclă care execută același cod de mai multe ori. Ea vine cu un avertisment, deși, trebuie să fie atent pentru a evita recursiuni infinite. Prin urmare, este nevoie de un caz de bază, pentru a-i spune când să se oprească. Funcțiile sau algoritmii recursivi pot fi implementați folosind recursivitate și bucle, dar este mai bine să folosiți recursivitatea. Mai jos este algoritmul bine cunoscut pentru factorizarea unui număr atât folosind recursivitate, cât și o buclă.
funcție recursivă
function factorialize(num){
if (num === 0 || num === 1){return 1;}
return (num * factorialize(num — 1));
}var result = factorialize(14);console.log(result);
Recursivitate folosind o buclă
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));
am acoperit câteva dintre ingredientele esențiale pentru scrierea codului funcțional. Nu este posibil să scrieți întotdeauna Cod funcțional într-o aplicație, dar beneficiile sunt excelente atunci când sunt utilizate cât mai mult posibil. Cadre precum Angular și React sunt puternic influențate de programarea funcțională, iar bibliotecile precum Redux și Lodash ne permit să utilizăm beneficiile it, deci există cu siguranță un mare beneficiu pentru a începe să gândim în modul FP.
resurse pentru a învăța mai mult? Iată câteva articole și resurse excelente pentru învățarea ulterioară.
- De ce să înveți programarea funcțională în JavaScript? de Eric Elliot
- JavaScript elocvent de Marijn Haverbeke
- Deci vrei să fii un programator funcțional de Charles Scalfani