Programmering

Funktionel programmering til Java-udviklere, del 1

Java 8 introducerede Java-udviklere til funktionel programmering med lambda-udtryk. Denne Java-udgivelse meddelte udviklere effektivt, at det ikke længere er tilstrækkeligt at tænke på Java-programmering kun fra det tvingende, objektorienterede perspektiv. En Java-udvikler skal også være i stand til at tænke og kode ved hjælp af det deklarative funktionelle paradigme.

Denne vejledning præsenterer det grundlæggende i funktionel programmering. Jeg starter med terminologi, så graver vi i funktionelle programmeringskoncepter. Jeg slutter med at introducere dig til fem funktionelle programmeringsteknikker. Kodeeksempler i disse sektioner får dig i gang med rene funktioner, højere ordensfunktioner, doven evaluering, lukninger og currying.

Funktionel programmering er stigende

Institute of Electrical and Electronics Engineers (IEEE) inkluderede funktionelle programmeringssprog i sine top 25 programmeringssprog i 2018, og Google Trends rangerer i øjeblikket funktionel programmering som mere populær end objektorienteret programmering.

Det er klart, at funktionel programmering ikke kan ignoreres, men hvorfor bliver den mere populær? Funktionel programmering gør det blandt andet lettere at kontrollere programkorrekthed. Det forenkler også oprettelsen af ​​samtidige programmer. Samtidighed (eller parallel behandling) er afgørende for at forbedre applikationsydelsen.

download Hent koden Download kildekoden for eksempel applikationer i denne vejledning. Oprettet af Jeff Friesen til JavaWorld.

Hvad er funktionel programmering?

Computere implementerer typisk Von Neumann-arkitekturen, som er en udbredt computerarkitektur baseret på en beskrivelse fra 1945 af matematikeren og fysikeren John von Neumann (og andre). Denne arkitektur er partisk mod tvingende programmering, som er et programmeringsparadigme, der bruger udsagn til at ændre et programs tilstand. C, C ++ og Java er alle vigtige programmeringssprog.

I 1977 holdt den fremragende computerforsker John Backus (kendt for sit arbejde med FORTRAN) et foredrag med titlen "Kan programmering frigøres fra von Neumann-stilen?" Backus hævdede, at Von Neumann-arkitekturen og dens tilknyttede tvingende sprog grundlæggende er fejlbehæftet, og præsenterede et programmeringssprog på funktionelt niveau (FP) som en løsning.

Afklaring af Backus

Fordi Backus-foredraget blev præsenteret for flere årtier siden, kan nogle af dets ideer være svære at forstå. Blogger Tomasz Jaskuła tilføjer klarhed og fodnoter i sit blogindlæg fra januar 2018.

Funktionelle programmeringskoncepter og terminologi

Funktionel programmering er en programmeringsstil, hvor beregninger er kodificeret som funktionelle programmeringsfunktioner. Disse er matematiske funktionslignende konstruktioner (fx lambda-funktioner), der evalueres i ekspressionskontekster.

Funktionelle programmeringssprog er erklærende, hvilket betyder, at en beregnings logik udtrykkes uden at beskrive dens kontrolflow. I deklarativ programmering er der ingen udsagn. I stedet bruger programmører udtryk for at fortælle computeren, hvad der skal gøres, men ikke hvordan man udfører opgaven. Hvis du er fortrolig med SQL eller regulære udtryk, har du nogle erfaringer med den deklarative stil; begge bruger udtryk til at beskrive, hvad der skal gøres, snarere end at bruge udsagn til at beskrive, hvordan man gør det.

EN beregning i funktionel programmering er beskrevet af funktioner, der evalueres i ekspressionskontekster. Disse funktioner er ikke de samme som de funktioner, der anvendes i tvingende programmering, såsom en Java-metode, der returnerer en værdi. I stedet for a funktionel programmering funktion er som en matematisk funktion, der producerer et output, der typisk kun afhænger af dets argumenter. Hver gang der kaldes en funktionel programmeringsfunktion med de samme argumenter, opnås det samme resultat. Funktioner i funktionel programmering siges at udvise henvisning til gennemsigtighed. Dette betyder, at du kan erstatte et funktionsopkald med dets resulterende værdi uden at ændre beregningens betydning.

