Funkcionalno programiranje kolska 201920 godina Letnji semestar 11

  • Slides: 139
Download presentation
Funkcionalno programiranje Školska 2019/20 godina Letnji semestar 11. 6. 2021. Predmet: Funkcionalno programiranje 1

Funkcionalno programiranje Školska 2019/20 godina Letnji semestar 11. 6. 2021. Predmet: Funkcionalno programiranje 1

Lekcija 9: Komponovanje objekata i obrasci dizajna u FP 11. 6. 2021. Predmet: Funkcionalno

Lekcija 9: Komponovanje objekata i obrasci dizajna u FP 11. 6. 2021. Predmet: Funkcionalno programiranje 2

Sadržaj 1 1. 2. Objekat u java. Script-u Komponovanje objekata 3. Obrasci dizajna u

Sadržaj 1 1. 2. Objekat u java. Script-u Komponovanje objekata 3. Obrasci dizajna u FP-u 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 6. 2021. Agregacija Konkatenacija Delegacija Factory funkcije Funkcionalni miksini Prosleđivanje funkcija Filtri i pajpovi Akumulatori Osnovni obrasci dizajna u FP-u Memoizacija Lenjo instanciranje Konstruktor Prototip Modul Predmet: Funkcionalno programiranje 3

Sadržaj 2 1. Kompozibilni prilagođeni tipovi 2. Sočivo 3. Transdjuser 11. 6. 2021. Predmet:

Sadržaj 2 1. Kompozibilni prilagođeni tipovi 2. Sočivo 3. Transdjuser 11. 6. 2021. Predmet: Funkcionalno programiranje 4

Objekat u Java. Script-u • Objekat u Java. Script-u je kompozitni tip podataka bez

Objekat u Java. Script-u • Objekat u Java. Script-u je kompozitni tip podataka bez i jedne od implikacija iz domena klasno-baziranog programiranja ili prosleđivanja poruka. • Objekti u Java. Script-u mogu da podrže enkapsulaciju, prosleđivanje poruka, deljenje ponašanja putem metoda, čak i podklasni polimorfizam (korišćenjem lanca delegiranja). • Svaka se funkcija može dodeliti svojstvu. • Ponašanje objekata može se izgrađivati dinamički, a i zančenje objekata se može menjati u toku izvršavanja. • Java. Script podržava i enkapsulaciju, odnosno implementaciju privatnosti putem zatvaranja. • Ali je sve to OPCIONO. 11. 6. 2021. Predmet: Funkcionalno programiranje 5

Komponovanje objekata 1 • “Komponovanje objekata: Asembliranje ili komponovanje objekata da bi se dobilo

Komponovanje objekata 1 • “Komponovanje objekata: Asembliranje ili komponovanje objekata da bi se dobilo složenije ponašanje. ” ( Gang of Four, “Design Patterns: Elements of Reusable Object-Oriented Software”) • “Dati prednost kompoziciji objekata nad klasnim nasleđivanjem. ” (Gang of Four) • Klasno nasleđivanje je mehanizam za ponovnu iskoristivost koda u kome instance formiraju is-a relacije sa baznim klasama. (“Design Patterns”. ) • To dovodi do nefleksibilnosti, zbog tesnog sprezanja sa baznom klasom i nasleđivanja. 11. 6. 2021. Predmet: Funkcionalno programiranje 6

Komponovanje objekata 2 • Ima puno različitih načina za komponovanje objekata, a različiti načini

Komponovanje objekata 2 • Ima puno različitih načina za komponovanje objekata, a različiti načini kompozicije daju različite strukture kompozita i različite relacije među objektima. • Kada objekti zavise od objekata sa kojima su povezani, ti objekti su spregnuti što znači da promena jednog može da dovede do poremećaja u drugom objektu. • Druga utucajna stvar je što se u nefunkcionalnim programskim jezicima razdvajaju podaci i funkcije – sa podacima se mogu raditi jedne stvari, sa funkcijama druge. • Kada se objekti asembliraju putem kompozicije ni jedna od ove dve stvari nije važna – prosto se asembliraju strukture podataka, metode i svojstva kao podaci. 11. 6. 2021. Predmet: Funkcionalno programiranje 7

Glavne tehnike komponovanja objekata • Agregacija: Objekat se formira iz prebrojive kolekcije podobjekata –

Glavne tehnike komponovanja objekata • Agregacija: Objekat se formira iz prebrojive kolekcije podobjekata – rezultat je objekat koji sadrži druge objekte. • Svaki podobjekat zadržava svoj referecni identitet, što znači da se može destrukturirati iz agregacije bez gubitka informacija. • Konkatenacija: Objekat se formira dodavanjem novih svojstava postojećem objektu (može po jedna u trenutku ili kopiranjem iz postojećih objekata). • Delegacija: Objekat prosleđuje/delegira drugom objektu (neka svojstva). • Java. Script prototipovi su delegati: Instance Array prosleđuju pozive ugrađenih metoda objektu Array. prototype, objekti prosleđuju objektu Object. prototype, itd… 11. 6. 2021. Predmet: Funkcionalno programiranje 8

Agregacija • Agregacija je kada se objekat formira iz prebrojive kolekcije podobjekata. Agregat je

Agregacija • Agregacija je kada se objekat formira iz prebrojive kolekcije podobjekata. Agregat je objekat koji sadrži druge objekte. Svaki podobjekat u agregaciji zadržava svoj referencijalni identite i može se bez gubitaka destrukturirati iz agregata. • Primeri: Nizovi, mape, skupovi, grafovi, stabla: • DOM čvorovi (DOM može da sadrži čvorove-decu) • UI komponente (komponenta može da sadrži komponentedecu) • Kada koristiti: kada god postoje kolekcije objekata koji treba da dele zajedničke operacije: n. pr. , stekovi, redovi, stabla, grafovi, mašine stanja) ili kompozitni obrazac (kada jedna stavka treba da deli isti interfejs sa više stavki). 11. 6. 2021. Predmet: Funkcionalno programiranje 9

