Programmering

Funksjonell programmering for Java-utviklere, del 1

Java 8 introduserte Java-utviklere for funksjonell programmering med lambda-uttrykk. Denne Java-utgivelsen varslet utviklere effektivt om at det ikke lenger er tilstrekkelig å tenke på Java-programmering bare fra det tvingende, objektorienterte perspektivet. En Java-utvikler må også kunne tenke og kode ved hjelp av det deklarative funksjonelle paradigmet.

Denne opplæringen presenterer det grunnleggende om funksjonell programmering. Jeg begynner med terminologi, så skal vi grave i funksjonelle programmeringskonsepter. Jeg avslutter med å introdusere deg for fem funksjonelle programmeringsteknikker. Kodeeksempler i disse seksjonene vil komme i gang med rene funksjoner, høyere ordensfunksjoner, lat evaluering, nedleggelser og karri.

Funksjonell programmering øker

Institute of Electrical and Electronics Engineers (IEEE) inkluderte funksjonelle programmeringsspråk i sine 25 beste programmeringsspråk for 2018, og Google Trends rangerer for tiden funksjonell programmering som mer populær enn objektorientert programmering.

Det er klart at funksjonell programmering ikke kan ignoreres, men hvorfor blir den mer populær? Blant annet gjør funksjonell programmering det lettere å verifisere programkorrektheten. Det forenkler også opprettelsen av samtidige programmer. Samtidighet (eller parallell behandling) er viktig for å forbedre applikasjonsytelsen.

last ned Få koden Last ned kildekoden for eksempel applikasjoner i denne opplæringen. Skapt av Jeff Friesen for JavaWorld.

Hva er funksjonell programmering?

Datamaskiner implementerer vanligvis Von Neumann-arkitekturen, som er en mye brukt dataarkitektur basert på en beskrivelse fra 1945 av matematikeren og fysikeren John von Neumann (og andre). Denne arkitekturen er partisk mot tvingende programmering, som er et programmeringsparadigme som bruker utsagn for å endre tilstanden til et program. C, C ++ og Java er alle viktige programmeringsspråk.

I 1977 holdt den fremtredende informatikeren John Backus (kjent for sitt arbeid med FORTRAN) et foredrag med tittelen "Kan programmering frigjøres fra von Neumann-stilen?" Backus hevdet at Von Neumann-arkitekturen og dens tilknyttede imperative språk er grunnleggende feil, og presenterte et funksjonsnivå programmeringsspråk (FP) som en løsning.

Avklaring av Backus

Fordi Backus-foredraget ble presentert for flere tiår siden, kan det være vanskelig å forstå noen av ideene. Blogger Tomasz Jaskuła legger til klarhet og fotnoter i blogginnlegget sitt fra januar 2018.

Funksjonelle programmeringskonsepter og terminologi

Funksjonell programmering er en programmeringsstil der beregninger blir kodifisert som funksjonelle programmeringsfunksjoner. Dette er matematiske funksjonslignende konstruksjoner (f.eks. Lambda-funksjoner) som blir evaluert i ekspresjonssammenheng.

Funksjonelle programmeringsspråk er erklærende, som betyr at en beregnings logikk uttrykkes uten å beskrive dens kontrollflyt. I deklarativ programmering er det ingen uttalelser. I stedet bruker programmerere uttrykk for å fortelle datamaskinen hva som må gjøres, men ikke hvordan oppgaven skal utføres. Hvis du er kjent med SQL eller vanlige uttrykk, har du litt erfaring med den deklarative stilen; begge bruker uttrykk for å beskrive hva som må gjøres, i stedet for å bruke uttalelser for å beskrive hvordan man gjør det.