Funktionel programmering favoriserer uforanderlighed, hvilket betyder, at staten ikke kan ændre sig. Dette er typisk ikke tilfældet i tvingende programmering, hvor en tvingende funktion muligvis er associeret med tilstand (såsom en Java-instansvariabel). Hvis du kalder denne funktion på forskellige tidspunkter med de samme argumenter, kan det resultere i forskellige returværdier, fordi tilstanden i dette tilfælde er kan ændres, hvilket betyder, at det ændres.

Bivirkninger i tvingende og funktionel programmering

Statlige ændringer er en bivirkning af tvingende programmering, der forhindrer henvisning til gennemsigtighed. Der er mange andre bivirkninger, der er værd at vide om, især når du vurderer, om du skal bruge den bydende eller funktionelle stil i dine programmer.

En almindelig bivirkning i tvingende programmering er, når en tildelingserklæring muterer en variabel ved at ændre dens lagrede værdi. Funktioner i funktionel programmering understøtter ikke variable tildelinger. Da en variabels indledende værdi aldrig ændres, fjerner funktionel programmering denne bivirkning.

En anden almindelig bivirkning sker ved ændring af en tvingende funktions adfærd baseret på en kastet undtagelse, som er en observerbar interaktion med den, der ringer op. For mere information, se Stack Overflow-diskussionen "Hvorfor er rejsning af en undtagelse en bivirkning?"

En tredje almindelig bivirkning opstår, når en I / O-handling indtaster tekst, der ikke kan ulæses, eller udsender tekst, der ikke kan skrives. Se Stack Exchange-diskussionen "Hvordan kan IO forårsage bivirkninger i funktionel programmering?" for at lære mere om denne bivirkning.

Fjernelse af bivirkninger gør det meget lettere at forstå og forudsige beregningsadfærd. Det hjælper også med at gøre koden mere egnet til parallel behandling, hvilket ofte forbedrer applikationsydelsen. Mens der er bivirkninger i funktionel programmering, er de generelt færre end i tvingende programmering. Brug af funktionel programmering kan hjælpe dig med at skrive kode, der er lettere at forstå, vedligeholde og teste, og som også kan genbruges.

Oprindelser (og ophavsmænd) til funktionel programmering

Funktionel programmering stammer fra lambda-calculus, som blev introduceret af Alonzo Church. En anden oprindelse er kombinationslogik, som blev introduceret af Moses Schönfinkel og efterfølgende udviklet af Haskell Curry.

Objektorienteret versus funktionel programmering

Jeg har oprettet et Java-program, der står i kontrast til bydende nødvendigt, objektorienteret og deklarativ, funktionel programmering af tilgange til skrivning af kode. Undersøg koden nedenfor, og så vil jeg påpege forskelle mellem de to eksempler.

Notering 1. Medarbejdere.java

importere java.util.ArrayList; importere java.util.List; offentlige klassemedarbejdere {statisk klasse Medarbejder {privat Stringnavn; privat int alder Medarbejder (String name, int age) {this.name = name; this.age = alder; } int getAge () {return age; } @ Override public String toString () {return name + ":" + age; }} offentlig statisk ugyldig hoved (String [] args) {List medarbejdere = ny ArrayList (); ansatte.add (ny medarbejder ("John Doe", 63)); medarbejdere.add (ny medarbejder ("Sally Smith", 29)); ansatte.add (ny medarbejder ("Bob Jone", 36)); ansatte.add (ny medarbejder ("Margaret Foster", 53)); printMedarbejder1 (medarbejdere, 50); System.out.println (); printMedarbejder2 (medarbejdere, 50); } offentlig statisk ugyldig printEmployee1 (Liste medarbejdere, int alder) {for (Medarbejder emp: medarbejdere) hvis (emp.getAge () <age) System.out.println (emp); } offentlig statisk ugyldig printEmployee2 (Liste medarbejdere, int alder) {ansatte.stream () .filter (emp -> emp.age System.out.println (emp)); }}