Agregacija: Primer nizovi const objs = [ { a: 'a', b: 'ab' }, {

Agregacija: Primer nizovi const objs = [ { a: 'a', b: 'ab' }, { b: 'b' }, { c: 'c', b: 'cb' } ]; const collection = (a, e) => a. concat([e]); const a = objs. reduce(collection, []); console. log('collection aggregation', a, a[1]. b, a[2]. c, 'enumerable keys: ', Object. keys(a)); • Vraća: collection aggregation [{"a": "a", "b": "ab"}, {"b": "b"}, {"c": "c", "b": "cb"}] b c enumerable keys: 0, 1, 2 11. 6. 2021. Predmet: Funkcionalno programiranje 10

Agregacija: Primer povezana lista po parovima const objs = [ { a: 'a', b:

Agregacija: Primer povezana lista po parovima const objs = [ { a: 'a', b: 'ab' }, { b: 'b' }, { c: 'c', b: 'cb' } ]; const pair = (a, b) => [b, a]; const l = objs. reduce. Right(pair, []); console. log( 'linked list aggregation', l, `enumerable keys: ${ Object. keys(l) }` ); 11. 6. 2021. Predmet: Funkcionalno programiranje 11

Vraća: linked list aggregation [ {"a": "a", "b": "ab"}, [ {"b": "b"}, [ {"c":

Vraća: linked list aggregation [ {"a": "a", "b": "ab"}, [ {"b": "b"}, [ {"c": "c", "b": "cb"}, [] ] enumerable keys: 0, 1 11. 6. 2021. Predmet: Funkcionalno programiranje 12

Konkatenacija • Konkatenacija je kada se objekat formira dodavanjem novih svojstava postojećem objektu. •

Konkatenacija • Konkatenacija je kada se objekat formira dodavanjem novih svojstava postojećem objektu. • Primeri: • Plugin-ovi se dodaju u j. Query. fn • Reduktori stanja (n. pr. , Redux) • Funkcionalni miksini • Kada koristiti: za progresivno asembliranje struktura podataka u vreme izvršenja (n. pr. spajanje JSON objekata, kreiranje ažuriranja za imutabilno stanje (spajanjem prethodnog stanja sa novim podacima, itd. . ). • Potencijalni problemi: • Pažljivo mutirati (ako nema druge) postojeće objekte. • Konkatenacija omogućuje oponašanje hijerarhija i is-a relacija. Pri tome treba komponovati male nezavisne objekte a ne nasleđivati svojstva od bazne instance i primenjivati diferencijalno nasleđivanje. • Implicitne međuzavisnosti komponenti. • Kolizije u imenima svojstava rezolviraju se redosledom konkatenacije : poslednji pobeđuje. To je korisno pri default/override ponašanju ali može biti problematično ako redosled ne bi trebao da bude od značaja. 11. 6. 2021. Predmet: Funkcionalno programiranje 13

Konkatenacija: Primer const objs = [ { a: 'a', b: 'ab' }, { b:

Konkatenacija: Primer const objs = [ { a: 'a', b: 'ab' }, { b: 'b' }, { c: 'c', b: 'cb' } ]; const concatenate = (a, o) => ({. . . a, . . . o}); const c = objs. reduce(concatenate, {}); console. log( 'concatenation', c, `enumerable keys: ${ Object. keys(c) }` ); // Vratiće // concatenation { a: 'a', b: 'cb', c: 'c' } enumerable keys: a, b, c 11. 6. 2021. Predmet: Funkcionalno programiranje 14

Delegacija • Delegacija je kada objekat prosleđuje ili delegira drugom objektu. • Primeri •

Delegacija • Delegacija je kada objekat prosleđuje ili delegira drugom objektu. • Primeri • Java. Script ugrađeni tipovi delegiraju pozive metoda uz prototipski lanac ( n. pr. , []. map() delegira objektu Array. prototype. map(), obj. has. Own. Property() delegira objektu Object. prototype. has. Own. Property(), itd. • Photoshop koristi delegate “smart objects” za referisanje na slike i resurse definisane u odvojenom fajlu. Promene u objektima na koje se smart referišu odslikavaju se u svim instancama smart objekta. 11. 6. 2021. Predmet: Funkcionalno programiranje 15

Delegacija: kada je koristiti 1. Konzervacija memorije: deljenjem identičnih svojstava/metoda među instancama. 2. Dinamičko

Delegacija: kada je koristiti 1. Konzervacija memorije: deljenjem identičnih svojstava/metoda među instancama. 2. Dinamičko ažuriranje više instanci: Svaki put kada više instanci objekta treba da dele identično stanje što može da zahteva dinamičko ažuriranje i da se promene odmah reflektuju na svaku instancu. 11. 6. 2021. Predmet: Funkcionalno programiranje 16

Delegacija: prednosti i nedostaci 1 • Delegacija se često koristi da imitira klasno nasleđivanje

Delegacija: prednosti i nedostaci 1 • Delegacija se često koristi da imitira klasno nasleđivanje u Java. Script-u (ključna reč extends), ali je to retko potrebno. • Delegacija može da se koristi da tačno imitira ponašanje i ograničenja klasnog nasleđivanja. U stvari, klasno nasleđivanje u Java. Scropt-u je i izgrađeno nad statičkim delegatima putem lanca prototipskog delegiranja. • Svojstva delegta su ne-enumerabilna pri korišćenju uobičajenih mehanizama poput Object. keys(instance. Obj). 11. 6. 2021. Predmet: Funkcionalno programiranje 17

Delegacija: prednosti i nedostaci 2 • Delegiranje štedi memoriju, ali degradira pretragu svojstava i

Delegacija: prednosti i nedostaci 2 • Delegiranje štedi memoriju, ali degradira pretragu svojstava i neke optimizacije JS endžina se isključuju za dinamičke delegate (dinamički delegati se menjaju nakon kreiranja). • Ali čak i u najsporijem slučaju, teško je očekivati da to bude usko grlo (u sekundi može da se izvrši više milona lookup operacija), osim ako pravite baš biblioteku za operacije sa objektima. • Treba praviti razliku između stanja instance i stanja delegata. • Deljeno stanje dinamičkih delegata nije instancno bezbedno, jer se promene dele među svim instancama i deljeno stanje na dinamičkim delegatima je obično (ne nužno uvek) bag. • ES 6 klase ne kreiraju dinamičke delegate u ES 6. Može da izgleda u Babel okruženju kao da to radi, ali u realnim ES 6 okruženjima ne radi. 11. 6. 2021. Predmet: Funkcionalno programiranje 18

Delegacija: Primer // Komponovanje objekata: delegiranje const objs = [ { a: 'a', b:

Delegacija: Primer // Komponovanje objekata: delegiranje const objs = [ { a: 'a', b: 'ab' }, { b: 'b' }, { c: 'c', b: 'cb' } ]; const delegate = (a, b) => Object. assign(Object. create(a), b); const d = objs. reduce. Right(delegate, {}); console. log( 'delegation', d, `enumerable keys: ${ Object. keys(d) }` ); // Vratiće: delegation { a: 'a', b: 'ab' } enumerable keys: a, b console. log(d. b, d. c); // Vratiće: ab c 11. 6. 2021. Predmet: Funkcionalno programiranje 19

Obrasci dizajna u funkcionalnom programiranju 11. 6. 2021. Predmet: Funkcionalno programiranje 20

Obrasci dizajna u funkcionalnom programiranju 11. 6. 2021. Predmet: Funkcionalno programiranje 20

Factory funkcije • Factory funkcija je bilo koja funkcija koja nije klasa ili konstruktor

Factory funkcije • Factory funkcija je bilo koja funkcija koja nije klasa ili konstruktor koji vraća (po pretpostavci nov) objekat. • U Java. Script-u svaka funkcija može da vrati objekat, ako to uradi bez ključne reči new, to je factory funkcija. • Factory funkcije su uvek bile privlačne u Java. Scriptu jer omogućuju da se lako prave instance objekata bez upuštanja u složenosti klasa i ključne reči new. 11. 6. 2021. Predmet: Funkcionalno programiranje 21

Factory funkcije • Ako treba kreirati više objekata, kombinuju se objektni literali i factory

Factory funkcije • Ako treba kreirati više objekata, kombinuju se objektni literali i factory funkcije • Factory funkcija omogućuje da se kreira željeni broj objekata. • Ako pravite, na primer, čet aplikaciju možete da imate objekat user koji predstavlja tekućeg korisnika i mnogo drugih user objekata koji predstavljaju sve druge prijavljene na čet da možete da prikažete imena i avatare. • Objekat user const user = { user. Name: 'echo', avatar: 'echo. png' }; 11. 6. 2021. Predmet: Funkcionalno programiranje 22

Factory funkcije: Primer factory funkcije • Objekat user pretvoren u create. User() factory: const

Factory funkcije: Primer factory funkcije • Objekat user pretvoren u create. User() factory: const create. User = ({ user. Name, avatar }) => ({ user. Name, avatar, set. User. Name (user. Name) { this. user. Name = user. Name; return this; } }); console. log(create. User({ user. Name: 'echo', avatar: 'echo. png' })); /* Vratiće: { "avatar": "echo. png", "user. Name": "echo", "set. User. Name": [Function set. User. Name] } */ 11. 6. 2021. Predmet: Funkcionalno programiranje 23

Miksini • Miksini su način komponovanja objekata gde se mogućnosti komponente “umešavaju” u kompozitni

Miksini • Miksini su način komponovanja objekata gde se mogućnosti komponente “umešavaju” u kompozitni objekat tako da svojstva svakog miksina postaju svojstva kompozitnog objekta. • Započinje se sa praznim objektom i umešavaju se mogućnosti tako da one proširuju kompozitni objekat. • Java. Script podržava dinamičko proširivanje objekata bez upotrebe klasa, pa je korišćenje miksina trivijalno i to je najuobičajeniji oblik nasleđivanja u Java. Script-u. 11. 6. 2021. Predmet: Funkcionalno programiranje 24

Miksini: Primer sladoled 1 const chocolate = { has. Chocolate: () => true };

Miksini: Primer sladoled 1 const chocolate = { has. Chocolate: () => true }; const caramel. Swirl = { has. Caramel. Swirl: () => true }; const pecans = { has. Pecans: () => true }; const ice. Cream = Object. assign({}, chocolate, caramel. Swirl, pecans); /* // or, if your environment supports object spread. . . const ice. Cream = {. . . chocolate, . . . caramel. Swirl, . . . pecans}; */ console. log(` has. Chocolate: ${ ice. Cream. has. Chocolate() } has. Caramel. Swirl: ${ ice. Cream. has. Caramel. Swirl() } has. Pecans: ${ ice. Cream. has. Pecans() } `); 11. 6. 2021. Predmet: Funkcionalno programiranje 25

Miksini: Primer - Sladoled 2 • Vraća se sledeće: has. Chocolate: true has. Caramel.

Miksini: Primer - Sladoled 2 • Vraća se sledeće: has. Chocolate: true has. Caramel. Swirl: true has. Pecans: true 11. 6. 2021. Predmet: Funkcionalno programiranje 26

Funkcionalno nasleđivanje: Šta je ? • Funkcionalno nasleđivanje je proces nasleđivanja svojstava primenom “ojačavajuće”

Funkcionalno nasleđivanje: Šta je ? • Funkcionalno nasleđivanje je proces nasleđivanja svojstava primenom “ojačavajuće” funkcije na instancu objekta. • Funkcija obezbeđuje doseg zatvaranja koji se može iskoristiti za privatizaciju nekih podataka. • “Ojačavajuća” funkcija koristi dinamičko proširivanje objekta da proširi instancu objekta novim svojstvima i metodama. • Sledi primer koji je dao Douglas Crockford, koji je i smislio termin: 11. 6. 2021. Predmet: Funkcionalno programiranje 27

Funkcionalno nasleđivanje: primer // Base objekt factory function base(spec) { var that = {};

Funkcionalno nasleđivanje: primer // Base objekt factory function base(spec) { var that = {}; // Kreira se prazan objekat that. name = spec. name; // Dodaje mu se svojstvo "name" return that; // Vraća se objekat } // Konstruisanje objekta-deteta, koji nasleđuje od "base" function child(spec) { var that = base(spec); // Kreiranje objekta putem "base" konstruktora that. say. Hello = function() { // proširi taj objekat return 'Zdravo, ja sam ' + that. name; }; return that; // Vrati ga } // Korišćenje var result = child({ name: 'funkcionalni objekat' }); console. log(result. say. Hello()); // 'Zdravo, ja sam funkcionalni objekat' 11. 6. 2021. Predmet: Funkcionalno programiranje 28

Funkcionalno nasleđivanje: suština • Ovde se kao prvi u nizu kreira bazni objekat a

Funkcionalno nasleđivanje: suština • Ovde se kao prvi u nizu kreira bazni objekat a ostali objekti se kreiraju kao njegovi naslednici tako što se taj bazni objekat proširuje. • Zato što je child() tesno spregnut sa base(), pri dodavanju naslednika (recimo, grandchild(), great. Grandchild(), itd…) ulazi se u probleme koji su svojstveni klasnom nasleđivanju. 11. 6. 2021. Predmet: Funkcionalno programiranje 29

Funkcionalni miksini • Miksini su oblik kompozicije objekata gde se svojstva komponenti mešaju u

Funkcionalni miksini • Miksini su oblik kompozicije objekata gde se svojstva komponenti mešaju u kompozitni objekat tako da svojstva svakog miksina postaju svojstva kompozitnog objekta. • Funkcionalni miksini su kompozibilne factory funkcije koje se povezuju u pajplajn; svaka funkcija dodaje nova svojstva/ponašanje kao radnici na tekućoj traci • Funkcionalni miksini ne zavise od, niti zahtevaju bazni factory ili konstruktor: Prosto se prosledi proizvoljan objekat u miksin i biće vraćena verzija tog objekta pojačana svojstvima prosleđenpg objekta. 11. 6. 2021. Predmet: Funkcionalno programiranje 30

Funkcionalni miksini: Primer const flying = o => { let is. Flying = false;

Funkcionalni miksini: Primer const flying = o => { let is. Flying = false; return Object. assign({}, o, { fly () { is. Flying = true; return this; }, is. Flying: () => is. Flying, land () {1 is. Flying = false; return this; } }); }; const bird = flying({}); // prosleđuje se objekat za proširivanje console. log( bird. is. Flying() ); // Vraća: false console. log( bird. fly(). is. Flying() ); // Vraća: true 11. 6. 2021. Predmet: Funkcionalno programiranje 31

Funkcionalni miksini: komponovanje • Može jednostavna kompozicija funkcija: const create. Duck = quack =>

Funkcionalni miksini: komponovanje • Može jednostavna kompozicija funkcija: const create. Duck = quack => quacking(quack)(flying({})); const duck = create. Duck('Quack!'); console. log(duck. fly(). quack()); • Može se napraviti i pipe const pipe = (. . . fns) => x => fns. reduce((y, f) => f(y), x); // ILI. . . // import pipe from `lodash/fp/flow`; const create. Duck = quack => pipe( flying, quacking(quack) )({}); const duck = create. Duck('Quack!'); console. log(duck. fly(). quack()); 11. 6. 2021. Predmet: Funkcionalno programiranje 32

Prednosti • Privatnost podataka/enkapsulacija • Nasleđivanje privatnog stanja • Višestruko nasleđivanje • Ne javlja

Prednosti • Privatnost podataka/enkapsulacija • Nasleđivanje privatnog stanja • Višestruko nasleđivanje • Ne javlja se diamond problem (neodređenost kolizije svojstava) – važi: poslednji pobeđuje • Nema base-class zahteva 11. 6. 2021. Predmet: Funkcionalno programiranje 33

Kada koristiti funkcionalne miksine • Upravljanje stanjem aplikacije. • Presečni (cross-cutting ) zadaci, n.

Kada koristiti funkcionalne miksine • Upravljanje stanjem aplikacije. • Presečni (cross-cutting ) zadaci, n. pr. , centralizovano logovanje. • Kompozibilni funkcionalni tipovi podataka, n. pr. Java. Script Array tip implementira polugrupu, funktor, foldable… • Neke algebarske strukture mogu se izvesti iz drugih algebarskih struktura, što znači da se određene derivacije mogu komponovati u novi tip bez posebnog prilagođavanja. 11. 6. 2021. Predmet: Funkcionalno programiranje 34

Nedostaci miksina i kako ih izbeći • Čiste funkcije su “zakon”: većina problema se

Nedostaci miksina i kako ih izbeći • Čiste funkcije su “zakon”: većina problema se elegantno rešava korišćenjem čistih funkcija. • Za funkcionalne miksine ne važi isto. Oni sami mogu da izazovu probleme. Da bi se problemi izbegli treba: • Slediti prioritete: funkcije > factories > funkcionalni miksini > klase • Izbegavati kreiranje is-a relacija među objektima, miksinima, ili tipovima podataka • Izbegavati implicitne zavisnosti među miksinima – miksini treba da budu samosadržavajući • Biti svestan da “Funkcionalni miksini” ne znači “funkcionalno programiranje” 11. 6. 2021. Predmet: Funkcionalno programiranje 35

Funkcionalni miksini & Funkcionalno programiranje • “Funkcionalan” u kontekstu funkcionalnih miksina nema uvek istu

Funkcionalni miksini & Funkcionalno programiranje • “Funkcionalan” u kontekstu funkcionalnih miksina nema uvek istu konotaciju čistote kao u “funkcionalnom programiranju”. • Funkcionalni miksini obično se koriste u OOP stilu sa svim svojim bočnim efektima. • Mnogi funkcionalni miksini ne poštuju princip imutabilnosti – menjaju objekt argument koji im se prosleđuje. • Takođe, neki programeri preferiraju stil funkcionalnog programiranja i ne održavaju identitetsku referencu na objekat koji se prosleđuje. 11. 6. 2021. Predmet: Funkcionalno programiranje 36

Funkcionalni miksini & Funkcionalno Programiranje • Miksine i kod koji ih koristi treba pisati

Funkcionalni miksini & Funkcionalno Programiranje • Miksine i kod koji ih koristi treba pisati u slučaju mešavine oba stila (FP i OOP). • To znači da, ako treba da vratite instancu objekta, uvek treba vratiti this a ne referencu na instancu u zatvaranju – u FP kodu su velike šanse da to neće referencirati isti objekat. • Takođe, uvek treba pretpostaviti da će instanca objekta biti kopirana dodelom pomoću Object. assign() ili {. . . object, . . . spread} sintakse. • To znači da ako postavite neprebrojiva svojstva, to neće da radi na finalnom objektu kao u primeru koji sledi: 11. 6. 2021. Predmet: Funkcionalno programiranje 37

Neprebrojivost: primer const a = Object. define. Property({}, 'a', { enumerable: false, value: 'a'

Neprebrojivost: primer const a = Object. define. Property({}, 'a', { enumerable: false, value: 'a' }); const b = { b: 'b' }; console. log({. . . a, . . . b}); // Vraća: { b: 'b' } 11. 6. 2021. Predmet: Funkcionalno programiranje 38

Sadržaj • Osnovni obrasci dizajna • Prosleđivanje funkcija • Filtri i pajpovi • Akumulatori

Sadržaj • Osnovni obrasci dizajna • Prosleđivanje funkcija • Filtri i pajpovi • Akumulatori • Memoizacija 11. 6. 2021. Predmet: Funkcionalno programiranje 39

Osnovni obrasci dizajna u FP • Iteriranje je nerazdvojni deo svakog programiranja. • Funkcije

Osnovni obrasci dizajna u FP • Iteriranje je nerazdvojni deo svakog programiranja. • Funkcije višeg reda su osnovni mehanizam za komponovanje softvera u funkcionalnom programiranju. • Čiste funkcije i imutabilnost su osnovne karakteristike funkcionalnog programiranja. • Iteriranje u funkcionalnom programiranju oslanja se na “sveto trojstvo” funkcija višeg reda: map, filter, i reduce. 11. 6. 2021. Predmet: Funkcionalno programiranje 40

Funkcija map: Init + each + push -> map • Primer: konverzija jedne liste

Funkcija map: Init + each + push -> map • Primer: konverzija jedne liste u drugu listu • Proceduralno: let uppercase. Names = [] for (let name of ['milu', 'rantanplan']) { uppercase. Names. push(name. to. Upper. Case()) } console. log(uppercase. Names) // ['MILU', 'RANTANPLAN'] • Funkcionalno: const uppercase. Names = ['milu', 'rantanplan']. map(name => name. to. Upper. Case()) console. log(uppercase. Names) // ['MILU', 'RANTANPLAN'] 11. 6. 2021. Predmet: Funkcionalno programiranje 41

Funkcija filter: Init + each + uslovni push -> filter • Proceduralno: let filtered.

Funkcija filter: Init + each + uslovni push -> filter • Proceduralno: let filtered. Names = [] for (let name of ['milu', 'rantanplan']) { if (name. length === 4) { filtered. Names. push(name) } } console. log(filtered. Names) // ['milu'] • Funkcionalno: const filtered. Names = ['milu', 'rantanplan']. filter(name => name. length === 4) console. log(filtered. Names) // ['milu'] 11. 6. 2021. Predmet: Funkcionalno programiranje 42

Funkcija reduce: Init + each + accumulate -> reduce • Za listu stringova vraćamo

Funkcija reduce: Init + each + accumulate -> reduce • Za listu stringova vraćamo zbir dužina svih stringova iz liste. • Proceduralno: let sum. Of. Lengths = 0 for (let name of ['milu', 'rantanplan']) { sum. Of. Lengths += name. length } console. log(sum. Of. Lengths) // 14 • Funkcionalno: const total = (acc, len) => len + acc const sum. Of. Lengths = ['milu', 'rantanplan']. map(v=>v. length). reduce(total, 0) console. log(sum. Of. Lengths) // 14 11. 6. 2021. Predmet: Funkcionalno programiranje 43

Funkcija scan: Init + each + accumulate + push -> scan • Za listu

Funkcija scan: Init + each + accumulate + push -> scan • Za listu stringova vraćamo istoriju formiranja zbira dužina svih stringova iz liste. • Proceduralno: let lengths = [0] let total. Length = 0 for (let name of ['milu', 'rantanplan']) { total. Length += name. lengths. push(total. Length) } console. log(lengths) // [0, 4, 14] • Funkcionalno: const total = (acc, item) => acc + item. length const lengths = ['milu', 'rantanplan']. scan(total, 0) console. log(lengths) //[0, 4, 14] 11. 6. 2021. Predmet: Funkcionalno programiranje 44

Implementacija funkcije scan() Array. prototype. scan = function (callback, initial. Value) { const append.

Implementacija funkcije scan() Array. prototype. scan = function (callback, initial. Value) { const append. Aggregate = (acc, item) => { const aggregate = acc[acc. length-1] //uzmi poslednji const new. Aggregate = callback(aggregate, item) return [. . . acc, new. Aggregate] } const accumulator = [initial. Value] return this. reduce(append. Aggregate, accumulator) } 11. 6. 2021. Predmet: Funkcionalno programiranje 45

Implementacija funkcije scan(): objašnjenje • U ovom slučaju, umesto da se povratni poziv samo

Implementacija funkcije scan(): objašnjenje • U ovom slučaju, umesto da se povratni poziv samo direktno prosledu prosledi u reduce, novi ridjuser append. Aggregate omotava se oko povratnog poziva. append. Aggregate prima niz koji sadrži tekuće totale (iz svakog već urađenog koraka) iz akumulatora i kreira kopiju u koju dodaje i poslednji tekući total. • Na taj način se, umesto jedne povratne vrednosti iz redukcije, dobija niz svih međuvrednosti. 11. 6. 2021. Predmet: Funkcionalno programiranje 46

Funkcija mash: Init + each + hash -> mash • Konvertuje se lista u

Funkcija mash: Init + each + hash -> mash • Konvertuje se lista u mapu parova ključ-vrednost (za svaki par, ključ je element liste, a vrednost rezultat neke transformacije tog elementa). • U primeru koji sledi konvertuje se lista stringova u objekat koji ima string za ključ a dužinu stringa za vrednost tog ključa. 11. 6. 2021. Predmet: Funkcionalno programiranje 47

Proceduralno: const items = ['functional', 'programming', 'rules'] const process = item => item. length

Proceduralno: const items = ['functional', 'programming', 'rules'] const process = item => item. length let hash = {} for (let item of items) { hash[item] = process(item) } console. log(hash) //{functional: 10, programming: 11, rules: 5} 11. 6. 2021. Predmet: Funkcionalno programiranje 48

Funkcionalno: const items = ['functional', 'programming', 'rules'] const mashed = items. mash(item => [item,

Funkcionalno: const items = ['functional', 'programming', 'rules'] const mashed = items. mash(item => [item, item. length]) console. log(mashed) // {functional: 10, programming: 11, rules: 5} //a može i ovako: const also. Mashed = items. map(item => [item, item. length]). mash() console. log(also. Mashed) // {functional: 10, programming: 11, rules: 5} 11. 6. 2021. Predmet: Funkcionalno programiranje 49

Implementacija funkcije mash() Array. prototype. mash = function(callback) { const add. Key. Value. Pair

Implementacija funkcije mash() Array. prototype. mash = function(callback) { const add. Key. Value. Pair = (acc, item) => { const [key, value] = callback ? callback(item) : item return {. . . acc, [key]: value} } return this. reduce(add. Key. Value. Pair, {}) } 11. 6. 2021. Predmet: Funkcionalno programiranje 50

Implementacija funkcije mash(): objašnjenje • Ovde se koristi pristup kao i za implementaciju funkcije

Implementacija funkcije mash(): objašnjenje • Ovde se koristi pristup kao i za implementaciju funkcije scan. • Kao ulaz u reduce prosleđuje se add. Key. Value. Pair. Svaki puta kada reduce izvrši taj povratni poziv, on će da kreira novi objekat koji sadrži postojeće vrednosti u akumulatoru (parove ključ-vrednost) zajedno sa novom vrednošću koja odgovara tekućem paru ključ-vrednost 11. 6. 2021. Predmet: Funkcionalno programiranje 51

Neke napomene • Preporučuje se uzdržavanje od modifikacija Array. prototype-a (kao u primerima scan

Neke napomene • Preporučuje se uzdržavanje od modifikacija Array. prototype-a (kao u primerima scan i mash) • Preporučuje se i uzdržavanje od izmišljanja točka – biblioteke kao što je Ramda sadrže dobre implementacije pa ih treba koristiti. 11. 6. 2021. Predmet: Funkcionalno programiranje 52

Prosleđivanje funkcije • Iskustva i pretpostavke • Suštinska pretpostavka funkcionalnog programiranja je da funkcije

Prosleđivanje funkcije • Iskustva i pretpostavke • Suštinska pretpostavka funkcionalnog programiranja je da funkcije ne bi trebale da menjaju globalno stanje (programa). • Funkcija može da menja svoje lokalne vrednosti, ali ne sme da menja ništa van funkcije. • Funkcije su referencijalno transparentne i bočni efekti moraju da budu kontrolisani (poželjno eliminisani). • U java. Script-u, funkcije su “građani prvog reda”: mogu se dodeljivati promenljivima ili prosleđivati kako bilo koja druga varijabla, mogu se tretirati čak i kao objekti i stringovi. • Zbog jedno-nitne prirode Java. Script-a, povratni pozivi su uobičajena konvencija i javljaju se u svim okruženjima (klijent i server). • Obrazac: • Taj metod prosleđivanja brojnih funkcija drugim funkcijama sugeriše obrazac koji predstavlja izuzetno dobar način za obezbeđenje ekspanzionih 1 tačaka za klase. Na primer, pozivu funkcije može se proslediti objekat koji definiše više svojstava među kojima su povratni pozivi za uspešno izvršavanje i otkaz. 1 ekspanzija kopira nasleđene metode u podklasu 11. 6. 2021. Predmet: Funkcionalno programiranje 53

Primer implementacije: Turizam u Igri prestola • Na kontinentu Westeros, turizma skoro da i

Primer implementacije: Turizam u Igri prestola • Na kontinentu Westeros, turizma skoro da i nema. • To je zbog toga što banditi ubijaju tursite, a turisti se upetljavaju u regionalne konflikte. • Uprkos tome, neki preduzetnici počeli su da oglašavaju Veliku Westeros turu za obilazak glavnih atrakcija. • Jedan matematici naklonjen član Turističkog odbora nazvao je turu Hamiltonianskom turom zato što se svaka atrakcija posećuje samo jednom. 11. 6. 2021. Predmet: Funkcionalno programiranje 54

Hamiltonian. Tour klasa: šta obezbeđuje i kakav je interfejs • Klasa Hamiltonian. Tour obezbeđuje

Hamiltonian. Tour klasa: šta obezbeđuje i kakav je interfejs • Klasa Hamiltonian. Tour obezbeđuje options objekat koji dozvoljava definiciju options objekta. • Taj objekat sadrži različita mesta kojima se može pridružiti povratni poziv (callback). • U “turističkom” slučaju interfejs bi mogao da izgleda ovako: export class Hamiltonian. Tour. Options{ on. Tour. Start: Function; on. Entry. To. Attraction: Function; on. Exit. From. Attraction: Function; on. Tour. Completion: Function; } 11. 6. 2021. Predmet: Funkcionalno programiranje 55

Hamiltonian. Tour klasa: kod 1 var Hamiltonian. Tour = (function () { function Hamiltonian.

Hamiltonian. Tour klasa: kod 1 var Hamiltonian. Tour = (function () { function Hamiltonian. Tour(options) { this. options = options; } Hamiltonian. Tour. prototype. Start. Tour = function () { if (this. options. on. Tour. Start && typeof (this. options. on. Tour. Start) === "function") this. options. on. Tour. Start(); this. Visit. Attraction("King's Landing"); this. Visit. Attraction("Winterfell"); this. Visit. Attraction("Mountains of Dorne"); this. Visit. Attraction("Eyrie"); if (this. options. on. Tour. Completion && typeof (this. options. on. Tour. Completion) === "function") this. options. on. Tour. Completion(); }; 11. 6. 2021. Predmet: Funkcionalno programiranje 56

Hamiltonian. Tour klasa: kod 2 Hamiltonian. Tour. prototype. Visit. Attraction = function (Attraction. Name)

Hamiltonian. Tour klasa: kod 2 Hamiltonian. Tour. prototype. Visit. Attraction = function (Attraction. Name) { if (this. options. on. Entry. To. Attraction&&typeof (this. options. on. Entry. To. Attraction) === "function") this. options. on. Entry. To. Attraction(Attraction. Name); //radi sve što se radi u atrakciji if (this. options. on. Exit. From. Attraction&&typeof (this. options. on. Exit. From. Attraction) === "function") this. options. on. Exit. From. Attraction(Attraction. Name); }; return Hamiltonian. Tour; })(); var tour = new Hamiltonian. Tour({ on. Entry. To. Attraction: function(cityname){console. log("I'm delighted to be in " + cityname)}}); tour. Start. Tour(); 11. 6. 2021. Predmet: Funkcionalno programiranje 57

Hamiltonian. Tour klasa: izlaz • Izlaz prethodnog koda je: I'm delighted to be in

Hamiltonian. Tour klasa: izlaz • Izlaz prethodnog koda je: I'm delighted to be in King's Landing I'm delighted to be in Winterfell I'm delighted to be in Mountains of Dorne I'm delighted to be in Eyrie 11. 6. 2021. Predmet: Funkcionalno programiranje 58

Filtri i pajpovi • Iskustva i pretpostavke • Formiranje sekvence programa gde je izlaz

Filtri i pajpovi • Iskustva i pretpostavke • Formiranje sekvence programa gde je izlaz iz jednog programa ulaz u sledeći program je izuzetno moćan mehanizam za izvršavanje vrlo složenih funkcionalnosti. • Primer je komandna linija (recimo u Unix-u) gde se ovakva sekvenca formira pomoću znaka “|” kojim se povezuju program koji proizvodi neki izlaz i program koji taj izlaz preuzima na svoj ulaz. • Neki jezici obezbeđuju sintaksu za ovakav obrazac, recimo #F: [1. . 10] |>List. filter (fun n -> n% 2 = 0); ; 10. 5 |> float |>Math. Sqrt |>Math. Round ili C: Math. Round(Math. Sqrt((float)10. 5)) • Java. Script omogućuje ulančavanje funkcija. • Obrazac: • Ulančavanje funkcija u sekvencu gde je izlaz jedne funkcije ulaz u sledeću funkciju zove se pipe (pajp). 11. 6. 2021. Predmet: Funkcionalno programiranje 59

Filtri i pajpovi: Implementacija Array. prototype. where = function (inclusion. Test) { var results

Filtri i pajpovi: Implementacija Array. prototype. where = function (inclusion. Test) { var results = []; for (var i = 0; i<this. length; i++) { if (inclusion. Test(this[i])) results. push(this[i]); } return results; }; 11. 6. 2021. Predmet: Funkcionalno programiranje 60

Primer korišćenja: fluent interface • Može se lako filtrirati niz: var items = [1,

Primer korišćenja: fluent interface • Može se lako filtrirati niz: var items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; items. where(function(thing){ return thing % 2 ==0; }); // vraća [2, 4, 6, 8, 10] • Pozivi metode mogu se vrlo lako ulančati: var items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; items. where(function(thing){ return thing % 2 ==0; }). where(function(thing){ return thing % 3 == 0; }); vraća: [6] 11. 6. 2021. Predmet: Funkcionalno programiranje 61

Primer primene: projekcija na bazi proizvoljne projekcione funkcije • Još jedna implementacija obrasca je

Primer primene: projekcija na bazi proizvoljne projekcione funkcije • Još jedna implementacija obrasca je vrlo korisna: Array. prototype. select=function(projection){ var results = []; for(var i = 0; i<this. length; i++){ results. push(projection(this[i])); } return results; }; • Ova metoda omogućuje da se projektovanje originalnih stavki vrši na bazi proizvoljne projekcione funkcije. 11. 6. 2021. Predmet: Funkcionalno programiranje 62

Primer korišćenja: projekcija var children = [ { id: 1, Name: "Rob" }, {

Primer korišćenja: projekcija var children = [ { id: 1, Name: "Rob" }, { id: 2, Name: "Sansa" }, { id: 3, Name: "Arya" }, { id: 4, Name: "Brandon" }, { id: 5, Name: "Rickon" }]; var filtered. Children = children. where(function (x) { return x. id % 2 == 0; }). select(function (x) { return x. Name; }); • Ovaj kod će da napravi novi niz koji sadrži samo stavke sa parnim vrednostima ID-a i ne sadrži potpune originalne objekte, već samo imena: "Sansa" i "Brandon". 11. 6. 2021. Predmet: Funkcionalno programiranje 63

Imperativno je mnogo nečitljiviji var children = [{ id: 1, Name: "Rob" }, {

Imperativno je mnogo nečitljiviji var children = [{ id: 1, Name: "Rob" }, { id: 2, Name: "Sansa" }, { id: 3, Name: "Arya" }, { id: 4, Name: "Brandon" }, { id: 5, Name: "Rickon" }]; var even. Ids = []; for(var i=0; i<children. length; i++) { if(children[i]. id%2==0) even. Ids. push(children[i]); } var names = []; for(var i=0; i< even. Ids. length; i++) { names. push(even. Ids[i]. name); } 11. 6. 2021. Predmet: Funkcionalno programiranje 64

Akumulatori - redukcija • Iskustva i pretpostavke • Rekurzija je vrlo popularna u FP

Akumulatori - redukcija • Iskustva i pretpostavke • Rekurzija je vrlo popularna u FP jezicima i mnogi od njih pružaju mogućnost tail call optimizacije. • Jezici koji podržavaju ovu optimizaciju ponovno koriste stek i time povećavaju efikasnost. • Na taj način se može zamenuti većina petlji rekurzijom. • Problem sa for petljom je što je kontrolni tok kroz petlju mutabilan. • Obrazac: • Umesto for petlje koristi se akumulator – mehanizam koji omogućuje kombinovanje više vrednosti u jednu vrednost – dakle, redukcija. 11. 6. 2021. Predmet: Funkcionalno programiranje 65

Primer primene obrasca: poreski obveznici • Poreski obveznici su modelovani na sledeći način: var

Primer primene obrasca: poreski obveznici • Poreski obveznici su modelovani na sledeći način: var peasants = [ {name: "Jory Cassel", taxes. Owed: 11, bank. Balance: 50}, {name: "Vardis Egen", taxes. Owed: 15, bank. Balance: 20}]; • Sledeći kod prima listu stavki, akumulatorsku vrednost i funkciju koja projektuje (mapira) vrednost koju treba integrisati u akumulaciju. Tax. Collector. prototype. collect = function (items, value, projection) { if (items. length > 1) return projection(items[0]) + this. collect(items. slice(1), value, projection); return projection(items[0]); }; • Projekciona funkcija može da izgleda ovako function (item) { return Math. min(item. money. Owed, item. bank. Balance); } 11. 6. 2021. Predmet: Funkcionalno programiranje 66

Šta se tu dešava • Za iniciranje se prosleđuje inicijalna vrednost akumulatora zajedno sa

Šta se tu dešava • Za iniciranje se prosleđuje inicijalna vrednost akumulatora zajedno sa nizom i projekcijom (funkcijom koja će biti osnova za transformaciju). • Svaki prolaz kroz niz smanjuje mu dimenzionalnost i to bez i jedne mutabilne vrednosti. • Akumulacija može da bude proizvoljna funkcija (dodavanje stringa, sabiranje, . . ). Pri tome se izbegavaju bočni efekti. 11. 6. 2021. Predmet: Funkcionalno programiranje 67

Memoizacija • Memoizacija je optimizaciona tehnika koj se koristi za optimizaciju performanse. • Vrši

Memoizacija • Memoizacija je optimizaciona tehnika koj se koristi za optimizaciju performanse. • Vrši keširanje rezultata tako da se izbegnu nepotrebna računanja: ako se funkcija pozove sa argumentima za koje je računanje već izvršeno i rezultat keširan, biće vraćen taj keširani rezultat bez ponovnog izvršavanja računanja. • Posebno je korisna u rekurzivnim funkcijama jer je u rekurziji verovatnije da će se pojaviti pozivi sa istim argumentima. Standardan primer je računanje faktorijela 11. 6. 2021. Predmet: Funkcionalno programiranje 68

Zašto memoizacija function factorial(num) { if(num === 1) { return 1 }; return num

Zašto memoizacija function factorial(num) { if(num === 1) { return 1 }; return num * factorial(num - 1); } • Ako se pozove factorial(3), biće izvršeni funkcijski pozivi factorial(3), factorial(2), i factorial(1). Ako funkciju memoiziramo, drugi factorial(3) poziv neće trebati da radi rekurziju jer može jednostavno da vrati keširani rezultat. • Prava dobit je ako se pozove factorial(4), jer se samo uzme keširana vrednost factorial(3) i pomnoži se sa 4. 11. 6. 2021. Predmet: Funkcionalno programiranje 69

Faktorijel sa memoizacijom var factorial = memoize(function(num) { console. log('radim za faktorijel(' + num

Faktorijel sa memoizacijom var factorial = memoize(function(num) { console. log('radim za faktorijel(' + num + ')'); if(num === 1) { return 1 }; return num * factorial(num - 1); }); // Prvi poziv console. log(factorial(3)); //=> working for factorial(3) //=> working for factorial(2) //=> working for factorial(1) //=> 6 // Sledeći pozivi console. log(factorial(3)); //=> 6 // ’kratak spoj’ za više faktorijel pozive console. log(factorial(4)); //=> working for factorial(4) //=> 24 console. log(factorial(7)); 11. 6. 2021. Predmet: Funkcionalno programiranje 70

Memoizacija i broj argumenata funkcije • U realnosti većina funkcija prima više argumenata što

Memoizacija i broj argumenata funkcije • U realnosti većina funkcija prima više argumenata što usložnjava indeksiranje keša. • Za memoiziranje funkcije sa više argumenata moguća su dva pristupa: • uvođenje višedimenzionalnog keša, ili • kombinovanje svih argumenata u jedan indeks. 11. 6. 2021. Predmet: Funkcionalno programiranje 71

Multidimenzionalni pristup • U ovom pristupu keš nije jedan objekat, već postaje hijerarhija objekata

Multidimenzionalni pristup • U ovom pristupu keš nije jedan objekat, već postaje hijerarhija objekata i svaka dimenzija se indeksira jednim parametrom. • U sledećem primeru implementira se miltidimenzionalni keš za Fibonačijev niz. • U primeru funkcija prihvata dodatni argument “x”koji ništa ne radi u samom računanju. • Pri svakom pozivu funkcije, kod proverava da li postoji dimenzija “x” i inicijalizuje je ako ne postoji. • Od te tačke na dalje, dimenzija “x” se koristi da kešira vrednosti za “n”. • Rezultat je da se, na primer, pozivi funkcije fibonacci(“foo”, 3) i fibonacci(“bar”, 3) tretiraju kao različiti rezultati. 11. 6. 2021. Predmet: Funkcionalno programiranje 72

Multidimenzionalni pristup: kod var fibonacci = (function() { var memo = {}; function f(x,

Multidimenzionalni pristup: kod var fibonacci = (function() { var memo = {}; function f(x, n) { var value; memo[x] = memo[x] || {}; if (x in memo && n in memo[x]) { value = memo[x][n]; } else { if (n === 0 || n === 1) value = n; else value = f(x, n - 1) + f(x, n - 2); memo[x][n] = value; } return f; })(); 11. 6. 2021. Predmet: Funkcionalno programiranje 73

Jedinstven keš objekat • Alternativa višedimenzionom keširanju je jedan keš objekat koji se indeksira

Jedinstven keš objekat • Alternativa višedimenzionom keširanju je jedan keš objekat koji se indeksira kombinacijom svih argumenata funkcije. • Primenom ovog pristupa argumenti se transformišu u niz i zatim koriste za indeksiranje keša. • Svaka funkcija ima ugrađeni objekat sa imenom arguments 1 koji sadrži argumente prosleđene funkciji. • arguments je nizoliki objekat 2 i ne može se koristiti za indeksiranje keša pre no što se transformiše u “pravi” niz što se može uraditi metodom slice() tipa array. • Zatim se array reprezentacija koristi za indeksiranje keša na prethodno opisani način kao u kodu koji sledi. 1 Od ES 6 specifikacije ovo je depresirana mogućnost i preporučuje se korišćenje rest argumenata 2 Tip sličan nizu, ali bez ugrađenih metoda kao što su for. Each() i map(). 11. 6. 2021. Predmet: Funkcionalno programiranje 74

Jedinstven keš objekat: primer var fibonacci = (function() { var memo = {}; var

Jedinstven keš objekat: primer var fibonacci = (function() { var memo = {}; var slice = Array. prototype. slice; function f(x, n) { var args = slice. call(arguments); var value; if (args in memo) { value = memo[args]; } else { if (n === 0 || n === 1) value = n; else value = f(x, n - 1) + f(x, n - 2); memo[arguments] = value; } return f; })(); 11. 6. 2021. Predmet: Funkcionalno programiranje 75

Jedinstven keš objekat: napomene • U prethodnom kodu ima još jedna finesa koju je

Jedinstven keš objekat: napomene • U prethodnom kodu ima još jedna finesa koju je korisno zapaziti (i zapamtiti). • Definisana je dodatna varijabla slice kao referenca na slice() metodu tipa array. • Skladištenjem te reference može se izbeći opterećenje učestalog računanja Array. prototype. slice(). Metoda call() se tada koristi da primeni slice() na objekat arguments. 11. 6. 2021. Predmet: Funkcionalno programiranje 76

Keširanje objektnih argumenata • Memoizaciona šema koja je napravljena ne rukuje objektima na dobar

Keširanje objektnih argumenata • Memoizaciona šema koja je napravljena ne rukuje objektima na dobar način. • Kada se objekti koriste kao indeks, oni se prvo konvertuju u string reprezentaciju poput [object Object]. • To uzrokuje nekorektno mapiranje više objekata na istu keš lokaciju. • Ovo ponašanje može se korigovati tako što će se izvršiti stringifikacija objektnih argumenata pre indeksiranja. • Na žalost, to usporava proces memoizacije. 11. 6. 2021. Predmet: Funkcionalno programiranje 77

Generička funkcija za memoizaciju sa objektnim parametrom var foo = (function() { var memo

Generička funkcija za memoizaciju sa objektnim parametrom var foo = (function() { var memo = {}; function f(obj) { // Objektni argument se strnigifikuje ( JSON. stringify()) var index = JSON. stringify(obj); if (index in memo) { return memo[index]; } else { // memoized function contents return (memo[index] = function_value); } } 11. 6. 2021. Predmet: Funkcionalno programiranje 78

Kako memoizacija function memoize(func) { var cache = {}; return function() { var key

Kako memoizacija function memoize(func) { var cache = {}; return function() { var key = JSON. stringify(arguments); if(cache[key]) { return cache[key]; } else { var val = func. apply(this, arguments); cache[key] = val; return val; } }; } 11. 6. 2021. Predmet: Funkcionalno programiranje 79

Naprednija memoizacija • U prethodnom primeru napravili smo memoizaciju koja radi tako što jednostavno

Naprednija memoizacija • U prethodnom primeru napravili smo memoizaciju koja radi tako što jednostavno omotamo datu funkcijom memoizacije. Rezultati se keširaju za pozive sa istim argumentima. • To je lepo, ali šta ako imamo situaciju u kojoj argumenti nisu jedine zavisnosti. • Šta ako treba memoizirati metod nekog objekta koja se oslanja i na argumente i na svojstva tog objekta? • Kako uzeti u obzir te druge zavisnosti? • Ako se ništa ne uradi, funkcija memoizacije može da uzrokuje dobijanje nekorektnih vrednosti (ako se te druge zavisnosti promenu). • Potreban nam je mehanizam za modifikujemo keš i za te zavisnosti. 11. 6. 2021. Predmet: Funkcionalno programiranje 80

Naprednija memoizacija: primer 1 • Neka je dat model Person koji ima argumente first.

Naprednija memoizacija: primer 1 • Neka je dat model Person koji ima argumente first. Name i last. Name kao i metodu full. Name koja prima opcioni argument titulu (title) i izdaje puno ime osobe: function memoize() {. . . } function Person(first. Name, last. Name) { this. first. Name = first. Name; this. last. Name = last. Name; this. full. Name = memoize(function(title) { return title + ' ' + this. first. Name + ' ' + this. last. Name; }); } 11. 6. 2021. Predmet: Funkcionalno programiranje 81

Naprednija memoizacija: primer 2 • Ono što treba da se uradi da se memoizira

Naprednija memoizacija: primer 2 • Ono što treba da se uradi da se memoizira ta funkcija nad objektom Person jeste da se funkcija memoize prilagodi tako da prima i drugi argument deps. Func će biti funkcija koja vraća niz zavisnosti. Nakon toga se može koristiti deps. Func kao i func za sračunavanje jedinstvenog ključa u našem hešu. 11. 6. 2021. Predmet: Funkcionalno programiranje 82

Naprednija memoizacija: primer 3 function memoize(func, deps. Func) { var cache = {}; return

Naprednija memoizacija: primer 3 function memoize(func, deps. Func) { var cache = {}; return function() { var key = JSON. stringify([deps. Func(), arguments]); if(cache[key]) { return cache[key]; } else { var val = func. apply(this, arguments); cache[key] = val; return val; } }; } 11. 6. 2021. Predmet: Funkcionalno programiranje 83

Naprednija memoizacija: primer 4 function Person(first. Name, last. Name) { this. first. Name =

Naprednija memoizacija: primer 4 function Person(first. Name, last. Name) { this. first. Name = first. Name; this. last. Name = last. Name; } 11. 6. 2021. this. full. Name = memoize( // calculation function(title) { console. log('working. . . '); return title + ' ' + this. first. Name + ' ' + this. last. Name; }, // dependencies function() { return [this. first. Name, this. last. Name]; }. bind(this)); Predmet: Funkcionalno programiranje 84

Naprednija memoizacija: primer 5 // Kreira se novi objekat Person var person = new

Naprednija memoizacija: primer 5 // Kreira se novi objekat Person var person = new Person('Jonathan', 'Lehman'); // Prvi poziv memoizovane funkcije uradi posao console. log(person. full. Name('Mr. ')); //=> radi se //=> Mr. Jonathan Lehman // sukcesivni pozivi console. log(person. full. Name('Mr. ')); //=> Mr. Jonathan Lehman 11. 6. 2021. Predmet: Funkcionalno programiranje 85

Naprednija memoizacija: primer 6 // Mora se uraditi posao ako se menjaju // zavisnosti

Naprednija memoizacija: primer 6 // Mora se uraditi posao ako se menjaju // zavisnosti ili argumenti // promena argumenata console. log(person. full. Name('Mister')); //=> radi se //=> Mister Jonathan Lehman // promena zavisnosti person. first. Name = 'Jon'; console. log(person. full. Name('Mr. ')); //=> radi se //=> Mr. Jon Lehman 11. 6. 2021. Predmet: Funkcionalno programiranje 86

“Malo više FP” memoizacija 1 // Malo više FP memoizacija //Modul se može pojačati

“Malo više FP” memoizacija 1 // Malo više FP memoizacija //Modul se može pojačati kasnijim dodavanjem funkcija var Memoizer = (function(){ //Privatni podaci var cache = {}; //Imenovane funkcije su zgodne! function cacher(func){ return function(){ var key = JSON. stringify(arguments); if(cache[key]){ return cache[key]; } else{ val = func. apply(this, arguments); cache[key] = val; return val; } } } 11. 6. 2021. Predmet: Funkcionalno programiranje 87

“Malo više FP” memoizacija 2 //Javni podaci return { memo: function(func){ return cacher(func); }

“Malo više FP” memoizacija 2 //Javni podaci return { memo: function(func){ return cacher(func); } } })() var fib = Memoizer. memo(function(n){ if (n < 2){ return 1; } else { return fib(n-2) + fib(n-1); } }); 11. 6. 2021. Predmet: Funkcionalno programiranje 88

Memoizacija: sažetak • Memoizacija može da poveća performansu keširanjem rezultata prethodnih poziva funkcije. •

Memoizacija: sažetak • Memoizacija može da poveća performansu keširanjem rezultata prethodnih poziva funkcije. • Memoizovane funkcije se skladište u keš koji se indeksira ulaznim argumentima. Ako argumenti postoje u kešu, vraća se keširana vrednost a u protivnom se funkcija izvršava i novosračunata vrednost se dodaje u keš. • Objektni argumenti treba da se prevedu u string pre korišćenja indeksa. • Memoizacija se može automatski primeniti na referencijalno transparentne funkcije. • Memoizacija nije opravdana za funkcije koje se retko pozivaju ili se brzo izvršavaju. 11. 6. 2021. Predmet: Funkcionalno programiranje 89

Obrazac: Imutabilnost • Iskustva i pretpostavke • Imutabilnost je jedan od osnovnih principa FP-a

Obrazac: Imutabilnost • Iskustva i pretpostavke • Imutabilnost je jedan od osnovnih principa FP-a • Imutabilnost znači da se varijabli vrednost može dodeliti samo jednom. • Od specifikacije ECMAScript 6 Java. Script podržava ključnu reč const koja je deklaracija imutabilnih varijabli. • Obrazac: • Korišćenje deklaracije const, Object. freeze metode ili svojstva writable: false. 11. 6. 2021. Predmet: Funkcionalno programiranje 90

Imutabilnost: primena 1 var consts = Object. freeze({ pi : 3. 141}); consts. pi

Imutabilnost: primena 1 var consts = Object. freeze({ pi : 3. 141}); consts. pi = 7; console. log(consts. pi); //izlaz: 3. 141 _________________________ "use strict"; var consts = Object. freeze({ pi : 3. 141}); consts. pi = 7; ▲ Uncaught Type. Error: Cannot assign to read only property 'pi' of object '#<Object>‘ ___________________________ var number. Of. Queens = 1; const number. Of. Kings = 1; number. Of. Queens++; number. Of. Kings++; console. log(number. Of. Queens); console. log(number. Of. Kings); ▲ Uncaught Type. Error: Assignment to constant variable. 11. 6. 2021. Predmet: Funkcionalno programiranje 91

Imutabilnost: primena 2 var t = Object. create(Object. prototype, { value: { writable: false,

Imutabilnost: primena 2 var t = Object. create(Object. prototype, { value: { writable: false, value: 10} }); t. value = 7; console. log(t. value); //izlaz: 10 _______________________________ "use strict"; var t = Object. create(Object. prototype, { value: { writable: false, value: 10} }); t. value = 7; console. log(t. value); ▲ Uncaught Type. Error: Cannot assign to read only property 'value' of object '#<Object>' 11. 6. 2021. Predmet: Funkcionalno programiranje 92

Obrazac: Lenjo instanciranje • Iskustvo i pretpostavke: • Česte su situacije u kojima je

Obrazac: Lenjo instanciranje • Iskustvo i pretpostavke: • Česte su situacije u kojima je potrebno kreirati objekte koji su “skupi” za kreiranje: recimo potrebno je puno vremena da se objekat kreira. • Takođe, ima situacija u kojima neki objekat možda neće biti ni potreban za određeni scenario izvršavanja. • Obrazac: • Kreiranje objekta se odlaže sve dok on stvarno ne postane potreban za izvršavanje. 11. 6. 2021. Predmet: Funkcionalno programiranje 93

Lenjo instanciranje: primena 1 • U Westerosu vole dobro pecivo. Pekara prima narudžbe za

Lenjo instanciranje: primena 1 • U Westerosu vole dobro pecivo. Pekara prima narudžbe za različite vrste hleba i hleb se pravi odjednom čim se dobije prva narudžba. • Međutim, pravljenje hleba je skupa operacija i pekara je odlaže sve dok se zaista ne pojavi neka narudžba hleba: var Bread = (function () { function Bread(bread. Type) { this. bread. Type = bread. Type; //složena, dugotrajna operacija console. log("Bread " + bread. Type + " created. "); } return Bread; })(); 11. 6. 2021. Predmet: Funkcionalno programiranje 94

Lenjo instanciranje: primena 2 • Započinje se kreiranjm liste tipova hleba koji se po

Lenjo instanciranje: primena 2 • Započinje se kreiranjm liste tipova hleba koji se po potrebi prave. Toj listi se dodaju stavke na osnovu narudžbe tipa hleba: var Bakery = (function () { function Bakery() { this. required. Breads = []; } Bakery. prototype. order. Bread. Type = function (bread. Type) { this. required. Breads. push(bread. Type); }; • Na taj način se omogućava brzo dodavanje hlebova listi zahtevanih hlebova bez plaćanja cene za kreiranje svakog pojedinačnog hleba. 11. 6. 2021. Predmet: Funkcionalno programiranje 95

Lenjo instanciranje: primena 3 • Hlebovi će biti kreirani kada se stvarno pozove pick.

Lenjo instanciranje: primena 3 • Hlebovi će biti kreirani kada se stvarno pozove pick. Up. Bread: Bakery. prototype. pick. Up. Bread = function (bread. Type) { console. log("Pickup of bread " + bread. Type + " requested"); if (!this. breads) { this. create. Breads(); } for (var i = 0; i<this. breads. length; i++) { if (this. breads[i]. bread. Type == bread. Type) return this. breads[i]; } }; Bakery. prototype. create. Breads = function () { this. breads = []; for (var i = 0; i<this. required. Breads. length; i++) { this. breads. push(new Bread(this. required. Breads[i])); } }; 11. 6. 2021. Predmet: Funkcionalno programiranje 96

Lenjo instanciranje: primena 4 • Zatim dolazi serija operacija: var bakery = new Westeros.

Lenjo instanciranje: primena 4 • Zatim dolazi serija operacija: var bakery = new Westeros. Food. Suppliers. Bakery(); bakery. order. Bread. Type("Brioche"); bakery. order. Bread. Type("Anadama bread"); bakery. order. Bread. Type("Chapati"); bakery. order. Bread. Type("Focaccia"); console. log(bakery. pick. Up. Bread("Brioche"). bread. Type + "picked up"); • Rezultat ove bi trebao da bude: Pickup of bread Brioche requested. Bread Brioche created. Bread Anadama bread created. Bread Chapati created. Bread Focaccia created. Brioche picked up 11. 6. 2021. Predmet: Funkcionalno programiranje 97

Obrazac Konstruktor • Da se podsetimo: u objektnom ambijentu konstruktor je specijalna funkcija u

Obrazac Konstruktor • Da se podsetimo: u objektnom ambijentu konstruktor je specijalna funkcija u klasi koja inicijalizuje objekat nekim skupom pretpostavljenih ili zadatih vrednosti. • Uobičajeni načini za kreiranje objekata u Java. Scriptu su: var instance = {}; // ili var instance = Object. create(Object. prototype); // ili var instance = new Object(); 11. 6. 2021. Predmet: Funkcionalno programiranje 98

Dodavanje svojstava objektu 1 // od specifikacije ES 3 // dot notacija instance. key

Dodavanje svojstava objektu 1 // od specifikacije ES 3 // dot notacija instance. key = "A key's value"; // notacija srednje zagrade instance["key"] = "A key's value"; 11. 6. 2021. Predmet: Funkcionalno programiranje 99

Dodavanje svojstava objektu 2 // od specifikacije ES 5 // za pojedinačno svojstvo //

Dodavanje svojstava objektu 2 // od specifikacije ES 5 // za pojedinačno svojstvo // pomoću Object. define. Property(instance, "key", { value: "A key's value", writable: true, enumerable: true, configurable: true }); // pomoću Object. define. Properties za više svojstava Object. define. Properties(instance, { "first. Key": { value: "First key's value", writable: true }, "second. Key": { value: "Second key's value", writable: false } }); 11. 6. 2021. Predmet: Funkcionalno programiranje 100

Obrazac Konstruktor: Iskustvo ugrađeno u obrazac • Iskustva: • Najpopularniji način za kreiranje objekata

Obrazac Konstruktor: Iskustvo ugrađeno u obrazac • Iskustva: • Najpopularniji način za kreiranje objekata je sintaksa sa vitičastim zagradama a za dodavanje svojstava dot notacija ili notacija uglastih zagrada. • Java. Script ne podržava nativne klase ali podržava konstruktore korišćenjem ključne reči “new” u prefiksu poziva funkcije. • Obrazac: • To znači da se može koristiti funkcija kao konstruktor i inicijalizovati njena svojstva na isti način kao sa klasičnim jezičkim konstruktorom. 11. 6. 2021. Predmet: Funkcionalno programiranje 101

Definisanje konstruktora – prvi način // definiše se konstruktor za objekte Person function Person(name,

Definisanje konstruktora – prvi način // definiše se konstruktor za objekte Person function Person(name, age, is. Developer) { this. name = name; this. age = age; this. Developer = is. Developer || false; this. writes. Code = function() { console. log(this. Developer? "This person does write code" : "This person does not write code"); } } 11. 6. 2021. Predmet: Funkcionalno programiranje 102

Korišćenje konstruktora /* Kreira Person instancu sa svojstvima name: Bob, age: 38, is. Developer:

Korišćenje konstruktora /* Kreira Person instancu sa svojstvima name: Bob, age: 38, is. Developer: true i metodom writes. Code */ var person 1 = new Person("Bob", 38, true); /* Kreira Person instancu sa svojstvima name: Alice, age: 32, is. Developer: false i metodom writes. Code */ var person 2 = new Person("Alice", 32); // izdaje: This person does write code person 1. writes. Code(); // izdaje: this person does not write code person 2. writes. Code(); • Opaska: Metod writes. Code redefiniše se za svaku instancu Person konstruktora. 11. 6. 2021. Predmet: Funkcionalno programiranje 103

Malo poboljšanja • Java. Script koristi prototipski bazirano nasleđivanje. • Problem sa rešenjem koje

Malo poboljšanja • Java. Script koristi prototipski bazirano nasleđivanje. • Problem sa rešenjem koje je napravljeno je što se metod writes. Code redefiniše za svaku instancu Person konstruktora. • To se može izbeći postavljanjem metode u prototip funkcije • U konkretnom slučaju treba dodati metodu writes. Code u prototip funkcije 11. 6. 2021. Predmet: Funkcionalno programiranje 104

Definisanje konstruktora – drugi način // definiše se konstruktor za Person objekte function Person(name,

Definisanje konstruktora – drugi način // definiše se konstruktor za Person objekte function Person(name, age, is. Developer) { this. name = name; this. age = age; this. Developer = is. Developer || false; } // proširuje se prototip funkcije Person. prototype. writes. Code = function() { console. log(this. Developer ? " Ova osoba kodira" : " Ova osoba ne kodira"); } 11. 6. 2021. Predmet: Funkcionalno programiranje 105

Korišćenje: izgleda isto, ali nije isto • Sada obe instance Person konstruktora mogu da

Korišćenje: izgleda isto, ali nije isto • Sada obe instance Person konstruktora mogu da pristupe deljenoj instanci metode writes. Code(): // Kreira Person instancu sa svojstvima name: Bob, age: 38, is. Developer: true i metodom writes. Code u prototipu var person 1 = new Person("Bob", 38, true); // Kreira Person instancu sa svojstvima name: Alice, age: 32, is. Developer: false i metodom writes. Code u prototipu var person 2 = new Person("Alice", 32); // izdaje: This person does write code person 1. writes. Code(); // izdaje: This person does not write code person 2. writes. Code(); 11. 6. 2021. Predmet: Funkcionalno programiranje 106

Obrazac Prototype • Iskustvo i pretpostavke: • Java. Script ne podržava klase nativno. •

Obrazac Prototype • Iskustvo i pretpostavke: • Java. Script ne podržava klase nativno. • Nasleđivanje između objekata implementira se prototipski baziranim programiranjem. • Java. Script omogućuje da se kreiraju objekti koji mogu da služe kao prototipovi za kreiranje drugih objekata. • Obrazac: • Kreiraju se objekti koji predstavljaju uzorke za svaki objekat koji će konstruktor da kreira. 11. 6. 2021. Predmet: Funkcionalno programiranje 107

Obrazac Prototype: primena 1 var person. Prototype = { say. Hi: function() { console.

Obrazac Prototype: primena 1 var person. Prototype = { say. Hi: function() { console. log("Hello, my name is " + this. name + ", and I am " + this. age); }, say. Bye: function() { console. log("Bye Bye!"); } }; function Person(name, age) { name = name || "John Doe"; age = age || 26; function constructor. Function(name, age) { this. name = name; this. age = age; }; 11. 6. 2021. Predmet: Funkcionalno programiranje 108

Obrazac Prototype: primena 2 constructor. Function. prototype = person. Prototype; var instance = new

Obrazac Prototype: primena 2 constructor. Function. prototype = person. Prototype; var instance = new constructor. Function(name, age); return instance; } var person 1 = Person(); var person 2 = Person("Bob", 38); // Izdaje: Hello, my name is John Doe, and I am 26 person 1. say. Hi(); // Izdaje: Hello, my name is Bob, and I am 38 person 2. say. Hi(); 11. 6. 2021. Predmet: Funkcionalno programiranje 109

Obrazac Module • Iskustvo i pretpostavke: • Java. Script u osnovnom obliku ne podržava

Obrazac Module • Iskustvo i pretpostavke: • Java. Script u osnovnom obliku ne podržava modifikatore prava pristupa kao što je to u klasičnim OOP jezicima gde korisnik definiše klasu i odredi prava pristupa za članove. • Veliki broj programera koristi klasičan OOP pristup koji visoko rangira klasni obrazac dizajna, što zahteva i implementaciju mehanizama koji podržavaju modifikatore prava pristupa. • U Java. Script-u, zatvaranje je funkcija koja ima pristup roditeljskom dosegu i nakon izvršavanja roditeljske funkcije. • Obrazac: • Ponašanje modifikatora pristupa imitira se tako što se manipuliše zatvaranjem u procesu dosezanja. 11. 6. 2021. Predmet: Funkcionalno programiranje 110

Obrazac Module: implementacija 1 • Zatvaranje: // Koristi se neposredno pozvan funkcijski izraz (IIFE)

Obrazac Module: implementacija 1 • Zatvaranje: // Koristi se neposredno pozvan funkcijski izraz (IIFE) za kreiranje privatne varijable counter var counter. Incrementer = (function() { var counter = 0; return function() { return ++counter; }; })(); // Izdaje: 1 console. log(counter. Incrementer()); // Izdaje: 2 console. log(counter. Incrementer()); // Izdaje: 3 console. log(counter. Incrementer()); • Korišćenjem IIFE, kreirana je brojačka varijabla za funkciju koja je pozvana i zatvorena, ali se njoj još uvek može pristupiti iz nasledničke funkcije koja je inkrementira. Kako se brojačkoj varijabli ne može pristupiti spolja (izvan funkcijskog izraza) na taj način ona je učinjena privatnom. 11. 6. 2021. Predmet: Funkcionalno programiranje 111

Obrazac Module: implementacija 2 • Na opisani način se, korišćenjem zatvaranja, mogu kreirati objekti

Obrazac Module: implementacija 2 • Na opisani način se, korišćenjem zatvaranja, mogu kreirati objekti sa privatnim i javnim delovima. • Ovi objekti se zovu moduli i vrlo su korisni kada treba sakriti određene delove objekta i izložiti samo interfejs za korišćenje modula. 11. 6. 2021. Predmet: Funkcionalno programiranje 112

Obrazac Modul: Primer korišćenja // Korišćenjem zatvaranja izlaže se objekat kao javni API koji

Obrazac Modul: Primer korišćenja // Korišćenjem zatvaranja izlaže se objekat kao javni API koji upravlja // nizom privatnih objekata var collection = (function() { // Privatni članovi var objects = []; // javni članovi return { add. Object: function(object) { objects. push(object); }, remove. Object: function(object) { var index = objects. index. Of(object); if (index >= 0) { objects. splice(index, 1); } }, get. Objects: function() { return JSON. parse(JSON. stringify(objects)); } }; })(); 11. 6. 2021. Predmet: Funkcionalno programiranje 113

Obrazac Modul: Primer primene collection. add. Object("Bob"); collection. add. Object("Alice"); collection. add. Object("Franck"); //

Obrazac Modul: Primer primene collection. add. Object("Bob"); collection. add. Object("Alice"); collection. add. Object("Franck"); // Izdaje: ["Bob", "Alice", "Franck"] console. log(collection. get. Objects()); collection. remove. Object("Alice"); // Izdaje: ["Bob", "Franck"] console. log(collection. get. Objects()); 11. 6. 2021. Predmet: Funkcionalno programiranje 114

Obrazac Module: prednosti i nedostaci • Najveća prednost koju ovaj obrazac uvodi je jasna

Obrazac Module: prednosti i nedostaci • Najveća prednost koju ovaj obrazac uvodi je jasna separacija privatnog i javnog dela objekta na način veoma sličan klasičnom OO pristupu. • Nedostaci su u sledećem: • Kada je potrebno promenuti vidljivost člana, mora se modifikovati kod pri svakoj upotrebi tog člana zbog različite prirode pristup javnim i privatnim delovima. • Metode koje se dodaju objektu ne mogu da pristupe privatnim članovima objekta. 11. 6. 2021. Predmet: Funkcionalno programiranje 115

Otkrivajući Module obrazac • Ovaj obrazac (Revealing Module Pattern – RMP) je poboljšanje Module

Otkrivajući Module obrazac • Ovaj obrazac (Revealing Module Pattern – RMP) je poboljšanje Module obrasca. • Osnovna razlika je što se celokupna logika objekta zapisuje u privatnom dosegu modula i zatim javnosti izlažu njeni željeni delovi vraćanjem anonimnog objekta. • Moguće je i promenuti imenovanja privatnih članova pri njihovom mapiranju na odgovarajuće javne članove. 11. 6. 2021. Predmet: Funkcionalno programiranje 116

Otkrivajući Module obrazac: Primer korišćenja 1 // Celokupna logika objekta se zapisuje kao privatni

Otkrivajući Module obrazac: Primer korišćenja 1 // Celokupna logika objekta se zapisuje kao privatni članovi i // izlaže se anonimni objekat koji mapira članove koje želimo da otkrijemo // na njima odgovarajuće javne članove var names. Collection = (function() { // Privatni članovi var objects = []; function add. Object(object) { objects. push(object); } function remove. Object(object) { var index = objects. index. Of(object); if (index >= 0) { objects. splice(index, 1); } } function get. Objects() { return JSON. parse(JSON. stringify(objects)); } 11. 6. 2021. Predmet: Funkcionalno programiranje 117

Otkrivajući Module obrazac: Primer korišćenja 2 // Javni članovi return { add. Name: add.

Otkrivajući Module obrazac: Primer korišćenja 2 // Javni članovi return { add. Name: add. Object, remove. Name: remove. Object, get. Names: get. Objects }; })(); names. Collection. add. Name("Bob"); names. Collection. add. Name("Alice"); names. Collection. add. Name("Franck"); // Izdaje: ["Bob", "Alice", "Franck"] console. log(names. Collection. get. Names()); names. Collection. remove. Name("Alice"); // Izdaje: ["Bob", "Franck"] console. log(names. Collection. get. Names()); 11. 6. 2021. Predmet: Funkcionalno programiranje 118

Otkrivajući Module obrazac: prednosti i nedostaci • Osnovna razlika između otkrivajućeg Module obrasca i

Otkrivajući Module obrazac: prednosti i nedostaci • Osnovna razlika između otkrivajućeg Module obrasca i ostalih načina implementacije Module obrasca je prvenstveno u načinu pristupanja javnim članovima. • Rezultat je njegova prednost koja se ogleda u lakšem načinu korišćenja. • Međutim, on pokazuje i određeni nedostatak robusnosti u scenarijima korišćenja RPM objekata kao prototipova u lancu nasleđivanja: • Ako je u pitanju privatna funkcija koja referiše javnu funkciju, nije moguće prevazići (override) javnu funkciju, jer će privatna funkcija nastaviti da referiše privatnu implementaciju funkcije što dovodi do baga u sistemu. • Ako je u pitanju javni član koji pokazuje na privatnu varijablu i pokuša se prevazilaženje javnog člana izvan modula, druga funkcija će i dalje referisati privatnu vrednost što, takođe, dovodi do baga u sistemu. 11. 6. 2021. Predmet: Funkcionalno programiranje 119

Kompozibilni korisnički tipovi • O kompozibilnim prilagođenim korisničkim tipovima • Sočiva • Transdjuseri 11.

Kompozibilni korisnički tipovi • O kompozibilnim prilagođenim korisničkim tipovima • Sočiva • Transdjuseri 11. 6. 2021. Predmet: Funkcionalno programiranje 120

Kompozibilni korisnički tipovi: Uvod • U Java. Script-u, najlakši način za kompoziciju je kompozicija

Kompozibilni korisnički tipovi: Uvod • U Java. Script-u, najlakši način za kompoziciju je kompozicija funkcija, a funkcija je samo objekat kome se mogu dodati metode. • Drugim rečima, može se uraditi sledeće: const t = value => { const fn = () => value; fn. to. String = () => `t(${ value })`; // dodavanje metode return fn; }; let some. Value 0 = t(0) // console. log (some. Value 0 + ' type: ' + typeof some. Value 0); // Izlaz: t(0) type: function // console. log (some. Value 0. to. String + ' type: ' + typeof some. Value 0. to. String); // Izlaz: () => `t(${ value })` type: function 11. 6. 2021. Predmet: Funkcionalno programiranje 121

Kompozibilni korisnički tipovi: kompozicija • Prethodni kod je fabrika (factory) koja vraća instance numeričkog

Kompozibilni korisnički tipovi: kompozicija • Prethodni kod je fabrika (factory) koja vraća instance numeričkog tipa podatka, t. • Ono što treba zapaziti je da te instance nisu jednostavni objekti, već funkcije. • Kako su u pitanju funkcije, one se mogu komponovati. • Neka primer korišćenja bude scenario sabiranja njenih članova. • Pokušaćemo to da uradimo kompozicijom. 11. 6. 2021. Predmet: Funkcionalno programiranje 122

Pravila • Pravila i značenje Identitet: t(x)(t(0)) ≡ t(x) Asocijativnost: t(a)(t(b))(t(c)) ≡ t(a)(t(b)(t(c)) (a

Pravila • Pravila i značenje Identitet: t(x)(t(0)) ≡ t(x) Asocijativnost: t(a)(t(b))(t(c)) ≡ t(a)(t(b)(t(c)) (a + b) + c = a + (b + c) • Kod za pravila: t(x)(t(0)). to. String() === t(x). to. String() t(a)(t(b))(t(c)). to. String() === t(a)(t(b)(t(c)). to. String() 11. 6. 2021. Predmet: Funkcionalno programiranje 123

Jednostavan jedinični test • Sada se može napraviti kod koji vrši testiranje tipa koji

Jednostavan jedinični test • Sada se može napraviti kod koji vrši testiranje tipa koji smo kreirali • Testira se da li kreirani tip zadovoljava pravila • Kod za test može da izgleda ovako • Taj test ne prolazi – dobija se sledeć izlaz: NOT OK: a value t(x) composed with t(0) ==== t(x) Expected: t(20) Actual: 20 11. 6. 2021. Predmet: Funkcionalno programiranje 124

Ispravan kod • Da bi naše rešenje bilo ispravno, potrebno je: 1. 2. 3.

Ispravan kod • Da bi naše rešenje bilo ispravno, potrebno je: 1. 2. 3. • Izmenuti funkciju fn u funkciju add koja vraća t(value + n) i gde se n prosleđuje kao argument. Dodati metodu value. Of() tipu t tako da nova funkcija add() može da primi instance t() kao argumente. Operator + će da koristi rezultat iz n. value. Of() kao drugi operand. Pridružiti metode funkciji add() pomoću Object. assign(). Kod sada izgleda ovako: const t = value => { const add = n => t(value + n); }; 11. 6. 2021. return Object. assign(add, { to. String: () => `t(${ value })`, value. Of: () => value }); Predmet: Funkcionalno programiranje 125

Ispravan kod • Ispravan kod se može videti ovde • I on vraća sledeći

Ispravan kod • Ispravan kod se može videti ovde • I on vraća sledeći rezultat pri testiranju: "OK: a value t(x) composed with t(0) ==== t(x)" "OK: a value t(x) composed with t(1) ==== t(x + 1)“ 11. 6. 2021. Predmet: Funkcionalno programiranje 126

Primena kompozicije A primena kompozicije izgleda ovako: // Komponovanja funkcija od vrha ka dnu:

Primena kompozicije A primena kompozicije izgleda ovako: // Komponovanja funkcija od vrha ka dnu: const pipe = (. . . fns) => x => fns. reduce((y, f) => f(y), x); // Iniciranje pipeline-e početnom vrednošću: const add = (. . . fns) => pipe(. . . fns)(t(0)); const sum 1 = add(t(2), t(4), t(-1) ); console. log(sum. to. String()) // Ispis: t(5) const sum 2 = add(t(20), t(40), t(-5) ); console. log(sum. to. String()) // Ispis: t(55) 11. 6. 2021. Predmet: Funkcionalno programiranje 127

Nezavisnost od tipa podataka • Nije važno koji je oblik podataka sve dok postoji

Nezavisnost od tipa podataka • Nije važno koji je oblik podataka sve dok postoji operacija kompozicije koja ima smisla. • Na primer, za liste i stringove to može da bude konkatenacija. • Za obradu digitalnih signala (Digial Signal Processing, DSP), to može da bude sumiranje signala. • Naravno, za iste podatke i više različitih operacija može da ima smisla. . . • Suštinsko pitanje je koja operacija najbolje reprezentuje koncept kompozicije, odnosno za koju će biti najkorisnije ako se izrazi na sledeći način: const result = compose( vrednost 1, vrednost 2, vrednost 3 ); 11. 6. 2021. Predmet: Funkcionalno programiranje 128

Primer: Moneysafe • Moneysafe (https: //github. com/ericelliott/moneysafe ) je biblioteka otvorenog koda koja implementira

Primer: Moneysafe • Moneysafe (https: //github. com/ericelliott/moneysafe ) je biblioteka otvorenog koda koja implementira ovaj tip kompozibilnih tipova podataka. • Motivacija za pravljenje: Java. Script Number tip ne može tačno da predstavi određene delove dolara: . 1 +. 2 ===. 3 // false • Moneysafe rešava problem tako što dolarski iznos liftuje u cente: npm install --save moneysafe import { $ } from 'moneysafe'; $(. 1) + $(. 2) === $(. 3). cents; // true 11. 6. 2021. Predmet: Funkcionalno programiranje 129

Kako radi import { $ } from 'moneysafe'; import { $$, subtract. Percent, add.

Kako radi import { $ } from 'moneysafe'; import { $$, subtract. Percent, add. Percent } from 'moneysafe/ledger'; $$( $(40), $(60), // Oduzmi popust subtract. Percent(20), // Dodaj porez add. Percent(10) ). $; // 88 11. 6. 2021. Predmet: Funkcionalno programiranje 130

Funkcionalna sočiva (Lenses) • Lens (sočivo) je kompozibilan par čistih geter i seter funkcija

Funkcionalna sočiva (Lenses) • Lens (sočivo) je kompozibilan par čistih geter i seter funkcija koji fokusira određeno polje unutar objekta i poštuje skup aksioma koji se zovu zakoni sočiva. • Osnovna ideja je sledeća: O objektu se razmišlja kao o celini a o polju kao o delu. Geter prima celinu i vraća deo objekta na koji je sočivo fokusirano. // view = whole => part • Seter prima celinu i vrednost na koju treba postaviti deo i vraća novu celinu u kojoj je taj deo ažuriran. Ono što je važno je da su Lens seteri čiste funkcije: // set = whole => part => whole 11. 6. 2021. Predmet: Funkcionalno programiranje 131

Pozadina koncepta sočiva • Još 1985, u odličnoj knizi “Structure and Interpretation of Computer

Pozadina koncepta sočiva • Još 1985, u odličnoj knizi “Structure and Interpretation of Computer Programs” opisani su parovi geter/seter (tamo su nazvani put i get) kao način da se oblik objekta izoluje od koda koji taj objekat koristi. • Tekst opisuje predlog za kreiranje generičkih selektora koji pristupaju delovima kompleksnog broja nezavisno od načina reprezentacije broja. • Takva izolacija je korisna jer razbija zavisnosti oblika stanja. • Ti geter/seter parovi su slični referenciranim upitima koji su u relacionim bazama postojali decenijama. • Sočiva su taj koncept još pojačala time što su parove geter/seter učinila opštijim i kompozibilnim. 11. 6. 2021. Predmet: Funkcionalno programiranje 132

Sočivo: Primer • Zamislite da imate torku tipa array koja predstavlja x, y, i

Sočivo: Primer • Zamislite da imate torku tipa array koja predstavlja x, y, i z koordinate neke tačke: [x, y, z] • Da biste pojedinačno postavljali svako polje, mogli biste da kreirate tri sočiva, po jedno za svaku osu. Mogu se ručno kreirati geteri koji fokusiraju svako polje: const get. X = ([x]) => x; const get. Y = ([x, y]) => y; const get. Z = ([x, y, z]) => z; console. log( get. Z([10, 100]) // Vraća: 100 ); • A isto tako i seteri: const set. Y = ([x, _, z]) => y => ([x, y, z]); console. log( set. Y([10, 10])(999) // Vraća: [10, 999, 10] ); 11. 6. 2021. Predmet: Funkcionalno programiranje 133

Sočivo: Čemu služi • Zavisnosti među stanjima su uobičajeni izvor sprezanja u softveru. Mnoge

Sočivo: Čemu služi • Zavisnosti među stanjima su uobičajeni izvor sprezanja u softveru. Mnoge komponente mogu da zavise od oblika nekog deljenog stanja tako da potreba za kasnijom izmenom oblika stanja zahteva izmenu logike na više mesta. • Sočiva omogućuju da se oblik stanja apstrahuje iza getera i setera. Umesto da se zagađuje kodna baza kodom koji uranja duboko u oblik određenog objekta, uvozi se sočivo. • Ako je kasnije potrebno izmenuti oblik stanja, to se može uraditi u sočivu i ništa od koda koji zavisi od sočiva ne mora da se menja. 11. 6. 2021. Predmet: Funkcionalno programiranje 134

Zakoni sočiva • Zakoni sočiva su algebarski aksiomi koji osiguravaju da se sočivo dobro

Zakoni sočiva • Zakoni sočiva su algebarski aksiomi koji osiguravaju da se sočivo dobro ponaša. 1. view (lens, set(lens, value, store))≡value — Ako se postavi vrednost u skladište i odmah pogleda kroz sočivo, videćete postavljenu vrednost. 2. set(lens, b, set(lens, a, store))≡ set(lens, b, store) — Ako se postavi vrednost sočiva na a i odmah zatim se postavi na b, to je isto kao da je vrednost samo postavljena na b. 3. set(lens, view(lens, store)≡store — Ako se preuzme vrednost sočiva iz skladišta i zatim odmah postavi natrag u skladište, vrednost ostaje nepromenjena. 11. 6. 2021. Predmet: Funkcionalno programiranje 135

Naivna implementacija sočiva • Iako postoje dobre implementacije sočiva u bibliotekama kao što je,

Naivna implementacija sočiva • Iako postoje dobre implementacije sočiva u bibliotekama kao što je, na primer, Ramda, pokazaćemo ovde jednu naivnu implementaciju sočiva da bi se razumela njegova suština. • Implementacija obuhvata sledeće delove: • Čiste funkcije za gledanje (view) i postavljanje (set) vrednosti koje se mogu koristiti sa proizvoljnim sočivom • Funkciju koja prima svojstvo i vraća naivne (primenljive samo na objekat) pristupnike (akcesore) za to svojstvo. 11. 6. 2021. Predmet: Funkcionalno programiranje 136

Naivna implementacija sočiva: kod • Čiste funkcije za gledanje i postavljanje: const view =

Naivna implementacija sočiva: kod • Čiste funkcije za gledanje i postavljanje: const view = (lens, store) => lens. view(store); const set = (lens, value, store) => lens. set(value, store); • Funkcija koja prima svojstvo i vraća funkciju koja implementira pristup tom svojstvu kroz sočivo: const lens. Prop = prop => ({ view: store => store[prop], // Ovaj deo je vrlo pojednostavljen, radi samo za objekte: set: (value, store) => ({. . . store, [prop]: value }) }); • Kod koji demonstrira korišćenje ovih funkcija je ovde • Kod kojim se pokazuje da su zadovoljeni zakoni sočiva je ovde. 11. 6. 2021. Predmet: Funkcionalno programiranje 137

Sočiva: komponovanje • Sočiva se mogu komponovati. • Šta je, u stvari, komponovanje sočiva?

Sočiva: komponovanje • Sočiva se mogu komponovati. • Šta je, u stvari, komponovanje sočiva? • Naravno, to vam je kao da povećavate dioptriju: sve dublje zaranjate u objekat obilazeći sve njegove detalje. • Kako se to radi • Funkcija a => b može se primeniti u kontekstu svakog tipa funktor. • Već smo ranije pokazali da je mapiranje funktora kompozicija. • Slično, funkcija se može primeniti na vrednost u fokusu sočiva. • Obično je ta vrednost istog tipa, pa će funkcija biti a => a. • Operacija mapiranja sočiva u Java. Script bibliotekama uobičajeno se zove over(). 11. 6. 2021. Predmet: Funkcionalno programiranje 138

Primena funkcije na vrednost u fokusu: funkcija over() // over = (lens, f: a

Primena funkcije na vrednost u fokusu: funkcija over() // over = (lens, f: a => a, store) => store const view = (lens, store) => lens. view(store); const set = (lens, value, store) => lens. set(value, store); const lens. Prop = prop => ({ view: store => store[prop], set: (value, store) => ({. . . store, [prop]: value }) }); const over = (lens, f, store) => set(lens, f(view(lens, store)), store); const uppercase = x => x. to. Upper. Case(); const store = { a: 'foo', b: 'bar' }; const a. Lens = lens. Prop('a'); console. log( over(a. Lens, uppercase, store) // Izlaz: {a: "FOO", b: "bar" } ); • Kompletan kod za ovaj primer je ovde • I sočiva pod over() operacijom zadovoljavaju zakone sočiva. Kod kojim se to pokazuje je ovde. 11. 6. 2021. Predmet: Funkcionalno programiranje 139