Programování

Funkční programování pro vývojáře Java, 1. část

Java 8 představila vývojáře Java funkční programování pomocí výrazů lambda. Toto vydání Java účinně upozornilo vývojáře, že již nestačí přemýšlet o programování v Javě pouze z imperativního, objektově orientovaného hlediska. Vývojář Java musí být také schopen přemýšlet a kódovat pomocí deklarativního funkčního paradigmatu.

Tento tutoriál představuje základy funkčního programování. Začnu terminologií, pak se ponoříme do konceptů funkčního programování. Na závěr vám představím pět technik funkčního programování. Příklady kódu v těchto částech vám pomohou začít s čistými funkcemi, funkcemi vyššího řádu, líným hodnocením, uzávěrkami a kari.

Funkční programování je na vzestupu

Institut elektrotechnických a elektronických inženýrů (IEEE) zahrnul funkční programovací jazyky do svých 25 nejlepších programovacích jazyků pro rok 2018 a Google Trends v současné době řadí funkční programování jako populárnější než objektově orientované programování.

Je zřejmé, že funkční programování nelze ignorovat, ale proč je stále populárnější? Funkční programování mimo jiné usnadňuje ověřování správnosti programu. Také zjednodušuje vytváření souběžných programů. Souběžnost (nebo paralelní zpracování) je zásadní pro zlepšení výkonu aplikace.

stáhnout Získat kód Stáhněte si zdrojový kód například pro aplikace v tomto výukovém programu. Vytvořil Jeff Friesen pro JavaWorld.

Co je funkční programování?

Počítače obvykle implementují architekturu Von Neumann, což je široce používaná počítačová architektura založená na popisu matematika a fyzika Johna von Neumanna (a dalších) z roku 1945. Tato architektura je zaujatá imperativní programování, což je paradigma programování, které používá příkazy ke změně stavu programu. C, C ++ a Java jsou imperativní programovací jazyky.

V roce 1977 přednesl významný počítačový vědec John Backus (známý svou prací na FORTRANU) přednášku s názvem „Může být programování osvobozeno od stylu von Neumanna?“ Backus tvrdil, že architektura Von Neumann a její přidružené imperativní jazyky jsou zásadně vadné, a jako řešení představil programovací jazyk na funkční úrovni (FP).

Objasnění Backuse

Protože přednáška Backus byla představena před několika desítkami let, může být těžké uchopit některé její myšlenky. Blogger Tomasz Jaskuła přidává do svého příspěvku na blogu od ledna 2018 jasnost a poznámky pod čarou.

Pojmy a terminologie funkčního programování

Funkcionální programování je styl programování, ve kterém jsou výpočty kodifikovány jako funkční programovací funkce. Jedná se o matematické funkce podobné konstrukty (např. Funkce lambda), které se vyhodnocují v kontextech výrazů.

Funkční programovací jazyky jsou deklarativní, což znamená, že logika výpočtu je vyjádřena bez popisu jeho řídicího toku. V deklarativním programování nejsou žádné příkazy. Místo toho programátoři pomocí výrazů informují počítač o tom, co je třeba udělat, ale nikoli o tom, jak úkol splnit. Pokud znáte SQL nebo regulární výrazy, máte nějaké zkušenosti s deklarativním stylem; oba používají výrazy k popisu toho, co je třeba udělat, namísto použití příkazů k popisu, jak to udělat.

A výpočet ve funkčním programování je popsán funkcemi, které jsou vyhodnocovány v kontextech výrazu. Tyto funkce nejsou stejné jako funkce používané v imperativním programování, například metoda Java, která vrací hodnotu. Místo toho Funkcionální programování Funkce je jako matematická funkce, která vytváří výstup, který obvykle závisí pouze na jejích argumentech. Pokaždé, když je funkce funkčního programování volána se stejnými argumenty, je dosaženo stejného výsledku. Funkce ve funkčním programování se údajně projevují referenční průhlednost. To znamená, že můžete nahradit volání funkce výslednou hodnotou beze změny významu výpočtu.

Přednosti funkčního programování neměnnost, což znamená, že stát se nemůže změnit. To obvykle není případ imperativního programování, kde by imperativní funkce mohla být spojena se stavem (například proměnná instance Java). Volání této funkce v různých časech se stejnými argumenty může mít za následek různé návratové hodnoty, protože v tomto případě je stav proměnlivý, což znamená, že se mění.

Vedlejší účinky imperativního a funkčního programování