Liste 1 afslører en Medarbejdere applikation, der skaber nogle få Medarbejder objekter og udskriver derefter en liste over alle medarbejdere, der er yngre end 50 år. Denne kode viser både objektorienterede og funktionelle programmeringsstile.

Det printMedarbejder1 () Metoden afslører den bydende, sætningsorienterede tilgang. Som specificeret gentager denne metode en liste over medarbejdere, sammenligner hver medarbejders alder med en argumentværdi og (hvis alderen er mindre end argumentet), udskriver medarbejderens detaljer.

Det printMedarbejder2 () metoden afslører den deklarative, udtryksorienterede tilgang, i dette tilfælde implementeret med Streams API. I stedet for nødvendigt at specificere, hvordan de ansatte skal udskrives (trin for trin), angiver udtrykket det ønskede resultat og overlader detaljerne om, hvordan man gør det til Java. Tænke på filter() som den funktionelle ækvivalent af en hvis erklæring og for hver() som funktionelt svarende til til udmelding.

Du kan sammensætte liste 1 som følger:

javac Medarbejdere.java

Brug følgende kommando til at køre den resulterende applikation:

java Medarbejdere

Outputtet skal se sådan ud:

Sally Smith: 29 Bob Jone: 36 Sally Smith: 29 Bob Jone: 36

Eksempler på funktionel programmering

I de næste sektioner udforsker vi fem kerneteknikker, der bruges i funktionel programmering: rene funktioner, højere ordensfunktioner, doven evaluering, lukninger og currying. Eksempler i dette afsnit er kodet i JavaScript, fordi dets enkelhed i forhold til Java giver os mulighed for at fokusere på teknikkerne. I del 2 genbesøger vi de samme teknikker ved hjælp af Java-kode.

Liste 2 viser kildekoden til RunScript, en Java-applikation, der bruger Java's Scripting API til at gøre det lettere at køre JavaScript-kode. RunScript vil være basisprogrammet for alle de kommende eksempler.

Liste 2. RunScript.java

importere java.io.FileReader; importere java.io.IOException; importere javax.script.ScriptEngine; importere javax.script.ScriptEngineManager; importere javax.script.ScriptException; importer statisk java.lang.System. *; offentlig klasse RunScript {public static void main (String [] args) {if (args.length! = 1) {err.println ("use: java RunScript script"); Vend tilbage; } ScriptEngineManager manager = ny ScriptEngineManager (); ScriptEngine engine = manager.getEngineByName ("nashorn"); prøv {engine.eval (ny FileReader (args [0])); } fange (ScriptException se) {err.println (se.getMessage ()); } fange (IOException ioe) {err.println (ioe.getMessage ()); }}}

Det hoved () metode i dette eksempel verificerer først, at der er angivet et enkelt kommandolinjeargument (navnet på en scriptfil). Ellers viser det brugsoplysninger og afslutter applikationen.

Under forudsætning af tilstedeværelsen af ​​dette argument, hoved () instantierer javax.script.ScriptEngineManager klasse. ScriptEngineManager er indgangspunktet i Java's Scripting API.

Dernæst ScriptEngineManager objekt ScriptEngine getEngineByName (String shortName) metode kaldes for at få en scriptmotor, der svarer til det ønskede kort navn værdi. Java 10 understøtter Nashorn-scriptmotoren, som opnås ved at passere "nashorn" til getEngineByName (). Den returnerede objekts klasse implementerer javax.script.ScriptEngine interface.

ScriptEngine erklærer flere eval () metoder til evaluering af et script. hoved () påberåber sig Objekteval (læserlæser) metode til at læse scriptet fra dets java.io.FileReader objektargument og (forudsat at java.io.IOUndtagelse kastes ikke) evaluer derefter scriptet. Denne metode returnerer enhver scriptreturværdi, som jeg ignorerer. Også denne metode kaster javax.script.ScriptException når der opstår en fejl i scriptet.

