Programmēšana

Funkcionālā programmēšana Java izstrādātājiem, 1. daļa

Java 8 iepazīstināja Java izstrādātājus ar funkcionālu programmēšanu ar lambda izteiksmēm. Šis Java izlaidums efektīvi paziņoja izstrādātājiem, ka vairs nav pietiekami domāt par Java programmēšanu tikai no obligātās, objektorientētās perspektīvas. Java izstrādātājam arī jāspēj domāt un kodēt, izmantojot deklaratīvo funkcionālo paradigmu.

Šajā apmācībā ir sniegti funkcionālās programmēšanas pamati. Es sākšu ar terminoloģiju, tad mēs iedziļināsimies funkcionālās programmēšanas koncepcijās. Noslēgumā es jūs iepazīstināšu ar piecām funkcionālās programmēšanas metodēm. Kodu piemēri šajās sadaļās ļaus jums sākt ar tīrām funkcijām, augstākas kārtas funkcijām, slinku novērtēšanu, aizvēršanu un kariju.

Funkcionālā programmēšana pieaug

Elektrisko un elektronisko inženieru institūts (IEEE) iekļauj funkcionālās programmēšanas valodas savās 2018. gada 25 populārākajās programmēšanas valodās, un Google Trends pašlaik funkcionālo programmēšanu ierindo kā populārāku nekā objektorientētu programmēšanu.

Skaidrs, ka funkcionālo programmēšanu nevar ignorēt, bet kāpēc tā kļūst arvien populārāka? Cita starpā funkcionālā programmēšana atvieglo programmas pareizības pārbaudi. Tas arī vienkāršo vienlaicīgu programmu izveidi. Vienlaicīgums (vai paralēla apstrāde) ir būtiska, lai uzlabotu lietojumprogrammas veiktspēju.

lejupielādēt Iegūt kodu Lejupielādējiet šajā apmācībā avota kodu, piemēram, lietojumprogrammām. Izveidoja Jeff Friesen JavaWorld.

Kas ir funkcionālā programmēšana?

Datori parasti ievieš Von Neumann arhitektūru, kas ir plaši izmantota datoru arhitektūra, kuras pamatā ir matemātiķa un fiziķa John von Neumann (un citu) 1945. gada apraksts. Šī arhitektūra ir tendencioza pret obligāta programmēšana, kas ir programmēšanas paradigma, kas izmanto paziņojumus, lai mainītu programmas stāvokli. C, C ++ un Java ir visas obligātās programmēšanas valodas.

1977. gadā izcilais datorzinātnieks Džons Bekuss (ievērojams ar darbu pie FORTRAN) lasīja lekciju ar nosaukumu "Vai programmēšanu var atbrīvot no fon Neimaņa stila?" Bekuss apgalvoja, ka Fon Neimaņa arhitektūra un ar to saistītās imperatīvās valodas ir būtībā kļūdainas, un kā risinājumu piedāvāja funkcionālā līmeņa programmēšanas valodu (FP).

Noskaidrot Backusu

Tā kā Backus lekcija tika prezentēta pirms vairākām desmitgadēm, dažas no tās idejām varētu būt grūti saprotamas. Emuāra autors Tomasz Jaskuła savā 2018. gada janvāra emuāra ziņā papildina skaidrību un zemsvītras piezīmes.

Funkcionālās programmēšanas koncepcijas un terminoloģija

Funkcionāla programmēšana ir programmēšanas stils, kurā aprēķini tiek kodēti kā funkcionālās programmēšanas funkcijas. Tie ir matemātiskām funkcijām līdzīgi konstrukcijas (piemēram, lambda funkcijas), kuras tiek vērtētas izteiksmes kontekstos.

Funkcionālās programmēšanas valodas ir deklaratīvs, kas nozīmē, ka aprēķina loģika tiek izteikta, neaprakstot tā vadības plūsmu. Deklaratīvajā programmēšanā nav paziņojumu. Tā vietā programmētāji izmanto izteicienus, lai informētu datoru, kas jādara, bet ne to, kā izpildīt uzdevumu. Ja jums ir zināmas SQL vai regulārās izteiksmes, tad jums ir zināma pieredze ar deklaratīvo stilu; abi izmanto izteicienus, lai aprakstītu, kas jādara, nevis izmanto apgalvojumus, lai aprakstītu, kā to izdarīt.