Změny stavu jsou vedlejším efektem imperativního programování, které brání referenční transparentnosti. Existuje mnoho dalších vedlejších účinků, které stojí za to vědět, zvláště když hodnotíte, zda ve svých programech použít imperativní nebo funkční styl.

Jedním běžným vedlejším účinkem v imperativním programování je, když příkaz přiřazení mutuje proměnnou změnou její uložené hodnoty. Funkce ve funkčním programování nepodporují přiřazení proměnných. Protože se počáteční hodnota proměnné nikdy nezmění, funkční programování tento vedlejší efekt eliminuje.

Další častý vedlejší účinek se stane, když upravíte chování imperativní funkce na základě vyvolané výjimky, což je pozorovatelná interakce s volajícím. Další informace najdete v diskusi Přetečení zásobníku: „Proč je vyvolání výjimky vedlejším účinkem?“

Třetí společný vedlejší účinek nastane, když vstupně-výstupní operace zadá text, který nelze přečíst, nebo vydá text, který nelze odepsat. Viz diskuse Stack Exchange „Jak mohou IO způsobit vedlejší účinky ve funkčním programování?“ dozvědět se více o tomto vedlejším účinku.

Eliminace vedlejších účinků výrazně usnadňuje pochopení a předvídání výpočetního chování. Pomáhá také učinit kód vhodnějším pro paralelní zpracování, což často zlepšuje výkon aplikace. I když ve funkčním programování existují vedlejší účinky, je jich obecně méně než v imperativním programování. Používání funkčního programování vám pomůže napsat kód, který je snáze srozumitelný, udržovatelný a testovatelný a je také více použitelný.

Počátky (a původci) funkčního programování

Funkční programování vzniklo v lambda kalkulu, který zavedl Alonzo Church. Dalším počátkem je kombinační logika, kterou představil Moses Schönfinkel a následně ji vyvinul Haskell Curry.

Objektově orientované versus funkční programování

Vytvořil jsem aplikaci Java, která kontrastuje s imperativ, objektově orientovaný a deklarativní, funkční programovací přístupy k psaní kódu. Prostudujte si níže uvedený kód a poté poukážu na rozdíly mezi těmito dvěma příklady.

Výpis 1. Zaměstnanci.java

import java.util.ArrayList; import java.util.List; veřejná třída Zaměstnanci {statická třída Zaměstnanec {soukromý název řetězce; soukromý věk; Zaměstnanec (jméno řetězce, stáří) {this.name = name; this.age = věk; } int getAge () {návratový věk; } @Override public String toString () {návratové jméno + ":" + věk; }} public static void main (String [] args) {List zaměstnanci = nový ArrayList (); zaměstnanci.add (nový zaměstnanec ("John Doe", 63)); zaměstnanci.add (nový zaměstnanec ("Sally Smith", 29)); zaměstnanci.add (nový zaměstnanec ("Bob Jone", 36)); customers.add (nová zaměstnankyně („Margaret Foster“, 53)); printEmployee1 (zaměstnanci, 50); System.out.println (); printEmployee2 (zaměstnanci, 50); } public static void printEmployee1 (Seznam zaměstnanců, int věk) {for (Zaměstnanec emp: zaměstnanci) if (emp.getAge () <age) System.out.println (emp); } public static void printEmployee2 (seznam zaměstnanců, věk int) {zaměstnanci.stream () .filter (emp -> emp.age System.out.println (emp)); }}

Výpis 1 odhaluje Zaměstnanci aplikace, která vytváří několik Zaměstnanec objekty, poté vytiskne seznam všech zaměstnanců, kteří jsou mladší než 50. Tento kód ukazuje jak objektově orientované, tak styly funkčního programování.

The printEmployee1 () metoda odhaluje imperativní přístup orientovaný na prohlášení. Jak je uvedeno, tato metoda iteruje seznam zaměstnanců, porovnává věk každého zaměstnance s hodnotou argumentu a (pokud je věk menší než argument), vytiskne podrobnosti zaměstnance.

The printEmployee2 () metoda odhaluje deklarativní přístup zaměřený na výraz, v tomto případě implementovaný pomocí Streams API. Namísto imperativního určení, jak tisknout zaměstnance (krok za krokem), výraz určuje požadovaný výsledek a ponechává podrobnosti o tom, jak to udělat, v Javě. Myslet na filtr() jako funkční ekvivalent -li prohlášení a pro každého() jako funkčně ekvivalentní pro prohlášení.