Kompilér liste 2 som følger:

javac RunScript.java

Jeg viser dig, hvordan du kører denne applikation, efter at jeg har præsenteret det første script.

Funktionel programmering med rene funktioner

EN ren funktion er en funktionel programmeringsfunktion, der kun afhænger af dens inputargumenter og ingen ekstern tilstand. En uren funktion er en funktionel programmeringsfunktion, der overtræder et af disse krav. Fordi rene funktioner ikke har nogen interaktion med omverdenen (bortset fra at kalde andre rene funktioner), returnerer en ren funktion altid det samme resultat for de samme argumenter. Rene funktioner har heller ingen observerbare bivirkninger.

Kan en ren funktion udføre I / O?

Hvis I / O er en bivirkning, kan en ren funktion udføre I / O? Svaret er ja. Haskell bruger monader til at løse dette problem. Se "Rene funktioner og I / O" for mere om rene funktioner og I / O.

Rene funktioner versus urene funktioner

JavaScript i Listing 3 står i kontrast til et urent beregningsbonus () funktion med en ren calculatebonus2 () fungere.

Liste 3. Sammenligning af rene vs urene funktioner (script1.js)

// uren bonusberegning var grænse = 100; funktion calculatebonus (numSales) {return (numSales> limit)? 0,10 * numSales: 0} print (calculatebonus (174)) // ren bonus beregningsfunktion calculatebonus2 (numSales) {return (numSales> 100)? 0,10 * numSales: 0} print (calculatebonus2 (174))

beregningsbonus () er urent, fordi det får adgang til det eksterne begrænse variabel. I modsætning, calculatebonus2 () er ren, fordi den overholder begge krav til renhed. Løb script1.js som følger:

java RunScript script1.js

Her er det output, du skal observere:

17.400000000000002 17.400000000000002

Formode calculatebonus2 () blev ombygget til return calculatebonus (numSales). Ville det calculatebonus2 () stadig være ren? Svaret er nej: når en ren funktion påberåber sig en uren funktion, bliver den "rene funktion" uren.

Når der ikke findes dataafhængighed mellem rene funktioner, kan de evalueres i en hvilken som helst rækkefølge uden at påvirke resultatet, hvilket gør dem egnede til parallel udførelse. Dette er en af ​​fordelene ved funktionel programmering.

Mere om urene funktioner

Ikke alle funktionelle programmeringsfunktioner skal være rene. Som funktionel programmering: Pure Functions forklarer, er det muligt (og undertiden ønskeligt) at "adskille den rene, funktionelle, værdibaserede kerne i din applikation fra en ydre, bydende skal."

Funktionel programmering med højere ordensfunktioner

EN højere ordens funktion er en matematisk funktion, der modtager funktioner som argumenter, returnerer en funktion til dens opkalder eller begge dele. Et eksempel er kalkulus differentiale operator, d / dx, som returnerer afledt af funktion f.

Førsteklasses funktioner er førsteklasses borgere

Nært beslægtet med det matematiske koncept for højere ordensfunktion er førsteklasses funktion, som er en funktionel programmeringsfunktion, der tager andre funktionelle programmeringsfunktioner som argumenter og / eller returnerer en funktionel programmeringsfunktion. Første klasses funktioner er førsteklasses borgere fordi de kan vises, hvor andre førsteklasses programenheder (f.eks. tal) kan, inklusive at blive tildelt en variabel eller blive sendt som et argument til eller returneret fra en funktion.

JavaScript i liste 4 viser, at anonyme sammenligningsfunktioner overføres til en førsteklasses sorteringsfunktion.

Liste 4. Videregivelse af anonyme sammenligningsfunktioner (script2.js)