EN beregning i funksjonell programmering er beskrevet av funksjoner som evalueres i ekspresjonssammenhenger. Disse funksjonene er ikke de samme som funksjonene som brukes i tvingende programmering, for eksempel en Java-metode som returnerer en verdi. I stedet for a funksjonell programmering funksjon er som en matematisk funksjon, som produserer en utgang som vanligvis bare avhenger av argumentene. Hver gang en funksjonell programmeringsfunksjon kalles med de samme argumentene, oppnås det samme resultatet. Funksjoner i funksjonell programmering sies å vises referansetransparens. Dette betyr at du kan erstatte et funksjonsanrop med den resulterende verdien uten å endre beregningens betydning.

Funksjonell programmering favoriserer uforanderlighet, som betyr at staten ikke kan endre seg. Dette er vanligvis ikke tilfelle i tvingende programmering, der en tvingende funksjon kan være assosiert med tilstand (for eksempel en Java-forekomstvariabel). Å ringe til denne funksjonen til forskjellige tider med de samme argumentene, kan føre til forskjellige returverdier fordi tilstanden i dette tilfellet er foranderlig, noe som betyr at det endres.

Bivirkninger i tvingende og funksjonell programmering

Statlige endringer er en bivirkning av tvingende programmering, og forhindrer referansetransparens. Det er mange andre bivirkninger som er verdt å vite om, spesielt når du vurderer om du skal bruke den tvingende eller funksjonelle stilen i programmene dine.

En vanlig bivirkning i tvingende programmering er når en tildelingsuttalelse muterer en variabel ved å endre den lagrede verdien. Funksjoner i funksjonell programmering støtter ikke variable oppgaver. Ettersom den opprinnelige verdien til en variabel aldri endres, fjerner funksjonell programmering denne bivirkningen.

En annen vanlig bivirkning skjer når du endrer en tvingende funksjons atferd basert på et kastet unntak, som er en observerbar interaksjon med innringeren. For mer informasjon, se Stack Overflow-diskusjonen "Hvorfor er oppheving av et unntak en bivirkning?"

En tredje vanlig bivirkning oppstår når en I / O-operasjon skriver inn tekst som ikke kan leses, eller skriver ut tekst som ikke kan skrives. Se Stack Exchange-diskusjonen "Hvordan kan IO forårsake bivirkninger i funksjonell programmering?" for å lære mer om denne bivirkningen.

Å eliminere bivirkninger gjør det mye lettere å forstå og forutsi beregningsatferd. Det hjelper også å gjøre koden mer egnet for parallell behandling, noe som ofte forbedrer applikasjonsytelsen. Mens det er bivirkninger i funksjonell programmering, er de generelt færre enn i tvingende programmering. Bruk av funksjonell programmering kan hjelpe deg med å skrive kode som er lettere å forstå, vedlikeholde og teste, og som også er mer gjenbrukbar.

Opprinnelse (og opphavsmenn) til funksjonell programmering

Funksjonell programmering stammer fra lambdakalkulus, som ble introdusert av Alonzo Church. En annen opprinnelse er kombinasjonslogikk, som ble introdusert av Moses Schönfinkel og deretter utviklet av Haskell Curry.

Objektorientert versus funksjonell programmering

Jeg har opprettet et Java-program som kontrasterer tvingende, objektorientert og deklarativ, funksjonell programmering tilnærminger til å skrive kode. Studer koden nedenfor, og så peker jeg på forskjeller mellom de to eksemplene.

Oppføring 1. Ansatte.java

importere java.util.ArrayList; importere java.util.List; offentlig klasse Ansatte {statisk klasse Ansatt {privat Strengnavn; privat alder; Ansatt (strengnavn, int alder) {this.name = navn; this.age = alder; } int getAge () {retur alder; } @ Override public String toString () {return name + ":" + age; }} public static void main (String [] args) {List ansatte = ny ArrayList (); ansatte.add (ny ansatt ("John Doe", 63)); ansatte.add (ny ansatt ("Sally Smith", 29)); ansatte.add (ny ansatt ("Bob Jone", 36)); ansatte.add (ny ansatt ("Margaret Foster", 53)); printMedarbeider1 (ansatte, 50); System.out.println (); printMedarbeider2 (ansatte, 50); } offentlig statisk ugyldig utskriftEmployee1 (Liste ansatte, int alder) {for (Employee emp: ansatte) hvis (emp.getAge () <age) System.out.println (emp); } offentlig statisk ugyldig utskriftEmployee2 (Liste ansatte, int alder) {ansatte.stream () .filter (emp -> emp.age System.out.println (emp)); }}