A aprēķins funkcionālajā programmēšanā tiek aprakstīts ar funkcijām, kuras tiek vērtētas izteiksmes kontekstos. Šīs funkcijas nav tās pašas funkcijas, kuras tiek izmantotas obligātajā programmēšanā, piemēram, Java metode, kas atgriež vērtību. Tā vietā a funkcionāla programmēšana funkcija ir kā matemātiska funkcija, kas rada rezultātu, kas parasti ir atkarīgs tikai no tā argumentiem. Katru reizi, kad funkcionālā programmēšanas funkcija tiek izsaukta ar vieniem un tiem pašiem argumentiem, tiek sasniegts viens un tas pats rezultāts. Tiek teikts, ka funkcijas funkcionālajā programmēšanā demonstrē atsauces pārredzamība. Tas nozīmē, ka jūs varat aizstāt funkcijas izsaukumu ar tā iegūto vērtību, nemainot aprēķina nozīmi.

Funkcionāla programmēšana dod priekšroku nemainīgums, kas nozīmē, ka valsts nevar mainīties. Tas parasti nenotiek obligātajā programmēšanā, kur imperatīvā funkcija var būt saistīta ar stāvokli (piemēram, Java instances mainīgo). Zvanot šai funkcijai dažādos laikos ar vieniem un tiem pašiem argumentiem, var būt atšķirīgas atgriešanās vērtības, jo šajā gadījumā stāvoklis ir maināms, kas nozīmē, ka tas mainās.

Blakusparādības obligātā un funkcionālā programmēšanā

Stāvokļa izmaiņas ir obligātas programmēšanas blakus efekts, novēršot atsauces pārredzamību. Ir daudz citu blakusparādību, par kurām vērts zināt, it īpaši, ja jūs novērtējat, vai savās programmās izmantot obligāto vai funkcionālo stilu.

Obligātās programmēšanas gadījumā viena izplatīta blakusparādība ir tad, kad piešķiršanas paziņojums mutē mainīgo, mainot tā saglabāto vērtību. Funkcionālās programmēšanas funkcijas neatbalsta mainīgos piešķīrumus. Tā kā mainīgā sākotnējā vērtība nekad nemainās, funkcionālā programmēšana novērš šo blakusparādību.

Vēl viena izplatīta blakusparādība rodas, modificējot imperatīvās funkcijas uzvedību, pamatojoties uz izmestu izņēmumu, kas ir novērojama mijiedarbība ar zvanītāju. Lai iegūtu papildinformāciju, skatiet Steka pārpildes diskusiju "Kāpēc izņēmuma izvirzīšana ir blakusparādība?"

Trešais bieži sastopamais blakus efekts rodas, ja I / O darbība ievada tekstu, kuru nevar nelasīt, vai izvada tekstu, kuru nevar nerakstīt. Skatiet Stack Exchange diskusiju "Kā IO var izraisīt blakusparādības funkcionālajā programmēšanā?" lai uzzinātu vairāk par šo blakusparādību.

Blakusparādību novēršana ievērojami atvieglo skaitļošanas uzvedības izpratni un prognozēšanu. Tas arī palīdz padarīt kodu piemērotāku paralēlajai apstrādei, kas bieži uzlabo lietojumprogrammas veiktspēju. Lai gan funkcionālajā programmēšanā ir blakusparādības, tās parasti ir mazāk nekā obligātajā programmēšanā. Funkcionālās programmēšanas izmantošana var palīdzēt rakstīt kodu, kuru ir vieglāk saprast, uzturēt un pārbaudīt, kā arī vairāk izmantot atkārtoti.

Funkcionālās programmēšanas izcelsme (un iniciatore)

Funkcionālā programmēšana radās lambda aprēķinā, kuru ieviesa Alonzo baznīca. Vēl viena izcelsme ir kombinatīvā loģika, kuru ieviesa Mozus Šēnfinkels un pēc tam izstrādāja Haskels Karijs.

Objektorientēta pret funkcionālu programmēšanu