funktionssortering (a, cmp) {for (var pass = 0; pass  passere; i--) hvis (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] sortering (a, funktion (i, j) {return i - j;}) a.forEach (funktion (post) {print (post)}) print ( '\ n') sortering (a, funktion (i, j) {return j - i;}) a.forEach (funktion (post) {print (post)}) print ('\ n') a = ["X "," E "," Q "," A "," P "] sort (a, funktion (i, j) {return i  j; }) a.forEach (funktion (post) {print (post)}) print ('\ n') sortering (a, funktion (i, j) {return i> j? -1: i <j;}) a .forEach (funktion (post) {print (post)})

I dette eksempel er initialen sortere() opkald modtager en matrix som sit første argument efterfulgt af en anonym sammenligningsfunktion. Når den kaldes, udføres den anonyme sammenligningsfunktion returnere i - j; for at opnå en stigende sortering. Ved at vende om jeg og j, den anden sammenligningsfunktion opnår en faldende sortering. Den tredje og fjerde sortere() opkald modtager anonyme sammenligningsfunktioner, der er lidt forskellige for at sammenligne strengværdier korrekt.

Kør script2.js eksempel som følger:

java RunScript script2.js

Her er den forventede output:

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

Filtrer og kort

Funktionelle programmeringssprog giver typisk flere nyttige funktioner af højere orden. To almindelige eksempler er filter og kort.

  • EN filter behandler en liste i en eller anden rækkefølge for at producere en ny liste, der indeholder nøjagtigt de elementer i den oprindelige liste, hvor et givet predikat (tænk boolsk udtryk) returnerer sandt.
  • EN kort anvender en given funktion på hvert element på en liste og returnerer en liste med resultater i samme rækkefølge.

JavaScript understøtter filtrerings- og kortlægningsfunktionalitet via filter() og kort() højere ordensfunktioner. Liste 5 viser disse funktioner til filtrering af ulige tal og kortlægning af numre til deres terninger.

Fortegnelse 5. Filtrering og kortlægning (script3.js)

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

Kør script3.js eksempel som følger:

java RunScript script3.js

Du skal overholde følgende output:

2,4,6 9,39,66

Reducere

En anden almindelig funktion af højere orden er reducere, som er mere almindeligt kendt som en fold. Denne funktion reducerer en liste til en enkelt værdi.

Liste 6 bruger JavaScript reducere() højere ordensfunktion for at reducere et array med tal til et enkelt nummer, som derefter divideres med arrayets længde for at opnå et gennemsnit.

Fortegnelse 6. Reduktion af en række numre til et enkelt nummer (script4.js)

var numbers = [22, 30, 43] print (numbers.reduce (funktion (acc, curval) {return acc + curval}) / numbers.length)

Kør Listing 6's script (i script4.js) som følger:

java RunScript script4.js

Du skal overholde følgende output:

31.666666666666668

Du tror måske, at filteret, kortlægger og reducerer højere ordensfunktioner fjerner behovet for if-else og forskellige looping-udsagn, og du ville have ret. Deres interne implementeringer tager sig af beslutninger og iteration.

En højere ordensfunktion bruger rekursion til at opnå iteration. En rekursiv funktion påberåber sig selv, så en operation kan gentages, indtil den når en basissag. Du kan også udnytte rekursion for at opnå iteration i din funktionelle kode.

Funktionel programmering med doven evaluering

En anden vigtig funktionel programmeringsfunktion er doven evaluering (også kendt som ikke-streng evaluering), som er udsættelsen af ​​ekspressionsevaluering så længe som muligt. Lazy evaluering giver flere fordele, herunder disse to:

  • Dyre (tidsmæssige) beregninger kan udsættes, indtil de er absolut nødvendige.
  • Ubegrænsede samlinger er mulige. De fortsætter med at levere elementer, så længe de bliver bedt om at gøre det.

Lazy evaluering er en integreret del af Haskell. Det beregner ikke noget (inklusive en funktions argumenter, før funktionen kaldes), medmindre det er strengt nødvendigt at gøre det.

Java's Streams API udnytter doven evaluering. En streams mellemliggende operationer (f.eks. filter()) er altid dovne; de gør ikke noget før en terminaloperation (f.eks. for hver()) udføres.

Selvom doven evaluering er en vigtig del af funktionelle sprog, giver selv mange vigtige sprog indbygget støtte til nogle former for dovenskab. For eksempel understøtter de fleste programmeringssprog kortslutningsevaluering i forbindelse med de boolske AND- og OR-operatører. Disse operatører er dovne og nægter at evaluere deres højre operander, når den venstre operand er falsk (AND) eller sand (OR).

Liste 7 er et eksempel på doven evaluering i et JavaScript-script.

Fortegnelse 7. Lazy evaluering i JavaScript (script5.js)

var a = falsk && dyrtFunktion ("1") var b = sand && dyrFunktion ("2") var c = falsk || expensiveFunction ("3") var d = true || dyrFunktion ("4") funktion dyrFunktion (id) {print ("dyrFunktion () kaldet med" + id)}

Kør koden ind script5.js som følger:

java RunScript script5.js

Du skal overholde følgende output:

duurFunktion () kaldet med 2 dyrFunktion () kaldet med 3

Lazy evaluering kombineres ofte med memoization, en optimeringsteknik, der primært bruges til at fremskynde computerprogrammer ved at gemme resultaterne af dyre funktionsopkald og returnere det cachelagrede resultat, når de samme input igen forekommer.

Fordi doven evaluering ikke fungerer med bivirkninger (såsom kode, der producerer undtagelser og I / O), er det absolut nødvendigt, at sprog kun bruges ivrig evaluering (også kendt som streng evaluering), hvor et udtryk evalueres, så snart det er bundet til en variabel.

Mere om doven evaluering og memoization

En Google-søgning vil afsløre mange nyttige diskussioner om doven evaluering med eller uden memoization. Et eksempel er "Optimering af din JavaScript med funktionel programmering."

Funktionel programmering med lukninger

Førsteklasses funktioner er forbundet med begrebet a lukning, som er et vedvarende omfang, der holder fast på lokale variabler, selv efter at kodeudførelsen har forladt blokken, hvor de lokale variabler blev defineret.

Udformning af lukninger

Operationelt, en lukning er en post, der gemmer en funktion og dens miljø. Miljøet kortlægger hver af funktionens gratis variabler (variabler, der bruges lokalt, men defineret i et omsluttende omfang) med den værdi eller reference, som variabelens navn var bundet til, da lukningen blev oprettet. Det giver funktionen adgang til de fangede variabler gennem lukningens kopier af deres værdier eller referencer, selv når funktionen påberåbes uden for deres anvendelsesområde.

For at hjælpe med at afklare dette koncept præsenterer Listing 8 et JavaScript-script, der introducerer en simpel lukning. Scriptet er baseret på eksemplet præsenteret her.

Liste 8. En simpel lukning (script6.js)

funktion tilføj (x) {funktion delvisTilføj (y) {retur y + x} returner delvisTilføj} var tilføj10 = tilføj (10) var tilføj20 = tilføj (20) udskriv (tilføj10 (5)) udskriv (tilføj20 (5))

Liste 8 definerer en førsteklasses funktion med navnet tilføje() med en parameter x og en indlejret funktion partialTilføj (). Den indlejrede funktion partialTilføj () har adgang til x fordi x er i tilføje()'s leksikale anvendelsesområde. Fungere tilføje() returnerer en lukning, der indeholder en henvisning til partialTilføj () og en kopi af miljøet omkring tilføje(), hvori x har den værdi, der er tildelt den i en specifik påkaldelse af tilføje().

Fordi tilføje() returnerer en værdi af funktionstype, variabler tilføj10 og tilføj20 har også funktionstype. Det tilføj10 (5) påkaldelse vender tilbage 15 fordi påkaldelsen tildeles 5 til parameter y i opkaldet til partialTilføj (), ved hjælp af det gemte miljø til partialTilføj () hvor x er 10. Det tilføj20 (5) påkaldelse vender tilbage 25 fordi, selvom det også tildeles 5 til y i opkaldet til partialTilføj (), bruger den nu et andet gemt miljø til partialTilføj () hvor x er 20. Således, mens tilføj10 () og tilføj20 () bruge den samme funktion partialTilføj (), de tilknyttede miljøer adskiller sig, og påkald af lukningerne vil være bundet x til to forskellige værdier i de to påkaldelser, evaluere funktionen til to forskellige resultater.

Kør Listing 8's script (i script6.js) som følger:

java RunScript script6.js

Du skal overholde følgende output:

15 25

Funktionel programmering med currying

Currying er en måde at oversætte evalueringen af ​​en flerargumentfunktion til vurderingen af ​​en ækvivalent sekvens af enkeltargumentfunktioner. For eksempel tager en funktion to argumenter: x og y. Currying forvandler funktionen til kun at tage x og returnere en funktion, der kun tager y. Currying er relateret til, men er ikke det samme som delvis anvendelse, hvilket er processen med at rette et antal argumenter til en funktion, hvilket producerer en anden funktion med mindre arity.

Listing 9 præsenterer et JavaScript-script, der viser currying.

Liste 9. Currying i JavaScript (script7.js)

funktion gang (x, y) {return x * y} funktion curried_multiply (x) {return funktion (y) {return x * y}} print (multiplicer (6, 7)) print (curried_multiply (6) (7)) var mul_by_4 = curried_multiply (4) print (mul_by_4 (2))

Manuskriptet præsenterer et non-curried to-argument formere sig() funktion efterfulgt af en førsteklasses curried_multiply () funktion, der modtager multiplikandargument x og returnerer en lukning, der indeholder en henvisning til en anonym funktion (der modtager multiplikatorargument y) og en kopi af miljøet omkring curried_multiply (), hvori x har den værdi, der er tildelt den i en påkaldelse af curried_multiply ().

Resten af ​​manuskriptet påberåber sig først formere sig() med to argumenter og udskriver resultatet. Det påberåber sig derefter curried_multiply () på to måder:

  • curried_multiply (6) (7) resulterer i curried_multiply (6) udfører først. Den returnerede lukning udfører den anonyme funktion med lukningen gemt x værdi 6 bliver ganget med 7.
  • var mul_by_4 = curried_multiply (4) udfører curried_multiply (4) og tildeler lukningen til mul_by_4. mul_by_4 (2) udfører den anonyme funktion med lukningen 4 værdi og bestået argument 2.

Kør Listing 9's script (i script7.js) som følger:

java RunScript script7.js

Du skal overholde følgende output:

42 42 8

Hvorfor bruge karry?

I sit blogindlæg "Hvorfor karry hjælper" bemærker Hugh Jackson, at "små stykker let kan konfigureres og genbruges uden rod." Quoras "Hvad er fordelene ved curry i funktionel programmering?" beskriver currying som "en billig form for afhængighedsinjektion", der letter processen med kortlægning / filtrering / foldning (og funktioner i højere orden generelt). Denne Q&A bemærker også, at curry "hjælper os med at skabe abstrakte funktioner."

Afslutningsvis

I denne vejledning har du lært nogle grundlæggende funktioner til funktionel programmering. Vi har brugt eksempler i JavaScript til at studere fem centrale funktionelle programmeringsteknikker, som vi nærmere udforsker ved hjælp af Java-kode i del 2. Ud over at turnere Java 8s funktionelle programmeringsfunktioner, vil anden halvdel af denne tutorial hjælpe dig med at begynde at tænk funktioneltved at konvertere et eksempel på objektorienteret Java-kode til dens funktionelle ækvivalent.

Lær mere om funktionel programmering

Jeg fandt bogen Introduktion til funktionel programmering (Richard Bird og Philip Wadler, Prentice Hall International Series in Computing Science, 1992) nyttige til at lære de grundlæggende funktioner i funktionel programmering.

Denne historie, "Funktionel programmering til Java-udviklere, del 1" blev oprindeligt udgivet af JavaWorld.

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