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 kommersiella program. Funktionell programmering är ett paradigm för att skriva kod och läggs vältaligt i introduktionen av denna Wikipedia-artikel:
” — en stil för att bygga strukturen och elementen i datorprogram-som behandlar beräkning som utvärdering av matematiska funktioner och undviker förändrade tillstånd och föränderliga data. Det är ett deklarativt programmeringsparadigm, vilket innebär att programmering görs med uttryck eller deklarationer istället för uttalanden.”
Vi kommer att komma in i vad det här exakt betyder mycket snart, men först, låt oss få grunden ur vägen genom att ge något sammanhang. Den här artikeln tjänar syftet att förhoppningsvis introducera de grundläggande begreppen funktionell programmering till dig och i slutet av det skulle vi ha etablerat en grundläggande förståelse för varför vi skulle välja att tillämpa den i våra kodningstilar, hur den relaterar till JavaScript och några grundläggande mönster som du kan börja implementera i din kod. Håll utkik efter en andra artikel som kommer att bygga vidare på den här och gräva ännu djupare in i de tankar som diskuteras här.
rötterna till funktionell programmering ligger i Lambda calculus, som var ett system som utvecklades på 1930-talet för att uttrycka beräkning med funktioner som liknar vad vi kommer att se mycket snart. Under en lång tid diskuterades funktionella programmeringskoncept och språk allmänt i akademin och vetenskapliga sammanhang och så småningom blödde in i utvecklingen av kommersiell programvara. Det som gör ett programmeringsspråk funktionellt eller inte är dess förmåga att underlätta det funktionella programmeringsparadigmet, språk som dessa är Ruby, Python, Julia och JavaScript, vars senare har egenskaper av imperativ, objektorienterad och funktionell Paradigm.
låt oss titta på ett exempel på att använda ett imperativ och sedan ett funktionellt tillvägagångssätt för att slutföra en enda uppgift.
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
funktionell:
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
bortsett från de uppenbara förbättringarna gör det funktionella tillvägagångssättet, som kortare kod, vilket sparar oss ett par tangenttryckningar och det faktum att det är mycket lättare att förstå med en snabb blick, det är också elegant, vilket resulterar i renare kod, förenklar felsökning, testning och underhåll.
låt oss bryta ner detta lite, så att vi kan nå en tydlig förståelse av skillnaderna mellan de två metoderna och definiera vilken funktionell programmering som är.
i det första tillvägagångssättet beskriver vi imperativt varje händelse som behöver äga rum för att vi ska kunna uppnå uppgiften att filtrera bort de udda siffrorna från en matris. Vi matar en funktion en matris, inuti funktionen skapar vi en tom matris som vi kommer att använda för att lagra de udda siffrorna i. Vi berättar för det att slinga över matrisen, då förklarar vi en villkorlig, om det aktuella indexet är ett udda tal, tryck det till den tomma. För-slingan innehåller inte det sista numret i matrisen, det innehåller bara siffrorna som leder fram till det, så om vårt sista nummer är udda kommer det inte att inkluderas. Därför lägger vi till +1 när vi definierar mängden iterationer som vår slinga behöver göra.
i det andra tillvägagångssättet definierar vi helt enkelt resultatet vi vill se med hjälp av en metod som kallas filter och låter maskinen ta hand om alla steg däremellan. Detta är ett mer deklarativt tillvägagångssätt. Vi förklarar vad slutresultatet måste vara, och vi resten hanteras för oss.
Nu kan vi se vad den ovan nämnda definitionen strävar efter att uttrycka. Ett sätt att programmera, använda deklarationer och uttryck, snarare än uttalanden. Denna definition skrapar bara ytan av funktionell programmering, och vi kommer ständigt att bygga vidare på vår definition när vår förståelse växer.
vissa skillnader mellan iterativa och funktionella metoder.
- stilistiskt definierar vi ett problem och de förändringar vi skulle vilja se, i motsats till att förklara det steg för steg.
- Vi behöver inte hantera tillstånd i våra funktioner som ovan där vi hanterade tillståndet för vår tomma array.
- vi behöver inte oroa oss så mycket om exekveringsordningen.
- Vi använder mindre loopar, villkor och använder mer inbyggda metoder, återanvändbara funktioner och rekursion.
genom att använda detta tillvägagångssätt skriver vi slutligen renare kod som som nämnts ovan hjälper oss i felsökning och underhåll. Det håller saker modulära, och delar av vår kod är uppdelad i mindre bitar som vi enkelt kan testa. Vi kan återanvända delar av vår kod med hjälpfunktioner och slutligen är det ett mer effektivt, matematiskt sätt att skriva kod.
pelarna: Vår kodningsverktyg för att skriva funktionell kod
Följande är några viktiga aspekter för att skriva funktionell kod av hög kvalitet. När vi ser att detta är en översikt kommer vi inte att dyka in för mycket i var och en, istället definierar vi bara några viktiga egenskaper och ett exempel på var och en.
rena funktioner:
rena funktioner returnerar ett värde enbart baserat på vad som skickades in i det. Tanken bakom det är att det kommer att vara en ren funktion om det alltid returnerar samma resultat om samma värden skickas in i det, och det ändrar inte värden utanför ts-omfattningen, vilket gör det oberoende av något tillstånd i systemet. Därför kan en ren funktion aldrig mutera data, ge inga biverkningar och kan enkelt återanvändas. Ett exempel på en icke ren funktion är en funktion som gör ett API-samtal eller returnerar ett oförutsägbart resultat.
enkel Oren 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 rena funktionen returnerar det exakta resultatet varje gång, och det muterar inte några data utanför den. Det viktiga att vara uppmärksam på är att en ren funktion måste hålla sig borta från att mutera data alls, så var försiktig när du väljer vilka metoder som ska användas i dina rena funktioner. Om du till exempel vill slå samman två arrayer i din funktion, som man vanligtvis skulle göra i en React reducer, undvik att använda matrisen.prototypstadiet.push () metod. Istället vill du använda Array.prototypstadiet.concat (), som kommer att bevara tillståndet för de gamla matriserna och returnera en ny för din användning.
högre orderfunktioner:
I Javascript behandlas funktioner som objekt, därför kan vi skicka funktioner runt som vi skulle ha något annat värde. En högre orderfunktion är helt enkelt en funktion som fungerar på andra funktioner. De kan ta in en funktion som ingång, eller returnera en som utgång. Vi kommer att se ett enkelt exempel i följande demonstration.
anonyma funktioner:
anonyma funktioner är till stor hjälp när vi behöver definiera ad hoc-logik som vi behöver. Som namnet antyder, en anonym funktion i namnlösa, och mestadels finns som ett argument till en funktion som en ersättning för en namngiven funktion, en funktion som tilldelats en variabel, eller returneras som en funktion i en högre ordning funktion. Dess rötter ligger tungt i Lambda-kalkylen och är mycket viktigt för alla funktionella programmeringsspråk.
anonym funktion tilldelad en variabel. Lätt att passera runt och åberopa vid behov.
const myVar = function(){console.log(‘Anonymous function here!’)}myVar()
anonym funktion som argument
setInterval(function(){console.log(new Date().getTime())}, 1000);
anonyma funktioner inom en högre ordningsfunktion
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 är en välkänd funktionell programmeringsteknik. En rekursiv funktion är helt enkelt en funktion som kallar sig själv och fungerar därför som en slinga som kör samma kod flera gånger. Det kommer dock med en varning, man måste vara försiktig för att undvika oändliga rekursioner. Därför behövs ett basfall för att berätta när man ska sluta. Rekursiva funktioner eller algoritmer kan båda implementeras med rekursion och loopar, men det är bättre att använda rekursion. Nedan är den välkända algoritmen för faktorisering av ett tal både med rekursion och en slinga.
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 med en slinga
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 täckt några av de väsentliga ingredienserna för att skriva funktionskod. Det är inte möjligt att alltid skriva funktionskod i en applikation, men fördelarna är stora när de används så mycket som möjligt. Ramar som Angular och React påverkas starkt av funktionell programmering, och bibliotek som Redux och Lodash gör det möjligt för oss att utnyttja fördelarna med det, så det är definitivt en stor fördel att börja tänka på FP-sättet.
resurser för att lära sig mer? Här är några bra artiklar och resurser för vidareutbildning.
- Varför lära sig funktionell programmering i JavaScript? av Eric Elliot
- vältalig JavaScript av Marijn Haverbeke
- så du vill vara en funktionell programmerare av Charles Scalfani