Esmu izveidojis Java lietojumprogrammu, kas kontrastē ar imperatīvs, orientēts uz objektu un deklaratīvs, funkcionāls programmēšanas pieejas koda rakstīšanai. Izpētiet zemāk esošo kodu, un tad es norādīšu uz atšķirībām starp abiem piemēriem.

Uzskaitīšana 1. Darbinieki.java

importēt java.util.ArrayList; importēt java.util.List; publiskā klase Darbinieki {statiskā klase Darbinieks {privātais Stīgas nosaukums; privāts int vecums; Darbinieks (virknes nosaukums, int vecums) {this.name = vārds; tas.vecums = vecums; } int getAge () {atgriešanās vecums; } @Orride public String toString () {return name + ":" + age; }} public static void main (String [] argumenti) {Sarakstu darbinieki = jauns ArrayList (); darbinieki.add (jauns darbinieks ("John Doe", 63)); darbinieki.add (jauns darbinieks ("Sally Smith", 29)); darbinieki.add (jauns darbinieks ("Bob Jone", 36)); darbinieki.add (jauns darbinieks ("Margaret Foster", 53)); printEmployee1 (darbinieki, 50); System.out.println (); printEmployee2 (darbinieki, 50); } public static void printEmployee1 (Darbinieku saraksts, int vecums) {par (Employee emp: darbinieki) if (emp.getAge () <vecums) System.out.println (emp); } public static void printEmployee2 (Sarakstā esošie darbinieki, int vecums) {darbinieki.stream () .filter (emp -> emp.age System.out.println (emp)); }}

1. saraksts atklāj Darbinieki programma, kas rada dažus Darbinieks objektus, pēc tam izdrukā visu darbinieku sarakstu, kuri ir jaunāki par 50 gadiem. Šis kods parāda gan objektorientētos, gan funkcionālos programmēšanas stilus.

The printEmployee1 () metode atklāj imperatīvo, uz paziņojumiem orientēto pieeju. Kā norādīts, šī metode atkārto darbinieku sarakstu, salīdzina katra darbinieka vecumu ar argumenta vērtību un (ja vecums ir mazāks par argumentu) izdrukā darbinieka datus.

The printEmployee2 () metode atklāj deklaratīvu, uz izteiksmi orientētu pieeju, kas šajā gadījumā tiek ieviesta ar Streams API. Tā vietā, lai obligāti norādītu, kā drukāt darbiniekus (soli pa solim), izteiksme norāda vēlamo rezultātu un informāciju par to, kā to izdarīt, atstāj Java. Padomā par filtrs () kā funkcionālais ekvivalents ja paziņojums un katram() kā funkcionāli līdzvērtīgs priekš paziņojums, apgalvojums.

1. sarakstu varat apkopot šādi:

javac Employees.java

Izmantojiet šo komandu, lai palaistu iegūto lietojumprogrammu:

java Darbinieki

Rezultātam vajadzētu izskatīties apmēram šādi:

Sallija Smita: 29 Bobs Džone: 36 Sallijs Smits: 29 Bobs Džone: 36

Funkcionālie programmēšanas piemēri

Nākamajās sadaļās mēs izpētīsim piecus galvenos paņēmienus, kas tiek izmantoti funkcionālajā programmēšanā: tīras funkcijas, augstāka līmeņa funkcijas, slinks novērtējums, slēgšana un karija. Šīs sadaļas piemēri ir kodēti JavaScript valodā, jo tā vienkāršība attiecībā pret Java ļaus mums koncentrēties uz metodēm. 2. daļā mēs pārskatīsim šīs pašas metodes, izmantojot Java kodu.

2. sarakstā tiek parādīts avota kods RunScript, Java lietojumprogramma, kas izmanto Java Scripting API, lai atvieglotu JavaScript koda palaišanu. RunScript būs visu nākamo piemēru pamatprogramma.

Saraksts 2. RunScript.java

importēt java.io.FileReader; importēt java.io.IOException; importēt javax.script.ScriptEngine; importēt javax.script.ScriptEngineManager; importēt javax.script.ScriptException; importēt statisko java.lang.System. *; public class RunScript {public static void main (String [] args) {if (args.length! = 1) {err.println ("lietojums: java RunScript skripts"); atgriešanās; } ScriptEngineManager manager = jauns ScriptEngineManager (); ScriptEngine engine = manager.getEngineByName ("nashorn"); mēģiniet {engine.eval (jauns FileReader (args [0])); } catch (ScriptException se) {err.println (se.getMessage ()); } noķert (IOException ioe) {err.println (ioe.getMessage ()); }}}