Oppføring 1 avslører en Ansatte applikasjon som skaper noen få Ansatt objekter, og skriver deretter ut en liste over alle ansatte som er yngre enn 50 år. Denne koden viser både objektorienterte og funksjonelle programmeringsstiler.

De printMedarbeider1 () metoden avslører den imperative, uttalelsesorienterte tilnærmingen. Som spesifisert, går den metoden over en liste over ansatte, sammenligner hver ansattes alder mot en argumentverdi, og (hvis alderen er mindre enn argumentet), skriver den ansattes detaljer ut.

De printMedarbeider2 () metoden avslører den deklarative, uttrykksorienterte tilnærmingen, i dette tilfellet implementert med Streams API. I stedet for å spesifisere spesifikt hvordan de ansatte skal skrives ut (trinnvis), spesifiserer uttrykket det ønskede resultatet og overlater detaljene om hvordan du gjør det til Java. Tenker på filter() som den funksjonelle ekvivalenten til en hvis uttalelse, og for hver() som funksjonelt tilsvarer til uttalelse.

Du kan samle liste 1 som følger:

javac Ansatte.java

Bruk følgende kommando for å kjøre det resulterende programmet:

java Ansatte

Utgangen skal se ut slik:

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

Funksjonelle programmeringseksempler

I de neste avsnittene vil vi utforske fem kjerneteknikker som brukes i funksjonell programmering: rene funksjoner, høyere ordensfunksjoner, lat evaluering, nedleggelser og karri. Eksempler i denne delen er kodet i JavaScript fordi dens enkelhet, i forhold til Java, vil tillate oss å fokusere på teknikkene. I del 2 vil vi se på de samme teknikkene ved hjelp av Java-kode.

Oppføring 2 presenterer kildekoden til RunScript, et Java-program som bruker Java's Scripting API for å lette kjøring av JavaScript-kode. RunScript vil være basisprogrammet for alle de kommende eksemplene.

Oppføring 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"); komme tilbake; } 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 ()); }}}

De hoved() metoden i dette eksemplet verifiserer først at et enkelt kommandolinjeargument (navnet på en skriptfil) er spesifisert. Ellers viser den bruksinformasjon og avslutter applikasjonen.

Forutsatt tilstedeværelsen av dette argumentet, hoved() instantierer javax.script.ScriptEngineManager klasse. ScriptEngineManager er inngangspunktet til Java's Scripting API.

Neste, den ScriptEngineManager objektets ScriptEngine getEngineByName (strengnavn) metoden kalles for å skaffe en skriptmotor som tilsvarer ønsket kort navn verdi. Java 10 støtter Nashorn-skriptmotoren, som oppnås ved bestått "nashorn" til getEngineByName (). Den returnerte gjenstandens klasse implementerer javax.script.ScriptEngine grensesnitt.

ScriptEngine erklærer flere eval () metoder for evaluering av et skript. hoved() påberoper seg Objekteval (Leserleser) metode for å lese skriptet fra dets java.io.FileReader objektargument og (forutsatt at java.io.IO Unntak blir ikke kastet) evaluer deretter skriptet. Denne metoden returnerer hvilken som helst skriptreturverdi, som jeg ignorerer. Også denne metoden kaster javax.script.ScriptException når det oppstår en feil i skriptet.

Sammensett oppføring 2 som følger:

javac RunScript.java

Jeg viser deg hvordan du kjører dette programmet etter at jeg har presentert det første skriptet.

