Java 8 je razvijalce Java predstavil funkcionalnemu programiranju z lambda izrazi. Ta izdaja Java je razvijalce učinkovito obvestila, da ni več dovolj, da o programiranju Java razmišljajo samo z nujne, objektno usmerjene perspektive. Razvijalec Java mora biti sposoben razmišljati in kodirati z uporabo deklarativne funkcionalne paradigme.
Ta vadnica predstavlja osnove funkcionalnega programiranja. Začel bom s terminologijo, nato pa se bomo poglobili v koncepte funkcionalnega programiranja. Na koncu vam predstavim pet tehnik funkcionalnega programiranja. Primeri kod v teh razdelkih vas bodo začeli s čistimi funkcijami, funkcijami višjega reda, leno oceno, zapiranji in curryjem.
Funkcionalno programiranje je v porastu
Inštitut za inženirje elektrotehnike in elektronike (IEEE) je v svojih 25 najboljših programskih jezikov za leto 2018 vključil funkcionalne programske jezike, Google Trends pa trenutno funkcionalno programiranje uvršča med bolj priljubljene od objektno usmerjenega programiranja.
Jasno je, da funkcionalnega programiranja ni mogoče prezreti, toda zakaj postaja vse bolj priljubljeno? Med drugim funkcionalno programiranje olajša preverjanje pravilnosti programa. Poenostavlja tudi ustvarjanje sočasnih programov. Sočasnost (ali vzporedna obdelava) je ključnega pomena za izboljšanje učinkovitosti aplikacije.
prenos Prenesite kodo Prenesite izvorno kodo, na primer programe v tej vadnici. Ustvaril Jeff Friesen za JavaWorld.Kaj je funkcionalno programiranje?
Računalniki običajno izvajajo arhitekturo Von Neumann, ki je široko uporabljena računalniška arhitektura, ki temelji na opisu matematika in fizika Johna von Neumanna (in drugih) iz leta 1945. Ta arhitektura je pristranska nujno programiranje, ki je programska paradigma, ki s stavki spreminja stanje programa. C, C ++ in Java so vsi nujni programski jeziki.
Leta 1977 je ugledni računalničar John Backus (znan po svojem delu na FORTRANU) imel predavanje z naslovom "Ali je mogoče programiranje osvoboditi von Neumannovega sloga?" Backus je zatrdil, da so arhitektura Von Neumanna in z njo povezani imperativni jeziki v bistvu pomanjkljivi, in kot rešitev predstavil programski jezik na funkcionalni ravni (FP).
Pojasnitev Backusa
Ker je bilo predavanje Backusa predstavljeno že pred nekaj desetletji, bi bilo mogoče nekatere njegove ideje težko dojeti. Bloger Tomasz Jaskuła dodaja jasnost in opombe v svoji objavi v spletnem dnevniku od januarja 2018.
Koncepti in terminologija funkcionalnega programiranja
Funkcionalno programiranje je programski slog, v katerem so izračuni kodificirani kot funkcije funkcionalnega programiranja. To so matematični konstrukti, podobni funkciji (npr. Lambda funkcije), ki se ovrednotijo v kontekstih izraza.
Funkcionalni programski jeziki so izjavo, kar pomeni, da je logika izračuna izražena brez opisa njegovega krmilnega toka. V deklarativnem programiranju ni izjav. Namesto tega programerji z izrazi sporočajo računalniku, kaj je treba storiti, ne pa tudi, kako izpolniti nalogo. Če poznate SQL ali regularne izraze, imate nekaj izkušenj z izjavnim slogom; oba uporabljata izraze, da opišeta, kaj je treba storiti, namesto da z izjavami opišeta, kako to storiti.
A računanje v funkcionalnem programiranju je opisan s funkcijami, ki se vrednotijo v kontekstih izraza. Te funkcije niso enake funkcijam, ki se uporabljajo v nujnem programiranju, na primer metoda Java, ki vrne vrednost. Namesto tega funkcionalno programiranje Funkcija je podobna matematični funkciji, ki daje rezultat, ki je običajno odvisen samo od njegovih argumentov. Vsakič, ko funkcijo funkcionalnega programiranja pokličete z enakimi argumenti, dosežete enak rezultat. Izkazale naj bi se funkcije v funkcionalnem programiranju referenčna preglednost. To pomeni, da lahko funkcijski klic nadomestite z izhajajočo vrednostjo, ne da bi spremenili pomen izračuna.
Funkcionalno programiranje je naklonjeno nespremenljivost, kar pomeni, da se država ne more spremeniti. To običajno ne velja za imperativno programiranje, kjer je imperativna funkcija lahko povezana s stanjem (kot je spremenljivka primerka Java). Klic te funkcije ob različnih časih z enakimi argumenti lahko povzroči različne vrnjene vrednosti, ker je v tem primeru stanje spremenljiv, kar pomeni, da se spremeni.
Neželeni učinki v imperativnem in funkcionalnem programiranju
Spremembe držav so stranski učinek nujnega programiranja, ki preprečuje referenčno preglednost. Obstaja veliko drugih neželenih učinkov, ki jih je vredno vedeti, še posebej, ko ocenjujete, ali v svojih programih uporabite imperativni ali funkcionalni slog.
Eden najpogostejših stranskih učinkov pri imperativnem programiranju je, ko stavek o dodelitvi spremeni spremenljivko tako, da spremeni njeno shranjeno vrednost. Funkcije v funkcionalnem programiranju ne podpirajo dodeljevanja spremenljivk. Ker se začetna vrednost spremenljivke nikoli ne spremeni, funkcionalno programiranje odpravi ta stranski učinek.
Drug pogost neželeni učinek se zgodi pri spreminjanju vedenja imperativne funkcije na podlagi vržene izjeme, ki je opazna interakcija s klicateljem. Za več informacij glejte razpravo Stack Overflow, "Zakaj je dvig izjeme stranski učinek?"
Tretji pogosti neželeni učinek se pojavi, ko V / I operacija vnese besedilo, ki ga ni mogoče prebrati, ali izpiše besedilo, ki ga ni mogoče nenapisati. Glejte razpravo o izmenjavi skladb "Kako lahko IO povzroči neželene učinke pri funkcionalnem programiranju?" če želite izvedeti več o tem neželenem učinku.
Odprava neželenih učinkov olajša razumevanje in napovedovanje računskega vedenja. Pomaga tudi, da je koda primernejša za vzporedno obdelavo, kar pogosto izboljša delovanje aplikacije. Čeprav so v funkcionalnem programiranju neželeni učinki, jih je na splošno manj kot v nujnem programiranju. Uporaba funkcionalnega programiranja vam lahko pomaga pri pisanju kode, ki je lažje razumljiva, vzdrževana in preizkušena ter je tudi bolj uporabna.
Izvori (in začetniki) funkcionalnega programiranja
Funkcionalno programiranje izvira iz lambda računa, ki ga je uvedel Alonzo Church. Drugi izvor je kombinacijska logika, ki jo je uvedel Moses Schönfinkel, kasneje pa jo je razvil Haskell Curry.
Predmetno usmerjeno v primerjavi s funkcionalnim programiranjem
Ustvaril sem aplikacijo Java, ki je v nasprotju z imperativ, objektno usmerjen in izjavni, funkcionalni programski pristopi k pisanju kode. Preučite spodnjo kodo in nato bom opozoril na razlike med obema primeroma.
Seznam 1. Zaposleni.java
uvoz java.util.ArrayList; uvoz java.util.List; javni razred Zaposleni {static class Zaposleni {private String name; zasebna int starost; Zaposleni (Ime niza, int starost) {this.name = name; this.age = starost; } int getAge () {vrnitev starosti; } @Override public String toString () {return ime + ":" + starost; }} public static void main (String [] args) {Seznam zaposlenih = nov ArrayList (); zaposleni.add (nov zaposleni ("John Doe", 63)); zaposleni.add (novi zaposleni ("Sally Smith", 29)); zaposleni.add (nov zaposleni ("Bob Jone", 36)); zaposleni.add (novi zaposleni ("Margaret Foster", 53)); printE Employee1 (zaposleni, 50); System.out.println (); printE Employee2 (zaposleni, 50); } javna statična void printE Employee1 (Seznam zaposlenih, int starost) {za (Employee emp: zaposlenih) if (emp.getAge () <age) System.out.println (emp); } javna statična void printE Employee2 (Seznam zaposlenih, int age) {zaposleni.stream () .filter (emp -> emp.age System.out.println (emp)); }}
Seznam 1 razkriva Zaposleni
program, ki ustvari nekaj Zaposleni
predmeti, nato natisne seznam vseh zaposlenih, mlajših od 50 let. Ta koda prikazuje objektno usmerjeni in funkcionalni slog programiranja.
The printE Employee1 ()
metoda razkriva nujni pristop, usmerjen k izjavam. Kot je določeno, ta metoda ponovi seznam zaposlenih, primerja starost vsakega zaposlenega z vrednostjo argumenta in (če je starost manjša od argumenta), natisne podatke o zaposlenem.
The printE Employee2 ()
metoda razkriva deklarativni, izrazno usmerjen pristop, v tem primeru implementiran z API-jem Streams. Namesto da bi natančno določil, kako tiskati zaposlene (korak za korakom), izraz določa želeni rezultat in podrobnosti o tem prepusti Javi. Pomislite filter ()
kot funkcionalni ekvivalent če
izjavo in za vsakogar()
kot funkcionalno enakovreden za
izjavo.
Seznam 1 lahko sestavite na naslednji način:
javac Zaposleni.java
Z naslednjim ukazom zaženite nastalo aplikacijo:
java Zaposleni
Izhod bi moral izgledati nekako takole:
Sally Smith: 29 Bob Jone: 36 Sally Smith: 29 Bob Jone: 36
Primeri funkcionalnega programiranja
V naslednjih razdelkih bomo raziskali pet temeljnih tehnik, ki se uporabljajo pri funkcionalnem programiranju: čiste funkcije, funkcije višjega reda, leno vrednotenje, zapiranje in curry. Primeri v tem razdelku so kodirani v JavaScript, ker nam bo njegova preprostost glede na Javo omogočila, da se osredotočimo na tehnike. V 2. delu bomo te iste tehnike ponovno uporabili z uporabo kode Java.
Seznam 2 predstavlja izvorno kodo RunScript
, aplikacija Java, ki uporablja Java-jev skriptni API za lažje izvajanje kode JavaScript. RunScript
bo osnovni program za vse prihodnje primere.
Seznam 2. RunScript.java
uvoz java.io.FileReader; import java.io.IOException; uvoz javax.script.ScriptEngine; uvoz javax.script.ScriptEngineManager; uvoz javax.script.ScriptException; uvozi statični java.lang.System. *; javni razred RunScript {public static void main (String [] args) {if (args.length! = 1) {err.println ("uporaba: skript java RunScript"); vrnitev; } ScriptEngineManager manager = nov ScriptEngineManager (); ScriptEngine engine = manager.getEngineByName ("nashorn"); poskusite {engine.eval (nov FileReader (args [0])); } catch (ScriptException se) {err.println (se.getMessage ()); } ulov (IOException ioe) {err.println (ioe.getMessage ()); }}}
The glavni ()
metoda v tem primeru najprej preveri, ali je podan en argument ukazne vrstice (ime datoteke skripta). V nasprotnem primeru prikaže informacije o uporabi in ukine aplikacijo.
Ob predpostavki prisotnosti tega argumenta, glavni ()
ustvari javax.script.ScriptEngineManager
razred. ScriptEngineManager
je vstopna točka v Java's Scripting API.
Nato, ScriptEngineManager
predmeta ScriptEngine getEngineByName (niz shortName)
metoda se pokliče za pridobitev skriptnega mehanizma, ki ustreza želenemu kratko ime
vrednost. Java 10 podpira motor skript Nashorn, ki ga dobimo s predajo "nashorn"
do getEngineByName ()
. Vrnjeni predmet razreda izvaja javax.script.ScriptEngine
vmesnik.
ScriptEngine
izjavlja več eval ()
metode za ocenjevanje skripta. glavni ()
prikliče Predmet eval (čitalnik bralnika)
metoda za branje skripta iz java.io.FileReader
argument objekta in (ob predpostavki, da java.io.IOException
ni vržen) nato ocenite skript. Ta metoda vrne katero koli vrnjeno vrednost skripta, ki jo prezrem. Tudi ta metoda vrže javax.script.ScriptException
ko pride do napake v skriptu.
Sestavite seznam 2, kot sledi:
javac RunScript.java
Po tem, ko predstavim prvi skript, vam pokažem, kako zagnati to aplikacijo.
Funkcionalno programiranje s čistimi funkcijami
A čista funkcija je funkcija funkcionalnega programiranja, ki je odvisna samo od vhodnih argumentov in brez zunanjega stanja. An nečista funkcija je funkcija funkcionalnega programiranja, ki krši katero koli od teh zahtev. Ker čiste funkcije nimajo interakcije z zunanjim svetom (razen klica drugih čistih funkcij), čista funkcija vedno vrne enak rezultat za iste argumente. Čiste funkcije tudi nimajo opaznih stranskih učinkov.
Ali lahko čista funkcija izvaja V / I?
Če je V / I stranski učinek, ali lahko čista funkcija izvaja V / I? Odgovor je pritrdilen. Haskell za reševanje te težave uporablja monade. Glejte "Čiste funkcije in V / I" za več informacij o čistih funkcijah in V / I.
Čiste funkcije v primerjavi z nečistimi funkcijami
JavaScript v seznamu 3 nasprotuje nečisti izračunaj bobonus ()
funkcijo s čisto izračunajbonus2 ()
funkcijo.
Seznam 3. Primerjava čistih in nečistih funkcij (script1.js
)
// izračun nečistega bonusa var limit = 100; funkcija izračunajbonus (numSales) {return (numSales> limit)? 0,10 * numSales: 0} print (izračunajbonus (174)) // čista funkcija za izračun bonusa izračunaj bobonus2 (število prodaj) {return (numSales> 100)? 0,10 * numSales: 0} tiskanje (izračunaj boni2 (174))
izračunaj bobonus ()
je nečist, ker ima dostop do zunanjega meja
spremenljivka. V nasprotju, izračunajbonus2 ()
je čista, ker spoštuje obe zahtevi po čistosti. Teči script1.js
kot sledi:
java RunScript script1.js
Tukaj je rezultat, ki ga morate upoštevati:
17.400000000000002 17.400000000000002
Recimo izračunajbonus2 ()
je bila predelana na vrne izračunbonusa (numSales)
. Bi izračunajbonus2 ()
še vedno čist? Odgovor je ne: ko čista funkcija prikliče nečisto funkcijo, "čista funkcija" postane nečista.
Če med čistimi funkcijami ni odvisnosti od podatkov, jih je mogoče ovrednotiti v poljubnem vrstnem redu, ne da bi to vplivalo na rezultat, zaradi česar so primerne za vzporedno izvajanje. To je ena od prednosti funkcionalnega programiranja.
Več o nečistih funkcijah
Ni nujno, da so vse funkcije funkcionalnega programiranja čiste. Kot pojasnjuje Funkcionalno programiranje: Čiste funkcije, je mogoče (in včasih tudi zaželeno) "ločiti čisto, funkcionalno jedro aplikacije, ki temelji na vrednosti, od zunanje nujne lupine."
Funkcionalno programiranje s funkcijami višjega reda
A funkcija višjega reda je matematična funkcija, ki prejme funkcije kot argumente, vrne funkcijo klicatelju ali oboje. En primer je diferencialni operater računa, d / dx, ki vrne izpeljanko funkcije f.
Prvorazredne funkcije so prvovrstni državljani
Z matematičnim konceptom funkcije višjega reda je tesno povezan prvovrstna funkcija, ki je funkcija funkcionalnega programiranja, ki druge funkcije funkcionalnega programiranja vzame kot argumente in / ali vrne funkcijo funkcijskega programiranja. Prvovrstne funkcije so državljani prvega razreda ker se lahko pojavijo kjer koli lahko druge prvovrstne programske entitete (npr. številke), vključno z dodeljevanjem spremenljivki ali posredovanjem kot argument funkciji ali vrnitvijo iz funkcije.
JavaScript v seznamu 4 prikazuje posredovanje anonimnih primerjalnih funkcij prvovrstni funkciji razvrščanja.
Seznam 4. Prenos anonimnih primerjalnih funkcij (script2.js
)
razvrstitev funkcije (a, cmp) {for (var pass = 0; pass mimo; i--) if (cmp (a [i], a [pass]) <0) {var temp = a [i] a [i] = a [pass] a [pass] = temp}} var a = [ 22, 91, 3, 45, 64, 67, -1] sort (a, function (i, j) {return i - j;}) a.forEach (function (entry) {print (entry)}) print ( '\ n') sort (a, function (i, j) {return j - i;}) a.forEach (function (entry) {print (entry)}) print ('\ n') a = ["X "," E "," Q "," A "," P "] sort (a, function (i, j) {return i j; }) a.forEach (function (entry) {print (entry)}) print ('\ n') sort (a, function (i, j) {return i> j? -1: i <j;}) a .forEach (funkcija (vnos) {tisk (vnos)})
V tem primeru začetnica razvrsti ()
klic prejme matriko kot prvi argument, čemur sledi anonimna funkcija primerjave. Ko se pokliče, se anonimna funkcija primerjave izvede vrnitev i - j;
da dosežemo naraščajočo sorto. Z vzvratno vožnjo jaz
in j
, druga primerjalna funkcija doseže padajočo sortiranje. Tretji in četrti razvrsti ()
klici prejmejo anonimne funkcije primerjave, ki se nekoliko razlikujejo, da se primerjajo vrednosti nizov.
Zaženite script2.js
primer, kot sledi:
java RunScript script2.js
Tu je pričakovana proizvodnja:
-1 3 22 45 64 67 91 91 67 64 45 22 3 -1 A E P Q X X Q P E A
Filter in zemljevid
Funkcionalni programski jeziki običajno ponujajo več uporabnih funkcij višjega reda. Dva pogosta primera sta filter in zemljevid.
- A filter obdeluje seznam v nekem vrstnem redu, da ustvari nov seznam, ki vsebuje natanko tiste elemente prvotnega seznama, za katere dani predikat (misli na logični izraz) vrne true.
- A zemljevid uporabi dano funkcijo za vsak element seznama in vrne seznam rezultatov v istem vrstnem redu.
JavaScript podpira funkcijo filtriranja in preslikave prek filter ()
in zemljevid()
funkcije višjega reda. Seznam 5 prikazuje te funkcije za filtriranje lihih števil in preslikavo številk na njihove kocke.
Seznam 5. Filtriranje in preslikava (script3.js
)
print ([1, 2, 3, 4, 5, 6] .filter (function (num) {return num% 2 == 0})) print ('\ n') print ([3, 13, 22]. zemljevid (funkcija (številka) {vrni številko * 3}))
Zaženite script3.js
primer, kot sledi:
java RunScript script3.js
Upoštevati morate naslednje rezultate:
2,4,6 9,39,66
Zmanjšajte
Druga pogosta funkcija višjega reda je zmanjšati, ki je bolj znana kot krat. Ta funkcija seznam zmanjša na eno vrednost.
Seznam 6 uporablja JavaScript zmanjšanje ()
funkcija višjega reda za zmanjšanje niza števil na eno število, ki ga nato delimo z dolžino polja, da dobimo povprečje.
Seznam 6. Zmanjšanje nabora števil na eno številko (script4.js
)
var numbers = [22, 30, 43] print (numbers.reduce (function (acc, curval) {return acc + curval}) / numbers.length)
Zaženite skript seznama 6 (v script4.js
) kot sledi:
java RunScript script4.js
Upoštevati morate naslednje rezultate:
31.666666666666668
Morda mislite, da filtriranje, preslikava in zmanjševanje funkcij višjega reda odpravlja potrebo po if-else in različnih cikličnih izjavah, in imeli bi prav. Njihove notranje izvedbe skrbijo za odločitve in ponovitve.
Funkcija višjega reda uporablja rekurzijo za dosego ponovitve. Rekurzivna funkcija se prikliče, kar omogoča ponovitev operacije, dokler ne doseže a osnovni primer. Rekurzijo lahko izkoristite tudi za ponovitev v svoji funkcionalni kodi.
Funkcionalno programiranje z leno oceno
Druga pomembna funkcija funkcionalnega programiranja je leno vrednotenje (poznan tudi kot nestrogo vrednotenje), kar je čim daljši odlog vrednotenja izraza. Leno vrednotenje ponuja več prednosti, med katerimi sta ti dve:
- Dragi (časovni) izračuni se lahko odložijo, dokler niso nujno potrebni.
- Možne so neomejene zbirke. Dostavljali bodo elemente, dokler bodo od njih zahtevali.
Leno vrednotenje je sestavni del Haskella. Ne bo izračunal ničesar (vključno z argumenti funkcije pred klicem funkcije), razen če je to nujno potrebno.
Java Streams API izkoristi lenobno ocenjevanje. Vmesne operacije toka (npr. filter ()
) so vedno leni; do terminala ne naredijo ničesar (npr. za vsakogar()
) se izvede.
Čeprav je lenobno vrednotenje pomemben del funkcionalnih jezikov, celo številni nujni jeziki nudijo vgrajeno podporo nekaterim oblikam lenobe. Na primer, večina programskih jezikov podpira vrednotenje kratkega stika v kontekstu logičnih operatorjev AND in OR. Ti operaterji so leni in nočejo oceniti svojih desnih operandov, kadar je levi operand false (AND) ali true (OR).
Seznam 7 je primer lenega ocenjevanja v skriptu JavaScript.
Seznam 7. Leno vrednotenje v JavaScript (script5.js
)
var a = false && dearFunction ("1") var b = true && dearFunction ("2") var c = false || dearFunction ("3") var d = true || funkcija dragoFunction ("4") dragoFunction (id) {print ("dragoFunction (), poklicano z" + id)}
Zaženite kodo v script5.js
kot sledi:
java RunScript script5.js
Upoštevati morate naslednje rezultate:
dragoFunction (), poklicano z 2 dragoFunction (), poklicano z 3
Leno vrednotenje se pogosto kombinira z zapisovanjem, optimizacijsko tehniko, ki se uporablja predvsem za pospešitev računalniških programov s shranjevanjem rezultatov dragih klicev funkcij in vrnitvijo predpomnjenega rezultata, ko se isti vhodi ponovijo.
Ker lenobno vrednotenje ne deluje s stranskimi učinki (kot je koda, ki ustvarja izjeme in V / I), se v glavnem uporabljajo nujni jeziki nestrpno vrednotenje (poznan tudi kot strogo vrednotenje), kjer se izraz izračuna takoj, ko je vezan na spremenljivko.
Več o leni ocenjevanju in spominjanju
Iskanje v Googlu bo razkrilo veliko uporabnih razprav o lenobnem vrednotenju z memoizacijo ali brez nje. En primer je "Optimizacija JavaScript-a s funkcionalnim programiranjem."
Funkcionalno programiranje z zapirali
Prvovrstne funkcije so povezane s konceptom a zaključek, ki je trajen obseg, ki zadrži lokalne spremenljivke tudi potem, ko je izvajanje kode zapustilo blok, v katerem so bile definirane lokalne spremenljivke.
Obrtne zapore
Operativno a zaključek je zapis, ki shranjuje funkcijo in njeno okolje. Okolje preslika vsako brezplačno spremenljivko funkcije (spremenljivke, ki se uporabljajo lokalno, vendar so definirane v obsegu, ki ga zajema) z vrednostjo ali referenco, na katero je bilo ime spremenljivke vezano, ko je bilo ustvarjeno zaprtje. Funkciji omogoča dostop do teh zajetih spremenljivk prek zapiralnih kopij njihovih vrednosti ali sklicev, tudi če se funkcija prikliče zunaj njihovega obsega.
Za lažjo razjasnitev tega koncepta je v seznamu 8 predstavljen skript JavaScript, ki uvaja preprosto zaprtje. Scenarij temelji na tukaj predstavljenem primeru.
Seznam 8. Preprosto zaprtje (script6.js
)
funkcija add (x) {funkcija delnoDodaj (y) {vrni y + x} vrni delnoAdd} var add10 = dodaj (10) var add20 = dodaj (20) print (add10 (5)) print (add20 (5))
Seznam 8 definira prvovrstno funkcijo z imenom dodaj ()
s parametrom x
in ugnezdena funkcija delnoDodaj ()
. Vgnezdena funkcija delnoDodaj ()
ima dostop do x
Ker x
je v dodaj ()
je leksikalni obseg. Funkcija dodaj ()
vrne zaprtje, ki vsebuje sklic na delnoDodaj ()
in kopija okolja okoli dodaj ()
, v kateri x
ima vrednost, ki ji je dodeljena v določenem klicu dodaj ()
.
Ker dodaj ()
vrne vrednost vrste funkcije, spremenljivke dodaj10
in add20
imajo tudi vrsto funkcije. The add10 (5)
priklic vrne 15
ker klic dodeli 5
do parametra y
v klicu delnoDodaj ()
, z uporabo shranjenega okolja za delnoDodaj ()
kje x
je 10
. The add20 (5)
priklic vrne 25
ker čeprav tudi dodeljuje 5
do y
v klicu delnoDodaj ()
, zdaj uporablja drugo shranjeno okolje za delnoDodaj ()
kje x
je 20
. Tako, medtem ko add10 ()
in add20 ()
uporabite isto funkcijo delnoDodaj ()
, povezana okolja se razlikujejo in sklicevanje na zapore bo obvezujoče x
na dve različni vrednosti v dveh klicih, pri čemer se funkcija oceni na dva različna rezultata.
Zaženite skript seznama 8 (v script6.js
) kot sledi:
java RunScript script6.js
Upoštevati morate naslednje rezultate:
15 25
Funkcionalno programiranje z curryjem
Curry je način, kako ovrednotiti funkcijo več argumentov v oceno enakovrednega zaporedja funkcij z enim argumentom. Na primer, funkcija vzame dva argumenta: x in y. Kaririranje funkcijo spremeni v samo fotografiranje x in vrnitev funkcije, ki traja samo y. Kaririranje je povezano z delno aplikacijo, vendar ni isto kot delna uporaba, to je postopek določanja številnih argumentov v funkciji, ki ustvarja drugo funkcijo manjše stopnje.
Seznam 9 predstavlja JavaScript skript, ki prikazuje currying.
Seznam 9. Currying v JavaScript (script7.js
)
funkcija pomnoži (x, y) {return x * y} funkcija curried_multiply (x) {return function (y) {return x * y}} print (multiply (6, 7)) print (curried_multiply (6) (7)) var mul_by_4 = curried_multiply (4) print (mul_by_4 (2))
V scenariju je predstavljen dvo-argument pomnoži ()
funkcija, ki ji sledi prvovrstna curried_multiply ()
funkcija, ki prejme argument multiplicand x
in vrne zaprtje, ki vsebuje sklic na anonimno funkcijo (ki prejme argument množitelja y
) in kopijo okolja okoli curried_multiply ()
, v kateri x
ima vrednost, ki ji je dodeljena v klicu curried_multiply ()
.
Preostali del skripta najprej pokliče pomnoži ()
z dvema argumentoma in natisne rezultat. Nato se prikliče curried_multiply ()
na dva načina:
curried_multiply (6) (7)
Rezultati vcurried_multiply (6)
izvršitev prva. Vrnjeno zapiranje izvede anonimno funkcijo s shranjenim zapiranjemx
vrednost6
pomnoženo z7
.var mul_by_4 = curried_multiply (4)
izvršicurried_multiply (4)
in dodeli zaprtjemul_by_4
.mul_by_4 (2)
izvede anonimno funkcijo z zaporo4
vrednost in posredovani argument2
.
Zaženite skript seznama 9 (v script7.js
) kot sledi:
java RunScript script7.js
Upoštevati morate naslednje rezultate:
42 42 8
Zakaj uporabljati currying?
Hugh Jackson v svojem zapisu v blogu "Zakaj curry pomaga" ugotavlja, da "je mogoče majhne koščke z lahkoto konfigurirati in ponovno uporabiti, brez nereda". Quora: "Kakšne so prednosti curryja pri funkcionalnem programiranju?" opisuje currying kot "poceni obliko vbrizgavanja odvisnosti", ki olajša postopek preslikave / filtriranja / zlaganja (in na splošno funkcij višjega reda). Ta Vprašanja tudi ugotavljajo, da curry "pomaga ustvariti abstraktne funkcije."
V zaključku
V tej vadnici ste se naučili nekaj osnov funkcionalnega programiranja. Z primeri v JavaScriptu smo preučevali pet temeljnih tehnik funkcionalnega programiranja, ki jih bomo nadalje raziskovali z uporabo kode Java v 2. delu. Poleg ogleda funkcionalnosti programskega programiranja Java 8 vam bo druga polovica te vadnice pomagala začeti razmišljati funkcionalno, s pretvorbo primera objektno usmerjene kode Java v njen funkcionalni ekvivalent.
Preberite več o funkcionalnem programiranju
Knjiga Uvod v funkcionalno programiranje (Richard Bird in Philip Wadler, Prentice Hall International Series in Computing Science, 1992) mi je bila v pomoč pri učenju osnov funkcionalnega programiranja.
To zgodbo "Funkcionalno programiranje za razvijalce Java, 1. del" je prvotno objavil JavaWorld.