The galvenais () Šajā piemērā esošā metode vispirms pārbauda, ​​vai ir norādīts viens komandrindas arguments (skripta faila nosaukums). Pretējā gadījumā tas parāda lietošanas informāciju un pārtrauc lietojumprogrammas darbību.

Pieņemot, ka ir šis arguments, galvenais () momentāno javax.script.ScriptEngineManager klasē. ScriptEngineManager ir ieejas punkts Java Scripting API.

Tālāk ScriptEngineManager objekta ScriptEngine getEngineByName (String shortName) metode tiek izmantota, lai iegūtu skriptu dzinēju, kas atbilst vēlamajam īss vārds vērtība. Java 10 atbalsta Nashorn skriptu dzinēju, kas tiek iegūts, nokārtojot "nashorn" uz getEngineByName (). Atgrieztā objekta klase īsteno javax.script.ScriptEngine interfeiss.

ScriptEngine paziņo vairāki eval () skripta novērtēšanas metodes. galvenais () izsauc Object eval (Lasītāja lasītājs) metode skripta nolasīšanai no tā java.io.FileReader objekta arguments un (pieņemot, ka java.io.IOException netiek izmests), tad novērtē skriptu. Šī metode atgriež jebkuru skripta atgriešanās vērtību, kuru es ignorēju. Arī šī metode met javax.script.ScriptException kad skriptā rodas kļūda.

Sastādiet 2. sarakstu šādi:

javac RunScript.java

Es parādīšu, kā palaist šo lietojumprogrammu, kad būšu uzrādījis pirmo skriptu.

Funkcionāla programmēšana ar tīrām funkcijām

A tīra funkcija ir funkcionāla programmēšanas funkcija, kas ir atkarīga tikai no tās ievades argumentiem un bez ārēja stāvokļa. An netīra funkcija ir funkcionāla programmēšanas funkcija, kas pārkāpj kādu no šīm prasībām. Tā kā tīrajām funkcijām nav mijiedarbības ar ārpasauli (izņemot citu tīru funkciju izsaukšanu), tīra funkcija vienmēr atgriež to pašu rezultātu par tiem pašiem argumentiem. Arī tīrām funkcijām nav novērojamu blakusparādību.

Vai tīra funkcija var veikt I / O?

Ja I / O ir blakusparādība, vai tīra funkcija var veikt I / O? Atbilde ir jā. Šīs problēmas risināšanai Haskels izmanto monādes. Lai uzzinātu vairāk par tīrām funkcijām un I / O, skatiet sadaļu "Tīras funkcijas un I / O".

Tīras funkcijas pret nešķīstajām funkcijām

3. saraksta JavaScript kontrastē ar nešķīstu aprēķinātbonusu () darbojas ar tīru aprēķinātbonus2 () funkciju.

3. saraksts. Tīro un netīro funkciju salīdzināšana (script1.js)

// netīrs bonusa aprēķins var limit = 100; funkcija calcbonus (numSales) {return (numSales> limits)? 0,10 * numSales: 0} print (aprēķinātbonusu (174)) // tīrā prēmiju aprēķināšanas funkcija calcbonus2 (numSales) {return (numSales> 100)? 0,10 * numSales: 0} drukāt (aprēķinātbonus2 (174))

aprēķinātbonusu () ir netīrs, jo piekļūst ārējam ierobežojums mainīgais. Turpretī aprēķinātbonus2 () ir tīrs, jo ievēro abas tīrības prasības. Palaist script1.js sekojoši:

java RunScript script1.js

Lūk, izeja, kas jums jāievēro:

17.400000000000002 17.400000000000002

Pieņemsim aprēķinātbonus2 () tika pārstrādāts līdz peļņas aprēķināšanas bonuss (numSales). Būtu aprēķinātbonus2 () joprojām esi tīrs? Atbilde ir nē: kad tīra funkcija izsauc nešķīstu funkciju, "tīrā funkcija" kļūst nešķīsta.

