Upload
halobing
View
222
Download
0
Embed Size (px)
Citation preview
8/17/2019 Fsharp prirucnik
1/57
1 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Programski jezik F# (I deo)
Uvod F# je programski jezik, razvijen na .NET platformi, sa izraženim funkcionalnim karakteristikama koji
podržava i druge paradigme programiranja poput imperativne i objektno‐orijentisane.
Autor F#‐a je Don Syme, istraživač zaposlen u okviru Microsoft Research centra u Kembridžu.
Snaga F#‐a leži u svedenoj sintaksi koja omogućava laku čitljivost koda, kao i efikasan razvoj programa
koje zahtevaju primenu složenih matematičkih algoritama. Jezik omogućava brzo generisanje
prototipova i njihovu brzu transformaciju u produkcioni kod. Kod napisan u F#‐u lako se može
paralelizovati, što je posebno značajno danas kada svi novi kompijuteri imaju više jezgara. Korišćenjem
F#‐a kao osnovnog jezika mogu se lako kreirati domensko specifični jezici (DSL) što ga čini posebno
pogodnim za naučno‐istraživačku primenu.
F# je kompatibilan sa svim ostalim .NET jezicima. To znači da F# program može da koristi sve .NET
biblioteke. Biblioteka napisana u F#‐u može se koristiti u bilo kojoj desktop ili Web aplikaciji razvijenoj na
.NET platformi.
Instalacija
Da bi ste programirali u F#‐u i provežbali primere koji su prikazani u ovoj skripti potrebno je da imate
instaliran F# kompajler i interpreter.
Ukoliko imate instaliranu neku od verzija Visual Studio‐a 2010 (u vreme pisanja ovog teksta dostupan
kao Beta 2 verzija), nije potrebna nikakva dodatna instalacija. U suprotnom, možete pronaći link za
preuzimanje aktuelne verzije F#‐a na web adresi http://msdn.microsoft.com/en‐us/fsharp/default.aspx.
Sama instalacija se obavlja jednostavno, pokretanjem instalacionog paketa ( Next,Next, ... Finish) pri
čemu nikakva specifična podešavanja nisu potrebna.
Vežbanje kroz primere
Koncept ove skripte je vežbanje kroz primere. Većina primera je napravljena tako da se mogu izvršiti u
F# konzoli .
VS2010
Ukoliko imate Visual Studio 2010, F# konzolu možete pokrenuti iz Start menija kao što je prikazano na
slici:
Preporuka autora je da po izlasku zvanične verzije Visual Studio‐a 2010 preuzmete njegovu
besplatnu ediciju i koristite je za programiranje u F#‐u.
Imperativno programiranje je termin koji se u literaturi često koristi za programiranje u
programskim jezicma poput C‐a ili Pascal‐a.
8/17/2019 Fsharp prirucnik
2/57
2 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Kada se konzola pokrene potrebno je da otkucate fsi i pritisnete taster Enter da bi pokrenuli F#
interpreter . Kako bi testirali da li F# interpreter radi otkucajte printfn “Hello World“;;. Dobićete prikaz
kao na sledećoj slici:
Instalacija F#‐a bez Visual Studio‐a
Ukoliko instalirate F# kompajler nezavisno od Visual Studio‐a imaćete u okviru Start menija Microsoft F#
grupu i u okviru nje opciju F# Interactive (Console).
Izaberite ovu opciju i na ekranu će se prikazati konzola. Da bi ste testirali da li F# interpreter radi
otkucajte printfn “Hello World“;;. Dobićete prikaz kao na sledećoj slici:
8/17/2019 Fsharp prirucnik
3/57
3 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Osnovne naredbe
Naredba povezivanja let
Naredba let je najznačajnija i najčešće korišćena naredba u F#‐u. Služi da poveže identifikatore sa vrednostima. Sledeći primer ilustruje upotrebu ove naredbe.
Kao što možete da uočite naredba let ima formu: let ident = expr , gde je ident identifikator (u ovom
slučaju „a“), dok je expr izraz ( u ovom slučaju vrednost „21“).
Treba uočiti da je F# interpretatora automatski odredio da je vrednost povezana sa identifikatorom „a“
celobrojna ( int ). Ova funkcionalnost F# interpretatora naziva se inferencija tipa.
Druga stvar koju ste možda uočili je upotreba reči identifikator za simbol „a“, umesto možda očekivane
reči promenljiva. Razlog za to je što se simboli u F# podrazumevano dodeljuju vremenski nepromenljivim
(eng. immutable) vrednostima. Ukoliko pomoću naredbe let povežemo identifikator „a“ sa nekom
drugom vrednošću, neće se promeniti sadržaj memorijske lokacije prethodno povezane sa
identifikatorom „a“, već će identifikator „a“ biti povezan sa drugom memorijskom lokacijom.
8/17/2019 Fsharp prirucnik
4/57
4 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Da bi to ilustrovali povezaćemo identifikator „a“ sa promenljivom tipa znak.
Pored celobrojnog i znakovnog u F# možemo koristiti i vrednosti osnovnih tipova poput realnog broja
( float ), niske znakova (string) i logičkog (bool ).
Funkcija kao tip podataka
Funkcije su u F#‐u samo jedan od tipova podataka kao što je to slučaj sa celobrojnim ili znakovnim
tipovima. Šta više možemo definisati i vrednost funkcijskog tipa, funkcijski literal .
8/17/2019 Fsharp prirucnik
5/57
5 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Svaki funkcijski literal ima svoj tip, koji interpreter automatski utvrđuje kao što je to slučaj i kod ostalih
tipova. Funkcijski literal (fun x ‐> x*x) ima tip „int ‐>int“ što označava da predstavlja funkciju koja
preslikava skup celih brojeva na skup celih brojeva.
Naredba povezivanja funkcijske vrednosti sa identifikatorom ima i svoju kraću, prirodniju, formu.
Ukoliko nismo zadovoljni tipom funkcije koji je interpreter automatski odredio, možemo mu dati
sugestiju (eng.
compiler
hint ).
U
primeru
koji
sledi
ova
sugestija
je
namerno
data
u
sredini
izraza
kako
je
čitalac ne bi pomešao sa definisanjem liste parametara.
Kako se odvija ovo automatsko utvrđivanje? Interpreter polazi od naredbe x*x , i predpostavlja da je operator množenja definisan nad skupom celih brojeva. Prema tome x je ceo broj, a samim
tim i rezultat funkcije.
8/17/2019 Fsharp prirucnik
6/57
6 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Tip podataka n‐torka
n‐torka (eng. tuple) je najjednostavniji i najčešće korišćeni od svih složenih tipova podataka. Koristimo ga
kada želimo da koristimo uređeni skup vrednosti, a da pri tome eksplicitno ne definišemo tip.
Sledeći primer prikazuje povezivanje uređenog para gde je prvi član tipa string, a drugi tipa int sa identifikatorom “s”.
Uređene parove možemo vezati i za više identifikatora, pri čemu se identifikatori vezuju za vrednosti
prema poziciji. Ukoliko neku od vrednosti iz uređenog para ne želimo da vežemo za neki identifikator,
umesto identifikatora stavljamo simbol “_”.
Navedeni oblici let naredbe ilustrovani su sledećim primerom.
8/17/2019 Fsharp prirucnik
7/57
7 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Tip podataka lista
Kreiranje liste
Liste su redovni pratilac funkcionalnih programskih jezika. Neki jezici poput Lisp‐a koncipirani su oko
rada sa listama.
Proučavanje lista počećemo sa sledećim naredbama:
Prva naredba predstavlja literal za praznu listu. Kompajler naravno ne može da odredi kog tipa je prazna lista pa automatski definiše generalizovani tip.
Lista kao tip podataka označava se kao ‘a list , pri čemu ‘a predstavlja generičku definiciju za tip
člana liste (npr. int list ). Za one koji poznaju programske jezike C++, ova oznaka je ekvivalentna
oznaci List.
8/17/2019 Fsharp prirucnik
8/57
8 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Druga naredba predstavlja literal za listu celih brojeva. Iako to nigde eksplicitno nismo naveli kompajler
je ispravno odredio tip literala kao int list .
Treća i četvrta naredba definiše listu preko intervala, pri čemu je u četvrtoj definisan i korak sa kojim se
članovi generišu.
Liste mogu biti i nekog drugog tipa, npr. tipa string. Međutim ono što je važno napomenuti je da svi
članovi liste moraju biti istog tipa. U suprotnom će kompajler prijaviti sintaksnu grešku.
Sledeći primer ovo pokazuje:
Rad sa listama
Kalkulacije sa listama izvršavaju se primenom operatora i funkicija na liste.
Operatori za rad sa listama su:
operator spajanja elementa i liste (::)
operator spajanja dve liste (@)
Sledeće naredbe ilustruju primenu navedenih operatora:
8/17/2019 Fsharp prirucnik
9/57
9 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Kao i većina osnovnih tipova u F#‐u liste su nepromenljive (eng. immutable). Sve operacije nad listama
kreiraju nove liste umesto da menjaju postojeće.
Sledeći primer prikazuje listu l kojoj smo dodeli literal [9;10]. Posle dodavanja vrednosti 8 na listu l , data
lista je ostala nepromenjena što je pokazano izvršavanjem naredbe l;;.
Pored operatora, F# biblioteke sadrže i veći broj funkcija za rad sa listama. U ovom poglavlju
prikazaćemo samo osnovne funkcije i to:
List.length
vraća
dužinu
liste
List.head vraća prvi element liste
List.tail vraća sve elemente liste osim prvog
Liste u F#‐u su interno implementirane kao grupa jednosmerno povezanih ćelija sa vrednošću,
pri čemu identifikator liste pokazuje na prvu ćeliju u grupi. Ovakva implementacija, uz
nepromenljivost članova zagarantovanu kompajlerom, omogućava efikasno izvršavanje operacija
nad listama kao i njihovo efikasno skladištenje u memoriji.
8/17/2019 Fsharp prirucnik
10/57
10 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Pored navedenih, od izuzetnog značaja za rad sa listama su i funkcije:
List.map funkcija projekcije
List.filter funkcija selekcije
List.fold funkcija agregacije
Ove funkcije biće detaljnije obrađene u jednom od narednih poglavlja.
8/17/2019 Fsharp prirucnik
11/57
11 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Naredba match
Osnovni oblik
Naredba match je naredba koja u sebi kombinuje dekompoziciju složenih vrednosti i kontrolu toka.
U svom osnovnom obliku podseća na switch naredbu iz jezika C++, i tada uparuje prosleđenu vrednost
sa nekim od datih literala. Zavisno od literala koji je uparen izvršava se odgovarajuci segment koda.
Kao i kod switch naredbe jedan segment koda je moguće vezati za više literala.
Za razliku od switch naredbe, naredba match (kao i sve ostale F# naredbe) vraća vrednost. U
prethodnom primeru je ta vrednost prikazana sa “val it : unit = ()” ,što je tip povratne vrednosti funkcije
printfn.
Tip unit odgovara tipu void u programskom jeziku C++. Suštinski to znači da funkcija printfn ne
vraća vrednost, odnosno da se radi o proceduri.
8/17/2019 Fsharp prirucnik
12/57
12 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Sledeći primer ilustruje naredbu match koja umesto prikazivanja teksta u konzoli vraća tekst kao
rezultat.
Uparivanje prema obrascu
Naredba match nije ograničena na uparivanje sa literalima, već je moguće da se uparivanje vrši prema obrascu. Jedan od obrazaca za uparivanje već je prikazan, iako to nije posebno istaknuto. To je obrazac
za uparivanje “_”, koji se može upariti sa bilo kojom vrednošću (odgovara default grani switch naredbe).
Sledeći primer ilustruje uparivanje sa obrascem za listu, pri implementaciji funkcije getFirst koja je
ekvivalentna funkciji List.head .
Obrazac za uparivanje može biti ograničen logičkim izrazom. U tom slučaju do uparenja sa
odgovarajućom granom dolazi samo ako logički izraz ima vrednost true (tačan izraz).
Sledeći primer ilustruje primenu ograničenja na primeru implementacije funkcije round koja preslikava
ceo broj na broj iz intervala [0,100].
8/17/2019 Fsharp prirucnik
13/57
13 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Možete uočiti kako je obrazac za uparivanje bilo koje vrednosti “_”, ograničen izrazima x>100 i x
8/17/2019 Fsharp prirucnik
14/57
14 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Tip podataka sekvenca
Koncept
Sekvenca predstavlja skup vrednosti istog tipa. Prema operacijama koje se nad njom mogu primeniti
slična je listi . Jednostavne sekvence se definišu na sličan način kao i liste što pokazuje sledeći primer:
Ono što sekvencu razlikuje od liste je njena deklarativna priroda. Naime sekvenca ne čuva u memoriji
svoje članove već samo generatorski izraz (eng. sequence expression) koji prema potrebi generiše date
elemente sekvence. Mogli ste da primetite da se za potrebe prikazivanja u konzoli generišu samo prva četiri elementa sekvence.
Generisanje sekvenci
Generatorski izraz ima opšti oblik seq { for value in expr .. expr do yield expr } .
Sledeći primer ilustruje generisanje sekvence kvadrata prirodnih brojeva iz intervala [1,100], primenom
obe sintaksne forme.
Umsto do yield najčešće se koristi oznaka ‐>.
Mnoge funkcije koje kao parametre primaju sekvence mogu kao parametar primiti i druge,
srodne, tipove poput liste, niza ili neke druge .NET kolekcije.
8/17/2019 Fsharp prirucnik
15/57
15 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Sekvence se mogu ugnežđavati, tako da rezultat primene generatorskog izraza može biti sekvenca
sekvenci, što je prikazano u sledećem primeru:
Ukoliko želimo da umesto ugnežđenih sekvenci kao rezultat dobijemo kompoziciju sekvenci, potrebno je
da umesto yield naredbe upotrebimo naredbu yield!.
8/17/2019 Fsharp prirucnik
16/57
16 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Izraz za generisanje sekvenci može biti proizvoljne složenosti i sadržati u sebi druge naredbe. Sledeći
primer ilustruje sekvencu od 100 uređenih parova, pri čemu su neparni članovi sekvence zamenjeni
uređenim parom (0,0).
Programski jezik F# (III deo)
Funkcije i njihova primena
Funkcionalni literali
Programski jezik F# tretira vrednost funkcije nezavisno od njenog identifikatora (naziva). Pokazano je da
izraz poput “let sq x = x * x” , predstavlja samo skraćenu formu koja objedinjuje definisanje funkcionalnog
literala “(fun x ‐> x * x)” i njegovo vezivanje sa identifikatorom “sq”.
Funkcionalni literali mogu se upotrebiti na bilo kom mestu, na kojem se može upotrebiti vrednost nekog
drugog tipa, poput argumenta koji se prosleđuje drugoj funkciji ili operanda datog operatora.
8/17/2019 Fsharp prirucnik
17/57
17 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Funkcionalni literali često se primenjuju u kumbinaciji sa funkcijama projekcije, selekcije i agregacije.
Ove tri funkcije, koje služe za transformaciju liste ili sekvence čine jedan od najmoćnijih alata “klasičnog”
funkcionalnog programiranja.
Funkcije projekcije, selekcije i agregacije
Seq.map
Seq.map je funkcija projekcije koja na osnovu postojeće, kreira novu sekvencu primenom date funkcije.
Svaki element
u
generisanoj
sekvenci
je
rezultat
izvršavanja
funkcije
nad
elementom
postoje
će
sekvence.
Sledeći primer ilustruje projekciju sekvence brojeva od 1 do 1000 u sekvencu uređenih parova, pri čemu
je prvi član uređenog para broj iz originalne sekvence, a drugi član kvadrat datog broja.
Seq.filter
Seq.filter je funkcija selekcije koja kreira novu sekvencu filtriranjem postojeće, korišćenjem predikatske
funkcije.
Sledeći primer ilustruje selekciju elemenata sekvence čiji je prvi član paran broj:
Možete uočiti da je kao drugi argument funkcije projekcije upotrebljen identifikator „it“, pri
čemu dati identifikator nije eksplicitno definisan u kodu. Napisani kod se i pored toga uspešno
izvršava, pošto F# konzolni interpreter automatski povezuje rezultat izvršavanja izraza sa
identifikatorom „it“, ukoliko dati rezultat nije eksplicitno povezan sa nekim drugim
identifikatorom. U prethodnom primeru identifikator „it” je vezan sa seq {1..1000} , što se može
uočiti na osnovu konzolnog odgovora: val it : seq = seq [1;2;3;4; …]
Tip funkcije projekcije je (‘a ‐> b’) ‐> #seq ‐> #seq. Ova definicija označava funkciju koja
kao argumente prima redom funkciju i sekvencu, a kao rezultat generiše novu sekvencu. Treba
uočiti upotrebu znaka “#” u oznaci sekvencnog tipa #seq. Na ovaj način se označava da
funkcija projekcije, pored sekvence, može da primi i bilo koji drugi tip kompatibilian sa
sekvencom (npr. listu).
8/17/2019 Fsharp prirucnik
18/57
18 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
U oba prethodna primera korišćen je funkcionalni literal kao argument funkcije. Međutim u drugom
primeru kao parametar funkcionalnog literala upotrebljen je obrazac za uparivanje koji predstavlja
uređeni par, kod koga se prvi član para uparuje sa identifikatorom „x“, a drugi član se ne uparuje: fun
(x,_) ‐> x%2=0 . Iako drugi član para nije važan, ovakva forma funkcionalnog literala je neophodna zbog
kompatibilnosti tipova. Naime sekvenca koja se filtrira je sekvenca uređenih parova, pa prema tome ulazni parametar predikatske funkcije mora biti uređeni par.
Seq.fold
Funkcija agregacije je svakako najmoćnija i ujedno najkompleksnija od svih funkcija za transformaciju
sekvenci. Služi za izračunavanje agregirane vrednosti, primenom date funkcije na skup vrednosti (u
ovom slučaju sekvencu). Primena se vrši rekurzivno, tako što funkcija za agregaciju, agregira svaki član
sekvence sa prethodno izračunatim rezultatom. Funkcija agregacije prima tri parametra redom: funkciju
za agregaciju člana sekvence sa akumuliranim rezultatom, početnu vrednost akumulacije i sekvencu.
Sledeći primer ilustruje izračunavanje sume drugih članova (kvadrata), selektovanih uređenih parova.
Možete zapaziti da funkcija agregacije može zameniti naredbu ciklusa ( for, foreach) poznatu iz
imperativnog i objektno orijentisanog programiranja.
8/17/2019 Fsharp prirucnik
19/57
19 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Operatori za rad sa funkcijama
F# definiše više operatora za rad sa funkcijama među kojima su najznačajniji:
operator ulančavanja poziva funkcija (|>)
operator kompozicije funkcija (>>)
Operator ulančavanja poziva funkcija
Operator ulančavanja poziva funkcija omogućava programeru da pozove funkciju na takav način da, u
programskom kodu,
poslednji argument funkcije napiše pre njenog naziva. Sledeći primer ilustruje
navedenu sintaksu na primeru poziva kvadratne funkcije:
Ovakav način pisanja koda omogućava nam ulančavanje poziva funkcija, što je ilustrovano sledećim
primerom:
Operator kompozicije funkcija
Operator kompozicije funkcija omogućava kreiranje nove funkcije koja predstavlja kompoziciju
operanada. Primer koji sledi ilustruje primenu operatora kompozicije na funkcije „sq“ i „neg“ iz
prethodnog primera:
8/17/2019 Fsharp prirucnik
20/57
20 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Mogućnosti prikazanih operatora posebno dolaze do izražaja u kombimnaciji sa funkcijama projekcije,
selekcije i agregacije. Sledeći primer ilustruje navedeno, na primeru rešavanja problema računanja sume
kvadrata brojeva od 1 do 1000 u jednoj liniji koda:
Parcijalna primena funkcije
Parcijalna primena funkcije (engl. function currying) je mogućnost kreiranja nove funkcije pozivanjem
postojeće, pri čemu se neki argumenti izostavljaju.
Primer koji sledi, ilustruje kreiranje funkcija „inc“ (koja uvećava dati broj za jedan) i „dec“ (koja umanjuje
dati broj za jedan), parcijalnom primenom funkcije za izračunavanje zbira dva broja „add“.
8/17/2019 Fsharp prirucnik
21/57
21 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Parcijalna primena funkcije postaje posebno korisna u kombinaciji sa funkcijama projekcije, selekcije ili
agregacije. Sledeći primer ilustruje jednostavno kreiranje funkcije za sumiranje elemenata sekvence:
Rekurzivne funkcije
Funkcija koja u svom telu poziva samu sebe naziva se rekurzivnom. Tipična rekurzivna funkcija je
faktorijel (n! = n x (n‐1)!). Rekurzivne funkcije se u F#‐u moraju posebno označiti upotrebom ključne reči
rec ispred naziva funkcije.
Možda zvuči neobično, ali formalno gledano funkcija u F#‐u ne može da primi više od jednog
argumenta. Iako se tip funkcije „add“ int ‐> int ‐> int , najčešće i prirodno tumači kao funkcija
koja prima dva celobrojna argumenta i vraća ceo broj, za funkciju „add“ bi bilo ispravnije reći da
je funkcija koja prima celobrojni argument i vraća funkciju koja ima tip int ‐> int .
Sintaksna forma let add x y = x + y predstavlja samo pregledniji oblik za let add x = (fun y ‐> x+y),
što je takođe pregledniji oblik za još kompleksniju formu let add = (fun x ‐> ( fun y ‐> x+y )).
Iz prikazanog sledi da je mogućnost parcijalne primene funkcija prirodna posledica strukture
programskog jezika F#.
8/17/2019 Fsharp prirucnik
22/57
22 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Ukoliko imamo dve funkcije koje međusobno pozivaju jedna drugu, onda kažemo da su te dve funkcije
međ usobno rekurzivne. U F# kodu je neophodno da međ usobno rekurzivne funkcije budu definisane
neposredno jedna za drugom i spojene pomoću ključne reči and. To omogućava F# kompajleru da ove
dve funkcije posmatra kao jednu celinu sa stanovišta automatskog utvrđivanja tipa.
Operatori Operatori u F#‐u su specijalne funkcije čiji se nazivi sastoje od simbola: „!%&*+-./?@^|~:“, pri čemu
simbol „:“ ne može biti na prvoj poziciji. Naziv operatora se prilikom definisanja funkcije piše između
zagrada. Primena operatora značajno povećava čitljivost koda.
Sledeći primer ilustruje definisanje operatora „!“ za izračunavanje faktorijela datog broja.
Upotreba ključne reči rec možda deluje suvišno, pošto najveći broj savremenih kompajlera
automatski prepoznaje rekurzivno definisane funkcije. Treba uzeti u obzir da F# kompajler ima
teži zadatak pošto pri kompajliranju vrši i automtsko prepoznavanje tipa. Posledica toga je
neophodno označavanje rekurzivnih funkcija ključnom reči rec.
8/17/2019 Fsharp prirucnik
23/57
23 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Programski jezik F# (IV deo)
Kompleksni funkcionalni tipovi podataka
Tip podataka slog (record)
Tip podataka slog omogućava programeru da grupiše više vrednosti u vrednost jednog tipa. Za razliku od
n‐torke slog omogućava imenovanje datih vrednosti. Imenovana vrednost u okviru sloga se naziva polje.
Slog definišete navođenjem parova naziv/tip kao što je ilustrovano na sledećem primeru:
Pošto ste definisali tip možete definisati i vrednosti datog tipa, navođenjem vrednosti za svako polje.
Možete uočiti da je F# kompajler automatski izvršio inferenciju tipa identifikatora “s”.
Vrednostima koje se nalaze u slogu možete pristupiti primenom operatora pristupa polju “.”.
8/17/2019 Fsharp prirucnik
24/57
24 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Ukoliko želite da definišete više slogova koji se razlikuju samo po vrednosti jednog polja možete
upotrebiti tehniku kloniranja sloga koja je ilustrovana na sledećem primeru:
Za kreiranje slogova se često koristi i generatorska funkcija koja omogućava korišćenje jednostavnije
sintakse za kreiranje slogova. Pored toga u okviru same funkcije moguće je izvršiti transformaciju
argumenata u vrednosti polja sloga. Sledeći primer ilustruje ovu tehniku:
8/17/2019 Fsharp prirucnik
25/57
25 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Tip podataka unija diskriminatora (discriminated union)
Unija diskriminatora predstavlja tip podataka čija vrednost može biti u skladu sa samo jednim od
definisanih diskriminatora. U svom najjednostavnijem obliku diskriminator predstavlja jednu vrednost a
unija diskriminatora skup vrednosti. Tada tip unija diskriminatora semantički podseća na tip
“enumeracija” u programskom jeziku C#.
Za razliku od elementa enumeracije diskriminatoru možemo pridružiti vrednost proizvoljnog tipa, pri
čemu dati tip ne mora biti isti za sve diskriminatore. Sledeći primer prikazuje definisanje unije
diskriminatora koja opisuje prevozno sredstvo. Pri tome je automobilu pridružen par niski znakova koje
označavaju marku i model, autobusu je pridružen broj linije, a biciklu nije pridružen nikakav podatak.
8/17/2019 Fsharp prirucnik
26/57
26 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Prilikom definisanja vrednosti tipa unija diskriminatora navodimo samo diskriminator, a kompajler vrši
inferenciju tipa.
Programski jezik F# omogućava definisanje aliasa za tipove pomoću sintaksne forme:
type alias = tip
Ova funkcionalnost
se
često
upotrebljava
prilikom
definisanja
unije
diskriminatora
radi
povećanja čitljivosti. Primenom aliasa, kod iz prethodnog primera ste mogli napisati na sledeći
način:
8/17/2019 Fsharp prirucnik
27/57
27 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Vrednost tipa unije diskriminatora se može uparivati prema obrascu. Pri tome se uparivanje može vršiti
na osnovu diskriminatora i pridruženih vrednosti.
Unija diskriminatora je tip podataka koji nam omogućava da pišemo veoma efikasan funkcionalni kod.
Sledećih nekoliko primera ilustruju njegovu primenu.
Modelovanje strukture podataka
Prvi primer prikazuje modelovanje strukture podataka pomoću unije diskriminatora koja ima samo jedan
diskriminator za koga su vezani podaci.
8/17/2019 Fsharp prirucnik
28/57
28 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Prednost ovakvog rešenja u odnosu na slog je uočljiva na primeru pisanja funkcije koja kao argument
prima strukturu Point3D.
Možete uočiti da je navedeni argument definisan preko segmenata diskriminatora Vector3D čime je
omogućeno da telo funkcije bude napisano kratko i jasno.
Modelovanje struktura u obliku stabla
Unije diskriminatora su idealne za modelovanje struktura u obliku stabla kao i za implementaciju
operacija nad njima. Sledeći primer ilustruje primenu unije diskriminatora za modelovanje binarnog
stabla.
8/17/2019 Fsharp prirucnik
29/57
29 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Za ovako definisano binarno stablo jednostavno je napisati rekurzivnu funkciju koja prolazi kroz njega.
Sledeći primer prikazuje funkciju koja vraća broj čvorova u stablu.
Modelovanje domenski specifičnih jezika
Sintaksa programskog jezika F# sadrži više sintaksnih elemenata koji omogućavaju modelovanje
domenski specifičnih jezika. Modelovanje domenski specifičnog jezika pomoću unije diskriminatora je
veoma jednostavno, mada složeniji problemi iz date oblasti zahtevaju upotrebu drugih sintaksnih
elemenata i drugačiji pristup.
Sledeći primer ilustruje primenu unije diskriminatora za modelovanje predikatske logike:
Uočite da definicaja unije diskriminatora može biti rekurzivna.
8/17/2019 Fsharp prirucnik
30/57
30 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Sada je lako definisati funkciju za evaluaciju datog izraza.
Tip podataka opcija (option)
Opcija je tip podataka koji služi za modelovanje vrednosti koje mogu ali ne moraju da budu postavljene.
Predstavlja specifičan slučaj unije diskriminatora definisane kao:
type ‘a option = None | Some of ‘a
Tip opcija se najčešće upotrebljava za povratnu vrednost funkcije koja nema definisan izlaz za sve
vrednosti ulaza.
Tipičan primer takve funkcije je funkcija koja konvertuje nisku znakova u ceo broj. Ukoliko niska znakova
ne predstavlja broj, funkcija ne može da vrati smislen rezultat.
Programski jezik C# koristi null vrednost za slučaj kada vrednost nije definisana. Međutim null vrednost može da znači i da vrednost nije inicijalizovana. Ova dualnost često dovodi do grešaka i
otežava razumevanje koda.
8/17/2019 Fsharp prirucnik
31/57
31 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Biblioteke programskog jezika F# sadrže veći broj funkcija za rad sa opcijama. Najznačajnije od njih su:
Option.isSome vraća true ukoliko argument ima vrednost, inače false
Option.isNone vraća true ukoliko argument nema vrednost, inače false
Option.get vraća vrednost ukoliko ona postoji, inače izbacuje izuzetak
Sledeći primer ilustruje upotrebu navedenih funkcija:
Programski jezik F# (V deo)
Imperativno programiranje Pod imperativnim programiranjem se podrazumeva pisanje programa, koji tokom izvršavanja više puta
upisuju podatke na istu memorijsku lokaciju. U programskim jezicima, kao što su C++, C# ili Visual Basic
to je potpuno uobičajno. Nasuprot, tome naredba let u F#‐u prilikom svakog povezivanja vrednosti sa
identifikatorom upisuje vrednost u novu memorijsku lokaciju.
8/17/2019 Fsharp prirucnik
32/57
32 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Naravno, ponekad postoji potreba da se i u F# programima piše imperativni kod. To je posebno slučaj
kad se postojeći, složeni algoritmi, prevode sa nekog imperativnog programskog jezika (poput C++a ili
Fortrana) prenose u F#.
Promenljive strukture
Osnovu imperativnog programiranja čine tipovi podataka, definisani tako da omogućavaju promenu
sopstvenih instanci kroz promenu memorijskog prostora koje instance zauzimaju.
Sintaksa programskog jezika F# razlikuje tri vrste promenljivih struktura, i to:
Lokalne promenljive
Reference
Slogove sa promenljivim poljima
Lokalne promenljive
Lokalne promenljive definišu se na sličan način kao i identifikatori, pri čemu se posle naredbe
povezivanja let upotrebljava ključna reč mutable. Promena lokalne promenljive vrši se pomoću
operatora strelica ulevo (
8/17/2019 Fsharp prirucnik
33/57
33 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Zbog toga se umesto lokalnih promenljivih često koriste reference (engl. reference cells).
Reference
Referenca predstavlja objektni omotač (ćeliju) u kojoj je smeštena vrednost koja se može menjati tokom
izvršavanja programa. Vrednost se smešta u referencu primenom funkcije ref .
Sadržaju reference pristupa se pomoću operatora (!), dok se za izmenu sadržaja koristi operator (:=).
Slogovi sa promenljivim poljima
Sintaksa programskog jezika F# omogućava definisanje slogova sa promenljivim poljima. Promenljiva
polja definišu se pisanjem ključne reči mutable ispred naziva polja. Sledeći primer ilustruje korišćenje
sloga sa promenljivim poljima kroz implementaciju imenovanog brojača.
8/17/2019 Fsharp prirucnik
34/57
34 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Nizovi
Niz (engl. array ) je kolekcija promenljivih elemenata istog tipa. Implemetacija niza je takva da su
elementi koji ga čine smešteni u memoriji neposredno jedan posle drugog. Zbog toga je pri deklaraciji
niza potrebno tačno znati koliko će elemenata biti u nizu. Prednost ovakve implementacije je u tome što
omogućava efikasan pristup proizvoljnom elementu niza.
Nizovi se mogu kreirati pomoću generatorskih izraza, poput lista i sekvenci, ili zadati kao lista vrednosti
odvojenih znakom ; između znakova [| i |] .
Elementima niza pristupa se pomoću operatora indeksiranja (.[]) . Operator indeksiranja upotrebljava se
kako kod čitanja tako i kod menjanja sadržaja elementa niza.
8/17/2019 Fsharp prirucnik
35/57
35 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Operator indeksiranja omogućava izdvajanje podniza kada se koristi u sintaksnoj formi
arr.[donjaGranica .. gornjaGranica] . Ukoliko donja granica nije specificirana, za donju granicu se uzima
prvi element niza. Slično tome, ukoliko gornja granica nije specificirana, za gornju granicu se uzima
poslednji element niza.
F# biblioteke sadrže i veći broj funkcija za rad sa nizovima. U ovom poglavlju prikazaćemo samo osnovne
funkcije i to:
Array.length vraća dužinu niza
Array.zeroCreate kreira niz popunjen podrazumevanim vrednostima elementa za dati tip
Array.append omogućava spajanje dva niza
8/17/2019 Fsharp prirucnik
36/57
36 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Pored navedenih, od izuzetnog značaja za rad sa nizovima su i funkcije projekcije selekcije i agregacije:
Array.map funkcija projekcije
Array.filter funkcija selekcije
Array.fold funkcija agregacije
koje su semantički ekvivalentne odgovarajućim funkcijama za rad sa listama.
Promenljive kolekcije
Promenljive kolekcije, pored mogućnosti izmene elemenata koje se u njima nalaze, imaju i mogućnost
dodavanja i uklanjanja elemenata. Mogućnost promene veličine kolekcije tokom vremena, je značajna u
situacijama kada unapred nije poznato koliko će elemenata biti u kolekciji ( npr. kada se u kolekciju
smešta rezultat upita u bazu podataka ).
Promenljive kolekcije nisu specifične za F#, već se nalaze u standarndnim .NET bibliotekama u prostoru
imena System.Collections.Generic.
List
Kolekcija List predstavlja niz promenljive dužine. Interna implementacija ove kolekvcije je zasnovana
na nizovima, tako da je pristup elementima kolekcije veoma efikasan.
Pošto se kolekcija List nalazi u prostoru imena System.Collections.Generic pre kreiranja same
kolekcije potrbno je uključiti navedeni prostor imena.
8/17/2019 Fsharp prirucnik
37/57
37 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
U kolekciju je moguće dodati element korišćenjem metode Add , odnosno sekvencu elemenata
korišćenjem metode AddRange. Broj elemenata koji se nalaze u kolekciji može se očitati pomoću
svojstva Count .
Uklanjanje elementa iz kolekcije vrši se pomoću metode Remove. Ova metoda vraća logičku vrednost
true ukoliko je element uklonjen iz kolekcije, a logičku vrednost false ukoliko se element nije ni nalazio u
kolekciji.
F# konzolni interpreter ne prikazuje automatski sadržaj instance tipa List. Ukoliko postoji potreba za prikazom sadržaja, isti se može dobiti upotrebom funkcije printfn “%A” .
8/17/2019 Fsharp prirucnik
38/57
38 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Elementi liste mogu se menjati na isti način kao i elementi niza.
Pored navedenih, metoda i svojstava od značaja za rad sa kolekcijama tipa List su i sledeće metode:
Contains Vraća logičku vrednost true ako je element sadržan u kolekciji
IndexOf Vraća indeks elementa u kolekciji. Ako se element ne nalazi u kolekciji vraća ‐1
Insert Dodaje element u kolekciju, na lokaciju sa datim indeksom
Dictionary
Kolekcija Dictionary predstavlja asocijativni niz. Koristi se kada je potrebno elementima pristupiti
po asociranoj vrednosti (ključu), umesto po indeksu.
8/17/2019 Fsharp prirucnik
39/57
39 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Asocirana vrednost za dati ključ očitava se pomoću operatora indeksiranja koji prima ključ kao
parametar. Ukoliko sa datim ključem nije asocirana neka vrednost, dolazi do pojave izuzetka1 i
eventualno do prekida programa.
Kad god postoji mogućnost da sa datim ključem nije asocirana vrednost, poželjno je koristiti metodu
TryGetValue. Ova metoda vraća uređeni par. Prvi član uređenog para je logičkog tipa i ima vrednost true
ili false, zavisno od toga da li je sa datim ključem asocirana neka vrednost ili ne. Drugi član uređenog
para je tražena vrednost, odnosno specijalna vrednost null , ukoliko ne postoji vrednost koja je asocirana
sa datim ključem.
1 O izuzetcima će biti više reči kasnije u ovom tekstu
8/17/2019 Fsharp prirucnik
40/57
40 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Ciklusi
Imperativno programeranje podrazumeva eksplicitnu kontrolu toka izvršavanja programa. Takva
kontrola podrazumeva i upotrebu ciklusa koji omogućavaju repetativno izvršavanje određenog dela
koda, određeni broj puta, odnosno do ispunjenja datog uslova.
Programski jezik F# podržava while ciklus i dve vrste for ciklusa.
While ciklus
While ciklus se izvršava sve dok uslov ciklusa vraća logičku vrednost true. Sledeći primer ilustruje
primenu while ciklusa u funkciji za izračunavanje zbira celih brojeva u zatvorenom intervalu [n,m].
For ciklus For ciklus se koristi kada je unapred poznat broj iteracija koje treba da budu izvršene.
Jednostavna forma for ciklusa podrazumeva postojanje celobrojne ciklusne promenljive (brojača) u
zaglavlju ciklusa, koja uzima vrednosti između donje i gornje granice. Sledeći primer je u funkcionalnom
smislu ekvivalentan prethodnom samo što je ovaj put za rešavanje problema upotrebljena jednostavna
forma for ciklusa.
8/17/2019 Fsharp prirucnik
41/57
41 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Nabrojiva forma for ciklusa podrazume postojanje ciklusne promenljiva koja uzima vrednosti redom iz
proizvoljne sekvence. U primeru koji sledi zatvoreni interval celih brojeva zadat je sekvencom u formi
liste celih brojeva od n do m.
Izuzetci
Da bi se obezbedila pouzdanost programa neophodno je vešto upravljanje neočekivanim ili izuetnim
situacijama. Pod neočekivanim i izuzetnim situacijama podrazumeva se neispravnost podataka, uređaja
ili nedostupnost servisa ( npr. Internet konekcije ). Ukoliko se dogodi neka od napred opisanih situacija,
u .NET programu dolazi do genereisanja izuzetka (engl. exception).
Izuzetak je neispravnost u .NET programu, koja prekida normalni tok programa, tako što dolazi do
automatskog prekida svake funkcije u lancu poziva, sve do obrade izuzetka u segmentu koda za obradu
izuzetaka (engl. exception handler ). Ako takav segment ne postoji dolazi do prekida programa.
Generisanje izuzetaka
Ukoliko funkcija ne može da vrati odgovarajuću vrednost za određene vrednosti argumenata, poželjno je
da u tom slučaju generiše izuzetak.
8/17/2019 Fsharp prirucnik
42/57
42 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Izuzetci se najjednostavnije generišu pomoću funkcije failwith, koja kao parametar prima odgovarajuću
poruku.
Iako je poruka o grešci sama po sebi korisna,u skladu sa pravilima dobre prakse potrebno je generisati
tipizirani izuzetak.
Tipizirani
izuzetci
generišu
se
pomo
ću
funkcije
raise.
Pre
koriš
ćenja
tipiziranih
izuzetaka neophodno je uključiti prostor imena System.
Čitljivost koda se može dodatno poboljšati definisanjem programski specifičnih (engl. custom) klasa
izuzetaka.
8/17/2019 Fsharp prirucnik
43/57
43 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Obrada izuzetaka
Obrada izuzetaka vrši se pomoću try ‐with narebe. Try ‐with naredba sastoji se iz try bloka naredbi i with
skupa pravila za uparivanje po obrascu. Try blok naredbi sadrži skup naredbi koje mogu generisati
izuzetak. Ukoliko neka od naredbi iz try bloka generiše izuzetak, .NET izvršno okruženje će pokušati da
upari generisani izuzetak sa nekim od pravila za uparivanje iz with skupa. Ukoliko dođe do uparivanja izvršavaju se naredbe u okviru odgovarajućeg pravila za uparivanje i program nastavlja sa izvršavanjem.
U suprotnom prekida se izvršavanje trenutne funkcije, a izuzetak se prosleđuje sledećoj funkciji u lancu
poziva.
Ukoliko postoji potreba da se posle izvršenja skupa naredbi izvrši drugi skup naredbi, nevezano za to da
li je pri izvršavanju prvog skupa naredbi došlo do generisanja izuzetka ili ne, koristi se try ‐ finally
naredba.
Try ‐ finally naredba sastoje iz try bloka naredbi i finally bloka naredbi. Try blok naredbi sadrži naredbe
koje mogu da generišu izuzetak, dok finally blok naredbi sadrži naredbe koje se izvršavaju po izlasku iz
try bloka naredbi.
Karakterističan primer primene try ‐ finally naredbe je fragment koda koji koristi resurs koji se eksplicitno
mora vratiti operativnom sistemu na korišćenje (npr. datoteka).
8/17/2019 Fsharp prirucnik
44/57
44 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Za razliku od programskog jezika C# čijom je sintaksom definisana naredba try ‐catch‐ finally , sintaksa
programskog jezika F# ne poznaje naredbu try ‐with‐ finally .
Programski jezik F# (VI deo)
Objektno orijentisano programiranje
Najveći deo
.NET
platforme
napisan
je
u
objektno
orijentisanim
programskim
jezicima,
prvenstveno
u
programskom jeziku C#. Zato je poznavanje objektno orijentisanog programiranja (OOP) od ključne
važnosti za korišćenje brojnih .NET biblioteka. Cilj ovog poglavlja nije da nauči čitaoca objektno
orijentisanom programiranju( to bi bilo previše ambiciozno), već da prikaže kako su objektno orijentisani
koncepti utkani u F#.
Objektno orijentisan stil programiranja pogodan je za pisanje kompleksnih softverskih sistema.
Navedena pogodnost se ogleda u mogućnosti da se objekti iz realnog sveta modeluju pomoću
softverskih abstrakcija, klasa.
Klasa Klasa je sintaksni element koji povezuje funkcije i podatke. Sintaksa programskog jezika F# definiše više
elemenata koji se iz objektno orijentisanih programskih jezika, poput C#‐a, „vide“ kao klase. To su:
Slog
Unija diskriminatora
Izuzetak
Klasa
Obratite pažnju na liniju koda f.WriteLine(text:string). Pošto je definisano više varijanti metode
WriteLine koje primaju jedan parametar i koje se razlikuju samo po tipu parametra, kompajler
nije u mogućnosti da automatski odredi sa kojom od tih varijanti da poveže poziv dati poziv. Zbog
toga je neophodno dati sugestiju kompajleru (eng. compiler hint ) koja precizno definiše koja
varijanta metode WriteLine treba da bude pozvana. U ovom slučaju to je WriteLine(string).
8/17/2019 Fsharp prirucnik
45/57
45 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Modul
Slog, unija diskriminatora i izuzetak prikazani su u prethodnim poglavljima. Ovaj odeljak bavi se
sintaksnim elementom koji je označen kao klasa u specifikaciji programskog jezika F#.
Sledeći primer prikazuje definisanje klase Vector2D:
Objekat klase Vector2D kreiramo navođenja imena klase i prosleđivanjem vrednosti parametara
potrebnih za inicijalizaciju objekta.
Broj i tip vrednosti koje se prosleđuju prilikom kreiranja objekta klase Vector2D definisan je formom
zaglavlja definicije klase:
type Vector2D(dx:float, dy:float)=
Radi boljeg razumevanja biće prikazana ekvivalentna C# sintaksa:
8/17/2019 Fsharp prirucnik
46/57
46 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Možete uočiti da zaglavlje definicije klase u F#‐u, u semantičkom smislu, igra ulogu koju ima konstruktor
u C#‐u, pa se u skladu sa time i naziva implicitni konstruktor. Implicitni konstruktor, uporedo sa
parametrima, definiše i privatna polja istog tipa i naziva koje imaju i parametri. Ovako definisana polja
mogu se koristiti u svim članovima klase.
Pored polja članovi klase mogu biti svojstva (engl. properties) i metode.
Svojstvo
Svojstva služe za pristup podacima. Najčešće su to “sirovi” podaci, prezentovani na način kako su
definisani u poljima, ali mogu biti i izračunate vrednosti (npr. svojstvo Length zavisi od veličine više
polja). Sledeći primer ilustruje korišćenje svojstava DX , DY i Length.
Svojstva DX i DY, iz prethodnog primera, definisana su korišćenjem skraćene sintakse: member t.DX = dx
Ovakva sintaksna forma omogućava samo očitavanje vrednosti svojstva i ekvivalentna je sledećem C# kodu:
class Vector2D
{ private readonly float dx;
private readonly float dy;
public Vector2D(float dx, float dy)
{ this.dx = dx;
this.dy = dy; }
}
8/17/2019 Fsharp prirucnik
47/57
47 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Slično kao i u drugim objektno orijentisanim programskim jezicima, svojstva mogu pripadati klasi umesto
pojedinim objektima date klase. Takva svojstva nazivaju se statička, a u programskom kodu označavaju
se pomoću ključne reči static:
static member Zero = Vector2D(0.,0.)
Statička svojstva najčešće se koriste za kreiranje specifičnih objekata date klase (npr. nula vektor).
Metoda
Metoda predstavlja operaciju koju je moguće izvršiti nad objektom. Prilikom definisanja metode u
zaglavlju se pored naziva navodi i skup parametara potrebnih za njeno pozivanje. U primeru je data
metoda Scale koja prima parametar k tipa float i vraća Vector2D objekat čije su dimenzije uvećane k
puta.
member t.Scale(k) = Vector2D(k*dx,k*dy)
class Vector2D {
...
public float DX { get { return dx; } }
public float DY { get { return dy; } } public float Length { get { return (float)Math.Sqrt(dx*dx+dy*dy); } }
}
8/17/2019 Fsharp prirucnik
48/57
48 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Možete uočiti da nijedno od svojstava ili metoda prikazanih u prethodnom primeru ne menja stanje
postojećeg objekta već kreira novi objekat inicijalizovan na promenjeno stanje. Zbog toga za klasu
Vector2D kažemo da je nepromenljiva (engl. immutable).
Iako je preporučeno da F# klase budu nepromenljive, moguće je napisati i klasu koja tokom izvršenja
programa menja svoje stanje.
Promenljiva klasa
Definisanje promenljive klase ilustrovano je na primeru koji je funkcionalno sličan prethodnom:
Možete uočiti da su polja klase eksplicitno definisana i definisana kao promenljiva, mada se i dalje koristi
implicitni konstruktor.
Promenljiva svojstva su definisana tako da sadrže programski kod za očitavanje (get ) i promenu (set ):
member t.DX with get()=dx and set(v)=dx
8/17/2019 Fsharp prirucnik
49/57
49 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Sada je moguće napisati kod koji menja stanje objekta korišćenjem svojstva i operatora promene stanja
(
8/17/2019 Fsharp prirucnik
50/57
50 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Testiranje metode Scale pokazuje da se njenim pozivom menja objekat nad kojim je metoda pozvana i
da identifikator v2 koji je povezan sa povratnom vrednošću metode referiše isti objekat kao i
identifikator v sa kojim je objekat povezan prilikom kreiranja.
Programski jezik F# (VII deo)
Napredni koncepti
Sledeći primer ilustruje napredne koncepte poput indeksiranih svojstava, preklapanja operatora i
imenovanih i opcionih argumenata.
8/17/2019 Fsharp prirucnik
51/57
51 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Indeksirano svojstvo
Indeksirana svojstva (engl. indexers) omogućavaju da se podacima pristupa pomoću operatora
indeksiranja (.[ ]). Datu funkcionalnost treba implementirati samo ukoliko ona ima logičkog smisla. U
prethodnom primeru implementacija indeksiranog svojstva omogućava nam da koordinatama vektora
pristupimo preko indeksa, pri čemu x koordinati odgovara indeks 0, a y koordinati vrednost indeksa 1.
Preklapanje operatora
Preklapanje operatora podrazumeva definisanje operatora (npr. + ili ‐) za proizvoljnu korisnički
definisanu klasu. Operator se definše implementiranjem statičke metode koja umesto imena sadrži
simbol operatora u zagradama:
static member (+) (a:Vector2D,b:Vector2D) = Vector2D(a.DX+b.DX, a.DY+b.DY)
Sledeći primer ilustruje upotrebu operatora:
Imenovani i opcioni argumenti
Sintaksa programskog jezika F#, omogućava programeru, da prilikom prosleđivanja parametra metodu,
imenovanjem poveže vrednost sa odgovarajućim argumentom.
8/17/2019 Fsharp prirucnik
52/57
52 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Mogućnost da se argument proglasi za opcioni, omogućava programeru, da izbegne definisanje većeg
broja funkcionalno istih metoda sa različitim brojem parametara. Argument se označava kao opcioni
tako što se ispred njegovog naziva stavi upitnik.
member t.Scale(k,?k2) =
let defK2 = defaultArg k2 1.
dx
8/17/2019 Fsharp prirucnik
53/57
53 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Interfejs Interfejs predstavlja sintaksni element koji omogućava implementaciju „može da“ relacije (engl. can do).
Ova relacija označava da objekat date klase može da izvrši skup opercija. Interfejs služi da definiše dati
skup operacija bez definisanja njihove implementacije.
Pomoću interfejsa se najčešće povezuju klase koje implementiraju skup operacija na potpuno različite
načine. Primer takvog interfejsa bio bi IShape interfejs koji definiše metodu Contains. Metoda Contains
vraća true, odnosno false u zavisnosti od toga da li prosleđeni par realnih vrednosti predstavlja
koordinate tačke u okviru date figure.
Za razliku od C#‐a, programski jezik F# podržava isključivo eksplicitnu implementaciju interfejsa. Sintaksa
je prikazana na primeru definisanja klasa Circle i Square koje implementiraju IShape interfejs.
Pošto je implementacija interfejsa eksplicitna, potrebno je pre poziva metode interfejsa izvršiti
konverziju objekta u dati interfejs. Konverzija se vrši pomoću operatora konverzije (:>), na način koji je
prikazan u sledećem primeru:
8/17/2019 Fsharp prirucnik
54/57
54 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Anonimna klasa
Programski jezik F# podržava i implementaciju interfejsa kreiranjem anonimne klase iz interfejsa. Tako
kreirana anonimna klasa sadrži isključivo metode interfejsa, a za objekat date klase nije potrebno vršiti
konverziju u interfejs kako bi se pozivale metode definisane u interfejsu.
Za kreiranje anonimnih klasa koristi se objektni izraz. Objektni izraz za kreiranje anonimne klase bazirane
na interfejsu sastoji se od para vitičastih zagrada, u okviru kojih se nalazi operator new , za kojim sledi
naziv interfejsa, a potom i implementacija interfejsa sintaksno identična implementaciji prikazanoj na
primeru definisanja klasa Circle i Square.
Objektni izraz se u praksi najčešće koristi u okviru generatorske funkcije koja prima parametre potrebne
za kreiranje objekta date anonimne klase, kao što je to prikazano u sledećem primeru.
Abstraktna klasa Delimično implementirana klasa naziva se abstraktna klasa. Abstraktna klasa može da sadrži deklarisane
(abstraktne) i implementirane članove. Pošto abstraktni članovi nemaju implementaciju, nemoguće je
kreirati objekat za datu abstraktnu klasu. Abstraktna klasa se najčešće koristi kao korena klasa u
hijerarhiji klasa, kada sve klase u hijerarhiji dele određenu zajedničku implementaciju.
8/17/2019 Fsharp prirucnik
55/57
55 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Prilikom definisanja abstraktne klase neophodno je markirati datu klasu atributom AbstractClass.
Sledeći primer prikazuje definisanje klase Shape koja sadrži abstraktnu metodu Contains i metodu Print
koja ima podrazumevanu implementaciju.
Klasa Circle nasleđuje abstraktnu klasu Shape i implementira metodu Contains.
Moguće je kreirati objekat tipa Circle i pozivati metode Contains i Print za dati objekat.
8/17/2019 Fsharp prirucnik
56/57
56 Micorosoft „Partner u učenju“ časopis za nastavnike http://casopis.spaces.live.com
Možete uočiti, da se metoda Print izvršava na način na koji je implementirana u Shape klasi. Metodu
Print moguće je predefinisati (engl. override) tako da se izvršava po algoritmu koji je specifičan za datu
klasu.
Modul Modul u F#‐u predstavlja način grupisanja funkcija. U C#‐u se za tu namenu koristi statička klasa.
Sledeći primer ilustruje definisanje modula Vector koji sadrži funkciju length, kao i način pozivanja
navedene funkcije.
8/17/2019 Fsharp prirucnik
57/57
Ekvivalentan C# kod glasi:
KRAJ SERIJALA
Autor: Srđan Božović
public static class Vector
{
public static float length(Vector2D v) {
return (float)Math.Sqrt(v.DX * v.DX + v.DY * v.DY); }
}