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 kaupalliset ohjelmistosovellukset. Funktionaalinen ohjelmointi on paradigma koodin kirjoittamisesta ja se esitetään kaunopuheisesti tämän Wikipedian artikkelin johdannossa:
” -tietokoneohjelmien rakenteen ja elementtien rakentamistyyli, joka käsittelee laskentaa matemaattisten funktioiden arviointina ja välttää muuttuvaa ja muunneltavaa dataa. Se on deklaratiivinen ohjelmointiparadigma, eli ohjelmointi tehdään lauseiden sijaan lauseilla tai julistuksilla.”
pääsemme hyvin pian siihen, mitä tämä tarkalleen tarkoittaa, mutta hoidetaan ensin fundamentit pois alta tarjoamalla jokin konteksti. Tämän artikkelin tarkoituksena on toivottavasti ottaa käyttöön funktionaalisen ohjelmoinnin peruskäsitteet sinulle ja sen loppuun mennessä olisimme perustaneet peruskäsityksen siitä, miksi haluamme soveltaa sitä koodaustyyleihimme, miten se liittyy Javascriptiin ja joihinkin peruskuvioihin, joita voit alkaa toteuttaa koodiisi. Etsi toinen kirjoitus, joka perustuu tähän kirjoitukseen, ja syvenny vielä syvemmälle tässä käsiteltyihin ajatuksiin.
funktionaalisen ohjelmoinnin juuret ovat Lambda-laskennassa, joka oli 1930-luvulla kehitetty järjestelmä laskennan ilmaisemiseksi funktioilla, jotka ovat samankaltaisia kuin mitä tulemme näkemään hyvin pian. Funktionaalisista ohjelmointikäsitteistä ja kielistä keskusteltiin akateemisessa maailmassa ja tieteellisissä yhteyksissä jonkin aikaa, ja ne valuivat lopulta kaupallisten ohjelmistojen kehitykseen. Mikä tekee ohjelmointikielestä funktionaalisen tai ei, on sen kyky helpottaa funktionaalista ohjelmointiparadigmaa, tällaisia kieliä ovat Ruby, Python, Julia ja JavaScript, joista jälkimmäisellä on imperatiivisen, oliokeskeisen ja funktionaalisen paradigman ominaisuuksia.
tarkastellaan esimerkkiä imperatiivin käyttämisestä ja sen jälkeen funktionaalista lähestymistapaa yksittäisen tehtävän suorittamiseen.
imperatiivi:
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
funktionaalinen:
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
sen lisäksi, että toiminnallisen lähestymistavan ilmeiset parannukset, kuten lyhyempi koodi, säästävät meiltä pari painallusta, ja se, että se on paljon helpompi ymmärtää nopealla silmäyksellä, se on myös tyylikäs, mikä johtaa puhtaampaan koodiin, yksinkertaistaa virheenkorjausta, testausta ja huoltoa.
eritellään tätä hieman, jotta päästään selkeään käsitykseen näiden kahden lähestymistavan eroista ja määritellään, mitä funktionaalinen ohjelmointi on.
ensimmäisessä lähestymistavassa kuvataan imperatiivisesti jokaista tapahtumaa, jonka on tapahduttava, jotta voimme saavuttaa tehtävän suodattaa parittomat numerot jonosta. Syötämme funktio array, sisällä funktio luomme tyhjä array, jota käytämme tallentaa pariton numerot. Kerromme sen silmukka yli array, sitten julistamme ehdollinen, jos nykyinen indeksi on pariton luku, työnnä se tyhjä yksi. For-silmukka ei sisällä joukon viimeistä numeroa, se sisältää vain siihen johtavat numerot, joten jos viimeinen numero on pariton, sitä ei oteta mukaan. Siksi lisäämme +1 määritettäessä määrää iteraatioita meidän silmukka tarvitsee tehdä.
toisessa lähestymistavassa määritellään yksinkertaisesti haluamamme lopputulos suodattimeksi kutsutulla menetelmällä ja annetaan koneen hoitaa kaikki välivaiheet. Tämä on julistavampi lähestymistapa. Julistamme, mikä lopputuloksen pitää olla, ja me hoidamme loput puolestamme.
nyt nähdään, mitä edellä mainittu määritelmä pyrkii ilmaisemaan. Tapa ohjelmoida, käyttäen julistuksia ja ilmaisuja, eikä lausuntoja. Tämä määritelmä vain raapii funktionaalisen ohjelmoinnin pintaa, ja rakennamme jatkuvasti määritelmämme varaan ymmärryksemme kasvaessa.
joitakin eroja iteratiivisten ja funktionaalisten lähestymistapojen välillä.
- tyylillisesti määrittelemme ongelman ja haluamamme muutokset sen sijaan, että selittäisimme sen askel askeleelta.
- meidän ei tarvitse hallita tilaa toiminnoissamme kuten yllä, missä hoidimme tyhjän jonomme tilaa.
- meidän ei tarvitse huolehtia yhtä paljon teloitusjärjestyksestä.
- käytämme vähemmän silmukoita, ehtoja ja käytämme enemmän rakennettuja menetelmiä, uudelleenkäytettäviä funktioita ja rekursioita.
käyttämällä tätä lähestymistapaa, lopulta kirjoitamme puhtaampaa koodia, joka, kuten edellä mainittiin, auttaa meitä virheenkorjauksessa ja ylläpidossa. Se pitää asiat modulaarisina, ja koodimme osat on jaettu pienempiin osiin, joita voimme testata helposti. Voimme käyttää koodimme osia uudelleen auttajatoimintojen avulla ja lopuksi, se on tehokkaampi, matemaattinen lähestymistapa koodin kirjoittamiseen.
pilarit: Koodaus työkalupakkimme funktionaalisen koodin kirjoittamiseen
seuraavat ovat muutamia tärkeitä näkökohtia laadukkaan funktionaalisen koodin kirjoittamiseen. Koska tämä on yleiskatsaus, emme sukella liikaa kuhunkin, vaan määrittelemme vain muutamia keskeisiä ominaisuuksia ja yhden esimerkin kustakin.
puhtaat funktiot:
puhtaat funktiot palauttavat arvon yksinomaan sen perusteella, mitä siihen on siirretty. Ajatus sen takana on, että se on puhdas funktio, jos se palauttaa aina saman tuloksen, jos siihen syötetään samat arvot, eikä se muuta arvoja ts-ulottuvuuden ulkopuolella, mikä tekee siitä riippumattoman kaikista järjestelmän tiloista. Siksi puhdas toiminto ei voi koskaan mutatoida tietoja, tuottaa mitään sivuvaikutuksia ja voidaan helposti käyttää uudelleen. Esimerkki ei-puhtaasta funktiosta on funktio, joka tekee API-puhelun tai palauttaa arvaamattoman tuloksen.
yksinkertainen epäpuhdas funktio:
var tip = 0;function calculateTip( mealTotal ) {
tip = 0.15 * mealTotal;
}calculateTip( 150 )
console.log(tip)
yksinkertainen puhdas funktio:
function isPure(x,y) {
return x * y
}console.log(isPure(3,5));
puhdas funktio palauttaa tarkan tuloksen joka kerta, eikä se mutatoi mitään sen ulkopuolella olevaa dataa. Tärkeää kiinnittää huomiota on, että puhdas toiminto on pysyttävä pois mutatoivien tietojen mitään, joten ole varovainen, kun valitset, mitä menetelmiä käyttää sisällä puhdas toimintoja. Esimerkiksi, jos haluat yhdistää kaksi matriiseja sisällä toiminto, kuten yksi tyypillisesti tehdä React reducer, välttää käyttämällä Array.prototyyppi.push () – menetelmä. Sen sijaan haluat käyttää Array.prototyyppi.concat (), joka säilyttää vanhojen järjestelmien tilan ja palauttaa uuden käyttöönsä.
korkeamman kertaluvun funktiot:
Javascriptissä funktioita käsitellään objekteina, joten voimme siirtää funktioita ympäriinsä kuten mitä tahansa muuta arvoa. Korkeamman kertaluvun funktio on yksinkertaisesti funktio, joka toimii muilla funktioilla. Ne voivat ottaa funktion syötteenä tai palauttaa sen ulostulona. Näemme yksinkertaisen esimerkin seuraavassa mielenosoituksessa.
anonyymit funktiot:
anonyymit funktiot ovat erittäin hyödyllisiä, kun meidän on määriteltävä ad hoc-logiikka tarpeen mukaan. Nimensä mukaisesti nimetön funktio on nimetön ja esiintyy useimmiten argumenttina jollekin funktiolle nimetyn funktion korvaajana, muuttujalle osoitettuna funktiona tai palautettuna funktiona korkeamman kertaluvun funktiossa. Sen juuret ovat vahvasti Lambda-laskennassa ja se on erittäin tärkeä kaikille funktionaalisille ohjelmointikielille.
muuttujalle annettu anonyymi funktio. Helppo kiertää ja vedota tarvittaessa.
const myVar = function(){console.log(‘Anonymous function here!’)}myVar()
anonyymi funktio argumenttina
setInterval(function(){console.log(new Date().getTime())}, 1000);
anonyymit funktiot korkeamman kertaluvun funktion sisällä
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’)
rekursio
rekursio on tunnettu funktionaalinen ohjelmointitekniikka. Rekursiivinen funktio on yksinkertaisesti funktio, joka kutsuu itseään, ja toimii siten silmukkana, joka suorittaa samaa koodia useita kertoja. Se tulee yksi varoitus vaikka, yksi on oltava varovainen välttää ääretön rekursiot. Siksi tarvitaan perustapaus, joka kertoo, milloin pitää lopettaa. Rekursiiviset funktiot tai algoritmit voidaan toteuttaa sekä rekursiolla että silmukoilla, mutta on parempi käyttää rekursiota. Alla on hyvin tiedossa algoritmi factorizing numero sekä käyttämällä rekursio ja silmukka.
rekursiivinen funktio
function factorialize(num){
if (num === 0 || num === 1){return 1;}
return (num * factorialize(num — 1));
}var result = factorialize(14);console.log(result);
rekursio silmukan avulla
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));
olemme käsitelleet muutamia funktionaalisen koodin kirjoittamisen olennaisia aineksia. Aina funktionaalista koodia ei ole mahdollista kirjoittaa sovellukseen, mutta hyödyt ovat suuret, kun niitä käytetään mahdollisimman paljon. Funktionaalinen ohjelmointi vaikuttaa vahvasti Angularyn ja React-ohjelman kaltaisiin kehyksiin, ja Reduxin ja Lodashin kaltaiset kirjastot auttavat meitä hyödyntämään sen etuja, joten on ehdottomasti iso etu alkaa ajatella FP-tavalla.
resursseja oppia lisää? Tässä on hienoja artikkeleita ja resursseja jatko-oppimiseen.
- miksi opetella funktionaalista ohjelmointia Javascriptissä? Eric Elliot
- Eloquent JavaScript by Marijn Haverbeke
- so you want to be a Functional Programmer by Charles Scalfani
i really hope this was helpful and in the next article we ’ ll dive a little deep and unpack entistäkin mielenkiintoisempia ja hyödyllisiä työkaluja, kuten JavaScript methods, partial application, currying, argument binding and more.
voit vapaasti taputtaa, jakaa, kritisoida tai jakaa ajatuksia aiheesta!