Ja starp tīrām funkcijām nav atkarības no datiem, tās var novērtēt jebkurā secībā, neietekmējot rezultātu, padarot tās piemērotas paralēlai izpildei. Tas ir viens no funkcionālās programmēšanas ieguvumiem.

Vairāk par netīrām funkcijām

Ne visām funkcionālajām programmēšanas funkcijām jābūt tīrām. Kā skaidro Funkcionālā programmēšana: Pure Functions, ir iespējams (un dažreiz vēlams) "nošķirt lietojumprogrammas tīru, funkcionālu, uz vērtībām balstītu kodolu no ārējā, obligātā apvalka".

Funkcionāla programmēšana ar augstāka līmeņa funkcijām

A augstākas kārtas funkcija ir matemātiska funkcija, kas saņem funkcijas kā argumentus, atgriež funkciju zvanītājam vai abus. Viens piemērs ir aprēķina diferenciālis operators, d / dx, kas atgriež funkcijas atvasinājumu f.

Pirmās klases funkcijas ir pirmās klases pilsoņi

Ar matemātisko augstākās pakāpes funkciju jēdzienu ir cieši saistīts pirmās klases funkcija, kas ir funkcionāla programmēšanas funkcija, kas citas funkcionālās programmēšanas funkcijas uzskata par argumentiem un / vai atgriež funkcionālo programmēšanas funkciju. Pirmās klases funkcijas ir pirmās klases pilsoņi tāpēc, ka tie var parādīties visur, kur vien iespējams, citas pirmās klases programmas entītijas (piemēram, skaitļi), tostarp piešķirt mainīgajam vai nodot kā argumentu funkcijai vai atgriezt no tās.

4. saraksta JavaScript parāda anonīmu salīdzināšanas funkciju nodošanu pirmās klases šķirošanas funkcijai.

Anonīmu salīdzināšanas funkciju nodošana (script2.js)

funkciju kārtošana (a, cmp) {for (var pass = 0; pass  iziet; i--) if (cmp (a [i], a [piespēle]) <0) {var temp = a [i] a [i] = a [iet] a [iet] = temp}} var a = [ 22, 91, 3, 45, 64, 67, -1] kārtot (a, funkcija (i, j) {atgriezties i - j;}) a.forEach (funkcija (ieraksts) {drukāt (ieraksts)}) izdrukāt ( '\ n') sort (a, function (i, j) {return j - i;}) a.forEch (funkcija (ieraksts) {druka (ieraksts)}) druka ('\ n') a = ["X "," E "," Q "," A "," P "] kārtot (a, funkcija (i, j) {atgriezties i  j; }) a. katram (funkcija (ieraksts) {izdrukāt (ievadīt)}) drukāt ('\ n') kārtot (a, funkcija (i, j) {atgriezties i> j? -1: i <j;}) a .forEach (funkcija (ieraksts) {drukāt (ieraksts)})

Šajā piemērā sākotnējais kārtot () zvans kā pirmo argumentu saņem masīvu, kam seko anonīma salīdzināšanas funkcija. Kad to izsauc, anonīma salīdzināšanas funkcija tiek izpildīta atgriešanās i - j; lai iegūtu augšupejošu kārtojumu. Ar atpakaļgaitu i un j, ar otro salīdzināšanas funkciju tiek panākta dilstoša kārtošana. Trešais un ceturtais kārtot () zvani saņem anonīmas salīdzināšanas funkcijas, kas nedaudz atšķiras, lai pareizi salīdzinātu virkņu vērtības.

Palaidiet script2.js piemērs:

java RunScript script2.js

Lūk, paredzamā produkcija:

-1 3 22 45 64 67 91 91 67 64 45 22 3 -1 A E P Q X X Q P E A

Filtrējiet un kartējiet

Funkcionālās programmēšanas valodas parasti nodrošina vairākas noderīgas augstākas kārtas funkcijas. Divi izplatīti piemēri ir filtrs un karte.

  • A filtru kaut kādā secībā apstrādā sarakstu, lai izveidotu jaunu sarakstu, kurā būtu tieši tie sākotnējā saraksta elementi, kuriem dotais predikāts (domāju, ka Būla izteiksme) atgriež patiesību.
  • A karte piemēro noteiktu funkciju katram saraksta elementam, atgriežot rezultātu sarakstu tādā pašā secībā.