Výpis 1 můžete sestavit následujícím způsobem:

zaměstnanci javac.java

Ke spuštění výsledné aplikace použijte následující příkaz:

zaměstnanci java

Výstup by měl vypadat asi takto:

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

Příklady funkčního programování

V dalších částech prozkoumáme pět základních technik používaných ve funkčním programování: čisté funkce, funkce vyššího řádu, líné vyhodnocení, uzávěry a kari. Příklady v této části jsou kódovány v JavaScriptu, protože jeho jednoduchost ve srovnání s Javou nám umožní soustředit se na techniky. V části 2 se vrátíme ke stejným technikám pomocí kódu Java.

Výpis 2 představuje zdrojový kód RunScript, Java aplikace, která používá Java Scripting API k usnadnění spouštění kódu JavaScript. RunScript bude základním programem pro všechny následující příklady.

Výpis 2. RunScript.java

importovat java.io.FileReader; import java.io.IOException; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; importovat statický java.lang.System. *; public class RunScript {public static void main (String [] args) {if (args.length! = 1) {err.println ("usage: java RunScript script"); vrátit se; } Správce ScriptEngineManager = nový ScriptEngineManager (); ScriptEngine engine = manager.getEngineByName ("nashorn"); try {engine.eval (new FileReader (args [0])); } catch (ScriptException se) {err.println (se.getMessage ()); } catch (IOException ioe) {err.println (ioe.getMessage ()); }}}

The hlavní() metoda v tomto příkladu nejprve ověří, že byl zadán jeden argument příkazového řádku (název souboru skriptu). Jinak zobrazí informace o použití a ukončí aplikaci.

Za předpokladu přítomnosti tohoto argumentu hlavní() vytváří instanci javax.script.ScriptEngineManager třída. ScriptEngineManager je vstupním bodem do Java Scripting API.

Dále ScriptEngineManager objektu ScriptEngine getEngineByName (řetězec shortName) metoda je volána k získání skriptovacího stroje odpovídajícího požadovanému krátké jméno hodnota. Java 10 podporuje skriptovací stroj Nashorn, který je získán předáním "nashorn" na getEngineByName (). Třída vráceného objektu implementuje javax.script.ScriptEngine rozhraní.

ScriptEngine prohlašuje několik eval () metody pro hodnocení skriptu. hlavní() vyvolá Object eval (čtečka Reader) metoda pro čtení skriptu z jeho java.io.FileReader argument objektu a (za předpokladu, že java.io.IOException není hozen), pak vyhodnotit skript. Tato metoda vrací jakoukoli návratovou hodnotu skriptu, kterou ignoruji. Tato metoda také hodí javax.script.ScriptException když ve skriptu dojde k chybě.

Sestavte výpis 2 následujícím způsobem:

javac RunScript.java

Po představení prvního skriptu vám ukážu, jak tuto aplikaci spustit.

Funkční programování s čistými funkcemi

A čistá funkce je funkční programovací funkce, která závisí pouze na jejích vstupních argumentech a žádném externím stavu. An nečistá funkce je funkční programovací funkce, která porušuje některý z těchto požadavků. Protože čisté funkce nemají žádnou interakci s vnějším světem (kromě volání jiných čistých funkcí), čistá funkce vždy vrátí stejný výsledek pro stejné argumenty. Čisté funkce také nemají žádné pozorovatelné vedlejší účinky.

Může čistá funkce provádět I / O?

Pokud je I / O vedlejší účinek, může čistá funkce provádět I / O? Odpověď je ano. Haskell k řešení tohoto problému používá monády. Další informace o čistých funkcích a I / O najdete v části „Čisté funkce a I / O“.

Čisté funkce versus nečisté funkce

JavaScript v seznamu 3 kontrastuje s nečistým vypočítatbonus () funkce s čistým vypočítatbonus2 () funkce.

Výpis 3. Porovnání čistých vs nečistých funkcí (script1.js)

// výpočet nečistého bonusu var limit = 100; funkce countbonus (numSales) {návrat (numSales> limit)? 0,10 * numSales: 0} tisk (vypočítatbonus (174)) // funkce výpočtu čistého bonusu vypočítatbonus2 (numSales) {návrat (numSales> 100)? 0,10 * numSales: 0} tisk (vypočítatbonus2 (174))

vypočítatbonus () je nečistý, protože přistupuje k externímu omezit proměnná. V porovnání, vypočítatbonus2 () je čistý, protože splňuje oba požadavky na čistotu. Běh script1.js jak následuje:

Java RunScript script1.js

Zde je výstup, který byste měli sledovat:

17.400000000000002 17.400000000000002

Předpokládat vypočítatbonus2 () byl refaktorován na návrat vypočítatbonus (numSales). Bych vypočítatbonus2 () být stále čistý? Odpověď zní ne: když čistá funkce vyvolá nečistou funkci, stane se „čistá funkce“ nečistou.

Pokud mezi čistými funkcemi neexistuje žádná závislost na datech, lze je vyhodnotit v libovolném pořadí bez ovlivnění výsledku, což je činí vhodnými pro paralelní provádění. To je jedna z výhod funkčního programování.

Více o nečistých funkcích

Ne všechny funkční programovací funkce musí být čisté. Jak vysvětluje Functional Programming: Pure Functions, je možné (a někdy žádoucí) „oddělit čisté, funkční a hodnotově orientované jádro vaší aplikace od vnějšího imperativního prostředí.“

Funkční programování s funkcemi vyššího řádu

A funkce vyššího řádu je matematická funkce, která přijímá funkce jako argumenty, vrací funkci volajícímu nebo obojí. Jedním příkladem je diferenciální operátor počtu, d / dx, který vrací derivaci funkce F.

Prvotřídní funkce jsou občané první třídy

S matematickým konceptem funkce vyššího řádu úzce souvisí prvotřídní funkce, což je funkce funkčního programování, která bere další funkce funkčního programování jako argumenty a / nebo vrací funkci funkčního programování. Prvotřídní funkce jsou občané první třídy protože se mohou objevit všude, kde mohou jiné prvotřídní entity programu (např. čísla), včetně toho, že jsou přiřazeny k proměnné nebo jsou předány jako argument nebo vráceny z funkce.

JavaScript ve výpisu 4 ukazuje předávání anonymních srovnávacích funkcí prvotřídní třídicí funkci.

Výpis 4. Předávání anonymních srovnávacích funkcí (script2.js)