Funksjonell programmering med rene funksjoner

EN ren funksjon er en funksjonell programmeringsfunksjon som bare avhenger av inngangsargumentene og ingen ekstern tilstand. An uren funksjon er en funksjonell programmeringsfunksjon som bryter med noen av disse kravene. Fordi rene funksjoner ikke har noen interaksjon med omverdenen (bortsett fra å kalle andre rene funksjoner), returnerer en ren funksjon alltid det samme resultatet for de samme argumentene. Rene funksjoner har heller ingen observerbare bivirkninger.

Kan en ren funksjon utføre I / O?

Hvis I / O er en bivirkning, kan en ren funksjon utføre I / O? Svaret er ja. Haskell bruker monader for å løse dette problemet. Se "Rene funksjoner og I / U" for mer om rene funksjoner og I / U.

Rene funksjoner kontra urene funksjoner

JavaScript i Listing 3 kontrasterer urent beregningsbonus () funksjon med en ren calculatebonus2 () funksjon.

Oppføring 3. Sammenligning av rene vs urene funksjoner (script1.js)

// uren bonusberegning var limit = 100; funksjon calculatebonus (numSales) {return (numSales> limit)? 0.10 * numSales: 0} print (calculatebonus (174)) // ren bonusberegningsfunksjon calculatebonus2 (numSales) {return (numSales> 100)? 0,10 * numSales: 0} print (calculatebonus2 (174))

beregningsbonus () er urent fordi den får tilgang til det eksterne grense variabel. I motsetning, calculatebonus2 () er ren fordi den overholder begge kravene til renhet. Løpe script1.js som følger:

java RunScript script1.js

Her er resultatet du bør observere:

17.400000000000002 17.400000000000002

Anta calculatebonus2 () ble ombygd til return calculatebonus (numSales). Ville det calculatebonus2 () fortsatt være ren? Svaret er nei: når en ren funksjon påkaller en uren funksjon, blir den "rene funksjonen" uren.

Når det ikke er dataavhengighet mellom rene funksjoner, kan de evalueres i hvilken som helst rekkefølge uten å påvirke resultatet, noe som gjør dem egnet for parallell kjøring. Dette er en av fordelene ved funksjonell programmering.

Mer om urene funksjoner

Ikke alle funksjonelle programmeringsfunksjoner trenger å være rene. Som Functional Programming: Pure Functions forklarer, er det mulig (og noen ganger ønskelig) å "skille den rene, funksjonelle, verdibaserte kjernen i applikasjonen din fra et ytre, tvingende skall."

Funksjonell programmering med høyere ordensfunksjoner

EN høyere ordensfunksjon er en matematisk funksjon som mottar funksjoner som argumenter, returnerer en funksjon til den som ringer, eller begge deler. Et eksempel er kalkulus differensialoperator, d / dx, som returnerer avledet av funksjon f.

Førsteklasses funksjoner er førsteklasses borgere

Nært knyttet til det matematiske funksjonskonseptet med høyere ordre er førsteklasses funksjon, som er en funksjonell programmeringsfunksjon som tar andre funksjonelle programmeringsfunksjoner som argumenter og / eller returnerer en funksjonell programmeringsfunksjon. Førsteklasses funksjoner er førsteklasses borgere fordi de kan vises hvor andre førsteklasses programenheter (f.eks. tall) kan, inkludert å bli tildelt en variabel eller bli sendt som et argument til eller returnert fra en funksjon.

JavaScript i Listing 4 demonstrerer overføring av anonyme sammenligningsfunksjoner til en førsteklasses sorteringsfunksjon.

Oppføring 4. Overføring av anonyme sammenligningsfunksjoner (script2.js)