JavaScript atbalsta filtrēšanas un kartēšanas funkcionalitāti, izmantojot filtrs () un karte () augstākas kārtas funkcijas. 5. saraksts parāda šīs funkcijas nepāra skaitļu filtrēšanai un numuru kartēšanai to kubiņos.

Saraksts 5. Filtrēšana un kartēšana (script3.js)

print ([1, 2, 3, 4, 5, 6] .filter (function (num) {return num% 2 == 0})) print ('\ n') print ([3, 13, 22]. karte (funkcija (num) {atgriezt num * 3}))

Palaidiet script3.js piemērs:

java RunScript script3.js

Jums jāievēro šāda izeja:

2,4,6 9,39,66

Samazināt

Vēl viena izplatīta augstākas pakāpes funkcija ir samazināt, kas ir vairāk pazīstams kā locījums. Šī funkcija samazina sarakstu līdz vienai vērtībai.

6. sarakstā tiek izmantoti JavaScript samazināt () augstākas kārtas funkcija, lai samazinātu skaitļu masīvu līdz vienam skaitlim, kas pēc tam tiek dalīts ar masīva garumu, lai iegūtu vidējo.

Saraksts 6. Skaitļu masīva samazināšana līdz vienam skaitlim (script4.js)

var numuri = [22, 30, 43] drukāt (skaitļi.samazināt (funkcija (acc, līkne) {return acc + līkne}) / skaitļi.length)

Palaidiet 6. saraksta skriptu (iekš script4.js) sekojoši:

java RunScript script4.js

Jums jāievēro šāda izeja:

31.666666666666668

Jūs varētu domāt, ka filtrs, kartēšana un augstākas kārtas funkciju samazināšana novērš nepieciešamību pēc if-else un dažādiem looping paziņojumiem, un jums būtu taisnība. Viņu iekšējā ieviešana rūpējas par lēmumiem un atkārtojumu.

Augstākas kārtas funkcija izmanto rekursiju, lai sasniegtu atkārtojumu. Rekursīvā funkcija piesaista sevi, ļaujot operācijai atkārtoties, līdz tā sasniedz a pamata lieta. Varat arī izmantot rekursiju, lai sasniegtu iterāciju savā funkcionālajā kodā.

Funkcionāla programmēšana ar slinku novērtēšanu

Vēl viena svarīga funkcionālās programmēšanas funkcija ir slinks vērtējums (zināms arī kā neierobežots novērtējums), kas ir izteiksmes novērtēšanas atlikšana pēc iespējas ilgāk. Slinks novērtējums piedāvā vairākas priekšrocības, tostarp šīs divas:

  • Dārgus (pēc laika) aprēķinus var atlikt, līdz tie ir absolūti nepieciešami.
  • Ir iespējamas neierobežotas kolekcijas. Viņi turpinās piegādāt elementus tik ilgi, kamēr viņiem to prasīs.

Slinkā vērtēšana ir neatņemama Haskela sastāvdaļa. Tas neko neaprēķinās (ieskaitot funkcijas argumentus pirms funkcijas izsaukšanas), ja vien tas nav absolūti nepieciešams.

Java straumēšanas API kapitalizē slinko vērtēšanu. Straumes starpoperācijas (piem., filtrs ()) vienmēr ir slinki; viņi neko nedara līdz termināla darbībai (piemēram, katram()) tiek izpildīts.

Kaut arī slinka vērtēšana ir svarīga funkcionālo valodu sastāvdaļa, pat daudzas obligātās valodas nodrošina iebūvētu atbalstu dažām slinkuma formām. Piemēram, lielākā daļa programmēšanas valodu atbalsta īssavienojuma novērtēšanu Būla un OR operatoru kontekstā. Šie operatori ir slinki, atsakoties novērtēt savus labās puses operandus, ja kreisās puses operands ir viltus (AND) vai patiess (OR).

7. saraksts ir slinka vērtējuma piemērs JavaScript skriptā.

Saraksts 7. Slinks vērtējums JavaScript (script5.js)

var a = nepatiesa && dārga funkcija ("1") var b = patiesa && dārga funkcija ("2") var c = nepatiesa || dearFunction ("3") var d = true || funkcija dearFunction ("4") dārga funkcija (id) {print ("dārgā funkcija () izsaukta ar" + id)}