funkce sort (a, cmp) {for (var pass = 0; pass  složit; 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 "] řazení (a, funkce (i, j) {návrat i  j; }) a.forEach (funkce (položka) {tisk (položka)}) tisk ('\ n') řazení (a, funkce (i, j) {návrat i> j? -1: i <j;}) a .forEach (funkce (položka) {tisk (položka)})

V tomto příkladu počáteční sort () volání přijme pole jako první argument, za nímž následuje anonymní porovnávací funkce. Při volání se provede funkce anonymního porovnání návrat i - j; dosáhnout vzestupného řazení. Zpětným chodem i a j, druhá srovnávací funkce dosahuje sestupného řazení. Třetí a čtvrtý sort () volání přijímají anonymní srovnávací funkce, které se mírně liší, aby bylo možné správně porovnat hodnoty řetězce.

Spusťte script2.js příklad takto:

Java RunScript script2.js

Zde je očekávaný výstup:

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

Filtrovat a mapovat

Funkční programovací jazyky obvykle poskytují několik užitečných funkcí vyššího řádu. Dva běžné příklady jsou filtr a mapa.

  • A filtr zpracuje seznam v určitém pořadí, aby vytvořil nový seznam obsahující přesně ty prvky původního seznamu, pro které daný predikát (myslím Booleovský výraz) vrací true.
  • A mapa použije danou funkci na každý prvek seznamu a vrátí seznam výsledků ve stejném pořadí.

JavaScript podporuje funkce filtrování a mapování prostřednictvím filtr() a mapa() funkce vyššího řádu. Výpis 5 ukazuje tyto funkce pro filtrování lichých čísel a mapování čísel na jejich kostky.

Výpis 5. Filtrování a mapování (script3.js)

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

Spusťte script3.js příklad takto:

java RunScript script3.js

Měli byste dodržovat následující výstup:

2,4,6 9,39,66

Snížit

Další běžná funkce vyššího řádu je snížit, který je více obyčejně známý jako záhyb. Tato funkce redukuje seznam na jednu hodnotu.

Výpis 6 používá JavaScript snížit() funkce vyššího řádu pro zmenšení pole čísel na jedno číslo, které se pak vydělí délkou pole, aby se získal průměr.

Výpis 6. Redukce řady čísel na jedno číslo (script4.js)

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

Spustit skript Výpisu 6 (v script4.js) jak následuje:

Java RunScript script4.js

Měli byste dodržovat následující výstup:

31.666666666666668

Možná si myslíte, že funkce filtrování, mapování a snižování vyšších řádů vylučují potřebu if-else a různých příkazů opakování a měli byste pravdu. Jejich interní implementace se starají o rozhodnutí a iteraci.

Funkce vyššího řádu používá k dosažení iterace rekurzi. Rekurzivní funkce se sama vyvolá a umožňuje operaci opakovat, dokud nedosáhne a základní případ. Můžete také využít rekurze k dosažení iterace ve vašem funkčním kódu.

Funkční programování s líným vyhodnocením

Další důležitou funkcí funkčního programování je líné hodnocení (také známý jako nonstrict hodnocení), což je odklad hodnocení výrazu na co nejdéle. Líné vyhodnocení nabízí několik výhod, včetně těchto dvou:

  • Drahé (časově) výpočty lze odložit, dokud nejsou naprosto nezbytné.
  • Jsou možné neomezené sbírky. Budou doručovat prvky tak dlouho, jak budou požádáni.

Líné hodnocení je nedílnou součástí Haskella. Nevypočítá nic (včetně argumentů funkce před voláním funkce), pokud to není nezbytně nutné.

Rozhraní Java Streams API vydělává na líném hodnocení. Mezilehlé operace streamu (např. filtr()) jsou vždy líní; nedělají nic, dokud nebude fungovat terminál (např. pro každého()) je proveden.

I když líné hodnocení je důležitou součástí funkčních jazyků, i mnoho imperativních jazyků poskytuje integrovanou podporu pro některé formy lenivosti. Například většina programovacích jazyků podporuje vyhodnocení zkratu v kontextu logických operátorů AND a OR. Tito operátoři jsou líní a odmítají hodnotit své pravé operandy, když je levý operand nepravdivý (AND) nebo true (OR).

Výpis 7 je příkladem líného vyhodnocení ve skriptu JavaScript.

Výpis 7. Líné vyhodnocení v JavaScriptu (script5.js)

var a = false && expensiveFunction ("1") var b = true && expensiveFunction ("2") var c = false || expensiveFunction ("3") var d = true || drahá funkce ("4") drahá funkce (id) {print ("drahá funkce () volaná s" + id)}

Spusťte kód script5.js jak následuje:

java RunScript script5.js

Měli byste dodržovat následující výstup:

drahá funkce () volala s 2 drahá funkce () volala s 3

Líné vyhodnocení se často kombinuje s memoizací, což je optimalizační technika používaná především k urychlení počítačových programů ukládáním výsledků drahých volání funkcí a vrácením výsledku v mezipaměti, když se znovu vyskytnou stejné vstupy.

Protože líné vyhodnocení nefunguje s vedlejšími efekty (jako je kód, který vytváří výjimky a I / O), používají se hlavně imperativní jazyky nedočkavé hodnocení (také známý jako přísné hodnocení), kde je výraz vyhodnocen, jakmile je vázán na proměnnou.

Více o líném hodnocení a memoizaci

Vyhledávání Google odhalí mnoho užitečných diskusí o líném hodnocení s memoizací nebo bez ní. Jedním z příkladů je „Optimalizace kódu JavaScript pomocí funkčního programování.“

Funkční programování s uzávěry

Prvotřídní funkce jsou spojeny s konceptem a uzavření, což je trvalý obor, který se drží na lokálních proměnných i poté, co provádění kódu opustilo blok, ve kterém byly definovány lokální proměnné.

Řemeslné uzávěry

Provozně, a uzavření je záznam, který ukládá funkci a její prostředí. Prostředí mapuje každou z volných proměnných funkce (proměnné používané místně, ale definované v uzavřeném rozsahu) s hodnotou nebo odkazem, na který byl vázán název proměnné při vytvoření uzávěru. Umožňuje funkci přistupovat k těmto zachyceným proměnným prostřednictvím kopií jejich hodnot nebo odkazů uzávěru, i když je funkce vyvolána mimo jejich rozsah.

Abychom objasnili tento koncept, seznam 8 představuje skript JavaScript, který zavádí jednoduché uzavření. Skript je založen na zde uvedeném příkladu.

Výpis 8. Jednoduché uzavření (script6.js)

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

Výpis 8 definuje prvotřídní funkci s názvem přidat() s parametrem X a vnořená funkce partialAdd (). Vnořená funkce partialAdd () má přístup k X protože X je v přidat()lexikální rozsah. Funkce přidat() vrátí uzávěr, který obsahuje odkaz na partialAdd () a kopii okolního prostředí přidat(), ve kterém X má přidělenou hodnotu v konkrétním vyvolání přidat().

Protože přidat() vrací hodnotu typu funkce, proměnné přidat10 a přidat20 mají také typ funkce. The add10 (5) přiznání k vrácení 15 protože vyvolání přiděluje 5 k parametru y ve volání na partialAdd (), pomocí uloženého prostředí pro partialAdd () kde X je 10. The add20 (5) přiznání k vrácení 25 protože, i když také přiřadí 5 na y ve volání na partialAdd (), nyní používá jiné uložené prostředí pro partialAdd () kde X je 20. Tak, zatímco add10 () a add20 () použijte stejnou funkci partialAdd (), přidružená prostředí se liší a vyvolání uzávěrek se sváže X na dvě různé hodnoty ve dvou vyvoláních a vyhodnocení funkce na dva různé výsledky.

Spustit skript výpisu 8 (v script6.js) jak následuje:

Java RunScript script6.js

Měli byste dodržovat následující výstup:

15 25

Funkční programování s kari

Kari je způsob, jak přeložit vyhodnocení funkce s více argumenty do vyhodnocení ekvivalentní sekvence funkcí s jedním argumentem. Například funkce má dva argumenty: X a y. Currying transformuje funkci pouze na braní X a vrácení funkce, která trvá pouze y. Currying souvisí, ale není to stejné jako částečná aplikace, což je proces fixace řady argumentů na funkci, produkující další funkci menší arity.

Výpis 9 představuje skript JavaScript, který demonstruje kari.

Výpis 9. Currying v JavaScriptu (script7.js)

funkce násobení (x, y) {návrat x * y} funkce curried_multiply (x) {návrat funkce (y) {návrat x * y}} tisk (násobení (6, 7)) tisk (curried_multiply (6) (7)) var mul_by_4 = curried_multiply (4) tisk (mul_by_4 (2))

Skript představuje neprohlédnutý dva argumenty násobit() funkce, následovaná prvotřídní curried_multiply () funkce, která přijímá multiplikátorový argument X a vrátí uzávěr obsahující odkaz na anonymní funkci (která přijímá multiplikační argument y) a kopii okolního prostředí curried_multiply (), ve kterém X má přidělenou hodnotu při vyvolání curried_multiply ().

Zbytek skriptu nejprve vyvolá násobit() se dvěma argumenty a vytiskne výsledek. Potom vyvolá curried_multiply () dvěma způsoby:

  • curried_multiply (6) (7) výsledky v curried_multiply (6) první provedení. Vrácená uzávěrka provede anonymní funkci s uloženou uzávěrkou X hodnota 6 vynásobeno 7.
  • var mul_by_4 = curried_multiply (4) vykonává curried_multiply (4) a přiřadí uzávěr mul_by_4. mul_by_4 (2) provede anonymní funkci s uzávěrkou 4 hodnota a předaný argument 2.

Spustit skript výpisu 9 (v script7.js) jak následuje:

Java RunScript script7.js

Měli byste dodržovat následující výstup:

42 42 8

Proč používat kari?

Ve svém příspěvku na blogu „Proč kari pomáhá“ poznamenává Hugh Jackson, že „malé kousky lze snadno konfigurovat a znovu použít, bez nepořádku.“ Quora „Jaké jsou výhody kari ve funkčním programování?“ popisuje kari jako „levnou formu vkládání závislostí“, která usnadňuje proces mapování / filtrování / skládání (a obecně funkcí vyššího řádu). Toto Otázky a odpovědi také konstatuje, že kari „pomáhá nám vytvářet abstraktní funkce“.

Závěrem

V tomto kurzu jste se naučili některé základy funkčního programování. Použili jsme příklady v JavaScriptu ke studiu pěti základních technik funkčního programování, které budeme dále zkoumat pomocí kódu Java v části 2. Kromě prohlídek funkčních funkcí programování v Javě 8 vám druhá polovina tohoto tutoriálu pomůže začít myslet funkčněpřevedením příkladu objektově orientovaného kódu Java na jeho funkční ekvivalent.

Další informace o funkčním programování

Kniha Úvod do funkčního programování (Richard Bird a Philip Wadler, Prentice Hall International Series in Computing Science, 1992) mi připadala užitečná při osvojování základů funkčního programování.

Tento příběh, „Funkční programování pro vývojáře prostředí Java, část 1“, byl původně publikován společností JavaWorld.