funksjons sortering (a, cmp) {for (var pass = 0; pass  sende; 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] sort (a, function (i, j) {return i - j;}) a.forEach (function (entry) {print (entry)}) print ( '\ n') sorter (a, funksjon (i, j) {retur j - i;}) a.forEach (funksjon (oppføring) {utskrift (oppføring)}) utskrift ('\ n') a = ["X "," E "," Q "," A "," P "] sort (a, funksjon (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 (funksjon (oppføring) {utskrift (oppføring)})

I dette eksemplet, den første sortere() anrop mottar en matrise som sitt første argument, etterfulgt av en anonym sammenligningsfunksjon. Når den anropes, utføres den anonyme sammenligningsfunksjonen retur i - j; for å oppnå en stigende sortering. Ved å reversere Jeg og j, den andre sammenligningsfunksjonen oppnår en synkende sortering. Den tredje og fjerde sortere() anrop mottar anonyme sammenligningsfunksjoner som er litt forskjellige for å kunne sammenligne strengverdier.

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

java RunScript script2.js

Her er forventet produksjon:

-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 kart

Funksjonelle programmeringsspråk gir vanligvis flere nyttige funksjoner med høyere ordre. To vanlige eksempler er filter og kart.

  • EN filter behandler en liste i noen rekkefølge for å produsere en ny liste som inneholder nøyaktig de elementene i den opprinnelige listen som et gitt predikat (tenk boolsk uttrykk) returnerer sant for.
  • EN kart bruker en gitt funksjon til hvert element i en liste, og returnerer en liste med resultater i samme rekkefølge.

JavaScript støtter filtrerings- og kartleggingsfunksjonalitet via filter() og kart() høyere ordensfunksjoner. Oppføring 5 viser disse funksjonene for å filtrere ut oddetall og kartlegge tall til kubene.

Oppføring 5. Filtrering og kartlegging (script3.js)

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

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

java RunScript script3.js

Du bør følge følgende utdata:

2,4,6 9,39,66

Redusere

En annen vanlig høyere ordensfunksjon er redusere, som er mer kjent som en fold. Denne funksjonen reduserer en liste til en enkelt verdi.

Oppføring 6 bruker JavaScript redusere() høyere ordensfunksjon for å redusere en rekke tall til et enkelt tall, som deretter deles med matrisens lengde for å oppnå et gjennomsnitt.

Oppføring 6. Redusere en rekke tall til et enkelt tall (script4.js)

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

Kjør oppføring 6s skript (i script4.js) som følger:

java RunScript script4.js

Du bør følge følgende utdata:

31.666666666666668

Du kan kanskje tro at filteret, kartlegger og reduserer funksjoner av høyere orden, fjerner behovet for if-else og forskjellige sløyfesetninger, og du vil ha rett. Deres interne implementeringer tar seg av beslutninger og iterasjon.

En høyere ordensfunksjon bruker rekursjon for å oppnå iterasjon. En rekursiv funksjon påkaller seg selv, slik at en operasjon kan gjenta til den når en basissak. Du kan også utnytte rekursjon for å oppnå iterasjon i funksjonskoden din.

Funksjonell programmering med lat evaluering

En annen viktig funksjonell programmeringsfunksjon er lat evaluering (også kjent som ikke-streng evaluering), som er utsettelse av uttrykksevaluering så lenge som mulig. Lat evaluering gir flere fordeler, inkludert disse to:

  • Dyre (tidvis) beregninger kan utsettes til de er helt nødvendige.
  • Ubegrensede samlinger er mulig. De vil fortsette å levere elementer så lenge de blir bedt om å gjøre det.

Lat evaluering er integrert i Haskell. Det vil ikke beregne noe (inkludert argumentene til en funksjon før funksjonen kalles) med mindre det er strengt nødvendig å gjøre det.

Java's Streams API utnytter lat evaluering. En strøms mellomliggende operasjoner (f.eks. filter()) er alltid lat; de gjør ingenting før en terminaloperasjon (f.eks. for hver()) utføres.

Selv om lat evaluering er en viktig del av funksjonelle språk, gir til og med mange viktige språk innebygd støtte for noen former for latskap. For eksempel støtter de fleste programmeringsspråk kortslutningsevaluering i sammenheng med de boolske AND- og OR-operatørene. Disse operatørene er late og nekter å evaluere sine høyre operander når den venstre operanden er falsk (AND) eller true (OR).

Oppføring 7 er et eksempel på lat evaluering i et JavaScript-skript.

Oppføring 7. Lat evaluering i JavaScript (script5.js)

var a = false && expensiveFunction ("1") var b = true && expensiveFunction ("2") var c = false || expensiveFunction ("3") var d = true || dyrFunksjon ("4") -funksjon dyrFunksjon (id) {utskrift ("dyrFunksjon () kalt med" + id)}

Kjør koden inn script5.js som følger:

java RunScript script5.js

Du bør følge følgende utdata:

expensiveFunction () kalt med 2 expensiveFunction () kalt med 3

Lazy evaluering kombineres ofte med memoization, en optimaliseringsteknikk som primært brukes til å øke hastigheten på dataprogrammer ved å lagre resultatene av dyre funksjonsanrop og returnere det bufrede resultatet når de samme inngangene kommer igjen.

Fordi lat evaluering ikke fungerer med bivirkninger (for eksempel kode som gir unntak og I / O), bruker tvingende språk hovedsakelig ivrig evaluering (også kjent som streng evaluering), hvor et uttrykk blir evaluert så snart det er bundet til en variabel.

Mer om lat evaluering og memoisering

Et Google-søk vil avsløre mange nyttige diskusjoner om lat evaluering med eller uten memoisering. Et eksempel er "Optimalisere JavaScript med funksjonell programmering."

Funksjonell programmering med nedleggelser

Førsteklasses funksjoner er knyttet til begrepet a nedleggelse, som er et vedvarende omfang som holder på lokale variabler selv etter at kodeutførelsen har forlatt blokken der de lokale variablene ble definert.

Utforming av nedleggelser

Operasjonelt, a nedleggelse er en post som lagrer en funksjon og dens omgivelser. Miljøet kartlegger hver av funksjonens gratisvariabler (variabler som brukes lokalt, men definert i et omsluttende omfang) med verdien eller referansen som variabelens navn ble bundet til da lukkingen ble opprettet. Den lar funksjonen få tilgang til de fangede variablene gjennom lukningens kopier av deres verdier eller referanser, selv når funksjonen påberopes utenfor deres omfang.

For å avklare dette konseptet presenterer Listing 8 et JavaScript-skript som introduserer en enkel lukking. Manuset er basert på eksemplet som presenteres her.

Oppføring 8. En enkel nedleggelse (script6.js)

function add (x) {function partialAdd (y) {return y + x} return partialAdd} var add10 = add (10) var add20 = add (20) print (add10 (5)) print (add20 (5))

Oppføring 8 definerer en førsteklasses funksjon som heter legge til() med en parameter x og en nestet funksjon partialAdd (). Den nestede funksjonen partialAdd () har tilgang til x fordi x er i legge til()sitt leksikale omfang. Funksjon legge til() returnerer en lukking som inneholder en referanse til partialAdd () og en kopi av miljøet rundt legge til(), der x har verdien tildelt i en spesifikk påkalling av legge til().

Fordi legge til() returnerer en verdi av funksjonstype, variabler legg til 10 og legg til20 har også funksjonstype. De legg til 10 (5) påkallingen kommer tilbake 15 fordi påkallingen tildeles 5 til parameter y i samtalen til partialAdd (), bruker det lagrede miljøet for partialAdd () hvor x er 10. De legg til 20 (5) påkallingen kommer tilbake 25 fordi, selv om det også tildeles 5 til y i samtalen til partialAdd (), bruker den nå et annet lagret miljø for partialAdd () hvor x er 20. Dermed mens legg til10 () og legg til 20 () bruker den samme funksjonen partialAdd (), de tilknyttede miljøene er forskjellige, og påkalling av stengingene vil binde seg x til to forskjellige verdier i de to påkallelsene, og evaluere funksjonen til to forskjellige resultater.

Kjør oppføring 8s skript (i script6.js) som følger:

java RunScript script6.js

Du bør følge følgende utdata:

15 25

Funksjonell programmering med karri

Currying er en måte å oversette evaluering av en flerargumentfunksjon til evaluering av en ekvivalent sekvens av enkeltargumentfunksjoner. For eksempel tar en funksjon to argumenter: x og y. Currying forvandler funksjonen til å ta bare x og returnere en funksjon som bare tar y. Currying er relatert til, men er ikke det samme som delvis applikasjon, som er prosessen med å fikse en rekke argumenter til en funksjon, og produsere en annen funksjon med mindre arity.

Listing 9 presenterer et JavaScript-skript som demonstrerer karri.

Oppføring 9. Currying i JavaScript (script7.js)

funksjon multiplisere (x, y) {return x * y} funksjon curried_multiply (x) {retur funksjon (y) {return x * y}} skriv ut (multipliser (6, 7)) print (curried_multiply (6) (7)) var mul_by_4 = curried_multiply (4) print (mul_by_4 (2))

Manuset presenterer et ikke-curried to-argument multiplisere() funksjon, etterfulgt av en førsteklasses curried_multiply () funksjon som mottar multiplikasjonsargument x og returnerer en lukking som inneholder en referanse til en anonym funksjon (som mottar multiplikatorargument y) og en kopi av miljøet rundt curried_multiply (), der x har verdien tildelt den i en påkalling av curried_multiply ().

Resten av manuset påberoper seg først multiplisere() med to argumenter og skriver ut resultatet. Den påberoper seg deretter curried_multiply () på to måter:

  • curried_multiply (6) (7) resulterer i curried_multiply (6) utfører først. Den returnerte nedleggelsen utfører den anonyme funksjonen med nedleggelsen lagret x verdi 6 blir multiplisert med 7.
  • var mul_by_4 = curried_multiply (4) utfører curried_multiply (4) og tildeler nedleggelsen til mul_by_4. mul_by_4 (2) utfører den anonyme funksjonen med nedleggelsen 4 verdi og bestått argument 2.

Kjør oppføring 9s skript (i script7.js) som følger:

java RunScript script7.js

Du bør følge følgende utdata:

42 42 8

Hvorfor bruke karri?

I sitt blogginnlegg "Why curry helps" bemerker Hugh Jackson at "små biter kan konfigureres og gjenbrukes med letthet, uten rot." Quoras "Hva er fordelene med karri i funksjonell programmering?" beskriver karri som "en billig form for avhengighetsinjeksjon", som letter prosessen med kartlegging / filtrering / folding (og funksjoner av høyere orden generelt). Denne spørsmål og svar bemerker også at karriering "hjelper oss med å skape abstrakte funksjoner."

For å konkludere

I denne veiledningen har du lært noen grunnleggende om funksjonell programmering. Vi har brukt eksempler i JavaScript for å studere fem funksjonelle programmeringsteknikker, som vi vil utforske videre ved hjelp av Java-kode i del 2. I tillegg til å turnere Java 8s funksjonelle programmeringsfunksjoner, vil andre halvdel av denne veiledningen hjelpe deg å begynne å tenk funksjonelt, ved å konvertere et eksempel på objektorientert Java-kode til dens funksjonelle ekvivalent.

Lær mer om funksjonell programmering

Jeg syntes boka Introduksjon til funksjonell programmering (Richard Bird og Philip Wadler, Prentice Hall International Series in Computing Science, 1992) var nyttig for å lære det grunnleggende om funksjonell programmering.

Denne historien, "Funksjonell programmering for Java-utviklere, del 1" ble opprinnelig utgitt av JavaWorld.

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