Palaidiet kodu script5.js sekojoši:

java RunScript script5.js

Jums jāievēro šāda izeja:

dearFunction () izsaukts ar 2 dearFunction () izsaukts ar 3

Slinks novērtējums bieži tiek apvienots ar piezīmēm - optimizācijas paņēmienu, ko galvenokārt izmanto, lai paātrinātu datorprogrammas, saglabājot dārgu funkciju izsaukumu rezultātus un atgriežot kešatmiņā saglabāto rezultātu, kad atkārtojas tās pašas ievades.

Tā kā slinks novērtējums nedarbojas ar blakusparādībām (piemēram, kods, kas rada izņēmumus un I / O), galvenokārt tiek izmantotas imperatīvās valodas dedzīgs novērtējums (zināms arī kā stingra vērtēšana), kur izteiksme tiek novērtēta, tiklīdz tā ir saistīta ar mainīgo.

Vairāk par slinku vērtēšanu un piezīmēšanu

Google meklēšana atklās daudzas noderīgas diskusijas par slinku novērtēšanu ar piezīmēm vai bez tām. Viens piemērs ir "JavaScript optimizēšana ar funkcionālu programmēšanu".

Funkcionāla programmēšana ar slēgšanu

Pirmās klases funkcijas ir saistītas ar jēdzienu a slēgšana, kas ir pastāvīga darbības joma, kas attiecas uz lokālajiem mainīgajiem pat tad, kad koda izpilde ir atstājusi bloku, kurā tika definēti vietējie mainīgie.

Amatniecības aizdari

Operatīvi: a slēgšana ir ieraksts, kas saglabā funkciju un tās vidi. Vide kartē katru no funkcijas brīvajiem mainīgajiem lielumiem (mainīgie, kas tiek izmantoti lokāli, bet ir definēti pievienojošajā sfērā) ar vērtību vai atsauci, kurai mainīgā nosaukums bija saistīts, kad tika izveidota slēgšana. Tas ļauj funkcijai piekļūt uzņemtajiem mainīgajiem, izmantojot to vērtību vai atsauču slēgšanas kopijas, pat ja funkcija tiek izsaukta ārpus to darbības jomas.

Lai palīdzētu noskaidrot šo jēdzienu, 8. sarakstā tiek parādīts JavaScript skripts, kas ievieš vienkāršu aizvēršanu. Skripts ir balstīts uz šeit sniegto piemēru.

8. saraksts. Vienkārša slēgšana (script6.js)

funkcija pievienot (x) {funkcija daļējaPievienot (y) {atgriezt y + x} atgriezt daļējipievienot} var pievienot10 = pievienot (10) var pievienot20 = pievienot (20) izdrukāt (pievienot10 (5)) izdrukāt (pievienot20 (5))

8. saraksts definē pirmās klases funkciju ar nosaukumu pievienot () ar parametru x un ligzdota funkcija daļēji pievienot (). Ligzdota funkcija daļēji pievienot () ir piekļuve x jo x ir iekšā pievienot ()leksiskā darbības joma. Funkcija pievienot () atgriež slēgšanu, kurā ir atsauce uz daļēji pievienot () un apkārtējās vides kopija pievienot (), kurā x ir vērtība, kas tai piešķirta īpašā izsaukumā pievienot ().

Tā kā pievienot () atgriež funkcijas tipa mainīgo lielumu pievienot10 un pievienot20 ir arī funkcijas tips. The pievienot10 (5) izsaukums atgriežas 15 jo izsaukums piešķir 5 uz parametru y zvanā uz daļēji pievienot (), izmantojot saglabāto vidi daļēji pievienot () kur x ir 10. The pievienot20 (5) izsaukums atgriežas 25 jo, kaut arī tas arī piešķir 5 uz y zvanā uz daļēji pievienot (), tagad tā izmanto citu saglabātu vidi daļēji pievienot () kur x ir 20. Tādējādi, kamēr pievienot10 () un pievienot20 () izmantojiet to pašu funkciju daļēji pievienot (), saistītās vides atšķiras, un, atsaucoties uz slēgšanu, būs saistība x uz divām dažādām vērtībām abos izsaukumos, novērtējot funkciju diviem dažādiem rezultātiem.

Palaidiet 8. saraksta skriptu (iekš script6.js) sekojoši:

java RunScript script6.js

Jums jāievēro šāda izeja:

15 25

Funkcionāla programmēšana ar kariju

Karija ir veids, kā daudzargumentu funkcijas novērtējumu tulkot līdzvērtīgā vienargumentu funkciju secības vērtējumā. Piemēram, funkcijai ir divi argumenti: x un y. Karija veicot funkciju pārveido tikai par uzņemšanu x un atgriež funkciju, kas prasa tikai y. Karija veidošana ir saistīta ar daļēju lietošanu, bet nav tas pats, kas ir process, kurā funkcijai tiek piestiprināti vairāki argumenti, veidojot citu mazāka aritāta funkciju.

9. sarakstā ir parādīts JavaScript skripts, kas demonstrē kariju.

9. uzskaite JavaScript (script7.js)

funkcija reizināt (x, y) {atgriezties x * y} funkcija curried_multiply (x) {atgriešanās funkcija (y) {return x * y}} print (reizināt (6, 7)) print (curried_multiply (6) (7)) var mul_by_4 = curried_multiply (4) print (mul_by_4 (2))

Scenārijs parāda neuztraucamu divu argumentu reizināt () funkciju, kam seko pirmās klases curried_multiply () funkcija, kas saņem argumentu multiplicand x un atgriež slēgšanu, kurā ir atsauce uz anonīmu funkciju (kas saņem reizinātāja argumentu y) un apkārtējās vides kopija curried_multiply (), kurā x ir vērtība, kas tai piešķirta izsaukumā curried_multiply ().

Pārējais skripts vispirms izsauc reizināt () ar diviem argumentiem un izdrukā rezultātu. Pēc tam tā atsaucas curried_multiply () divos veidos:

  • saīsināts (vairāk) (6) (7) rezultātā saīsināts (vairāk) (6) vispirms izpildot. Atgrieztā aizvēršana izpilda anonīmo funkciju ar aizvēruma saglabāto x vērtība 6 tiek reizināts ar 7.
  • var mul_by_4 = curried_multiply (4) izpilda saīsināts (4) un piešķir slēgšanu mul_by_4. zelts (2) izpilda anonīmo funkciju ar slēgšanu 4 vērtība un nodotais arguments 2.

Palaidiet 9. saraksta skriptu (iekš script7.js) sekojoši:

java RunScript script7.js

Jums jāievēro šāda izeja:

42 42 8

Kāpēc izmantot kariju?

Savā emuāra ziņā "Kāpēc palīdz karijs" Hjū Džeksons novēro, ka "mazos gabaliņus var viegli konfigurēt un atkārtoti izmantot bez traucējumiem". Quora "Kādas ir karija priekšrocības funkcionālajā programmēšanā?" apraksta kariju kā "lētu atkarības iesmidzināšanas veidu", kas atvieglo kartēšanas / filtrēšanas / locīšanas procesu (un parasti augstākas kārtas funkcijas). Šajā Q & A ir arī atzīmēts, ka karija izmantošana "palīdz mums izveidot abstraktas funkcijas".

Noslēgumā

Šajā apmācībā esat iemācījies dažus funkcionālās programmēšanas pamatus. Mēs esam izmantojuši JavaScript piemērus, lai izpētītu piecas galvenās funkcionālās programmēšanas metodes, kuras mēs tālāk izpētīsim, izmantojot Java kodu 2. daļā. Papildus Java 8 funkcionālo programmēšanas iespēju iepazīšanai šīs apmācības otrā puse palīdzēs jums domā funkcionāli, pārveidojot objektorientētā Java koda piemēru tā funkcionālajā ekvivalentā.

Uzziniet vairāk par funkcionālo programmēšanu

Grāmata Ievads funkcionālajā programmēšanā (Ričards Birds un Filips Vadlers, Prentice Hall International Series in Computing Science, 1992) man šķita noderīga, apgūstot funkcionālās programmēšanas pamatus.

Šo stāstu "Funkcionālā programmēšana Java izstrādātājiem, 1. daļa" sākotnēji publicēja JavaWorld.

$config[zx-auto] not found$config[zx-overlay] not found