Luentokalvot - Funktionaalinen ohjelmointi
Transcription
Luentokalvot - Funktionaalinen ohjelmointi
*x++=*y++ 815338A Ohjelmointikielten periaatteet 2014 - 2015 VI Funktionaalinen ohjelmointi *x++=*y++ Sisältö 1. 2. 3. 4. 5. Johdanto ja peruskäsitteitä LISP- ja Scheme-kielet Haskell Muita funktionaalisia kieliä Funktionaalisten ja imperatiivisten kielten vertailua Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 2 *x++=*y++ VI.1. Johdanto ja peruskäsitteitä Vaihtoehtoja imperatiiviselle ja olioparadigmalle: Funktionaalinen ohjelmointi ja logiikkaohjelmointi Yleisnimi deklaratiivinen ohjelmointi Joissakin lähteissä vain logiikkaohjelmointi deklaratiivista Imperatiivisten ohjelmointikielten tunnusmerkit Perustuvat von Neumannin arkkitehtuuriin Fyysisiin muistipaikkoihin sidottujen muuttujien käyttö Sijoituslause Iteratiivisen toiston tehokas soveltaminen Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 3 *x++=*y++ VI.1. Johdanto ja peruskäsitteitä (2) Funktionaalinen ohjelmointi Luovutaan komennoista Suoritetaan operaatiot lausekkeita käyttämällä, erityisesti funktioita toistuvasti soveltamalla Funktiot peruselementtejä Vastaavat muuttujia imperatiivisessa ohjelmoinnissa Ei sijoituslausetta Toisto tyypillisesti rekursiolla Monissa funktionaalisissa kielissä imperatiivisia piirteitä Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 4 *x++=*y++ VI.1.1. Matemaattiset funktiot ja korkeamman asteen funktiot (higher order functions) Matemaattisella funktiolla ei voi olla sivuvaikutuksia Ero imperatiivisen ohjelmoinnin funktioon Ainoa toimenpide palauttaa argumenttia vastaava arvo, joka on aina samalla argumentin arvolla sama Korkeamman asteen funktioita kutsutaan myös funktionaalisiksi muodoiksi (functional forms) Voivat ottaa parametreikseen funktioita Paluuarvo voi olla funktio Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 5 *x++=*y++ VI.1.2. Tavallisia funktionaalisia muotoja Funktioiden yhdistäminen (kompositio) Funktioiden f ja g yhdistetty funktio h = f○g; h(x) = f(g(x)) Esimerkki. Jos f(x) = x2 ja g(x) = 2x+1, h(x) = f○g(x) = f(g(x)) = f(2x+1) = (2x+1)2 = 4x2 + 4x +1 Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 6 *x++=*y++ VI.1.2. Tavallisia funktionaalisia muotoja (2) Konstruktio saadaan soveltamalla annetun funktiolistan jokaista funktiota yhteen argumenttiin: saadaan arvojen lista, jossa on yhtä monta alkioita kuin funktioita oli listassa Esimerkki f(x) = 3x-1 ja g(x) = x4+2 [f,g](3) tuottaa listan (8,83) Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 7 *x++=*y++ VI.1.2. Tavallisia funktionaalisia muotoja (3) Sovella kaikkiin: Sovelletaan samaa funktiota listan kaikkiin alkioihin Merkitään symbolilla α Esimerkki f(x) = x/3 -> operaation α(f,(1,2,3)) tuloksena (1/3,2/3,1) Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 8 *x++=*y++ VI.1.3 Funktionaalisen ohjelmoinnin peruskäsitteitä Viittauksen läpinäkyvyys (referential transparency): Funktio antaa samoilla parametreilla aina saman tuloksen Tiukka semantiikka (strict semantics) Funktiota ei evaluoida ennen kuin sen parametrit on täysin evaluoitu Noudatetaan yleensä imperatiivisissa ja useissa funktionaalisissa kielissä Ellei voimassa, semantiikka joustava (non-strict) Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 9 *x++=*y++ VI.1.3 Funktionaalisen ohjelmoinnin peruskäsitteitä (2) Innokas evaluointi (eager evaluation) : funktion ja lausekkeen arvo lasketaan välittömästi sen parametrien kulloisillakin arvoilla Käytetään kaikissa imperativiisissa ja monissa funktionaalisissa kielissä Laiska evaluointi (lazy evaluation): lausekkeen arvo evaluoidaan vasta kun sitä tarvitaan ja evaluointi tapahtuu ainoastaan kerran Mahdollinen jos semantiikka joustava Mahdollistaa näennäisesti äärettömien rakenteiden kirjoittamisen Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 10 *x++=*y++ VI.2. LISP- ja Scheme-kielet VI.2.1 LISP John McCarthy: LISP vuonna 1958 MIT:n tekoälyprojektin yhteydessä Haluttiin kieli, jolla vahva matemaattinen pohja McCarthy: rekursiivisten funktioiden teoria soveltuu perustaksi paremmin kuin Turingin koneeseen perustuvat mallit Mahdollisuus listojen käsittelyyn Funktion käsitteen mahdollisimman laaja soveltaminen Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 11 *x++=*y++ VI.2.1 LISP (2) McCarthy: LISPin yleisfunktio eval , joka laskee minkä tahansa LISP-funktion arvon -> Ensimmäinen LISP – tulkki kun huomattiin, että implementoituna voidaan käyttää tulkkina Ensimmäinen kääntäjä toteutettiin LISPillä Tiettävästi ensimmäinen kerta, kun kielen kääntäjä kirjoitetaan samalla kielellä LISPistä monia murteita, COMMON LISP ja Scheme yleisimmin käytössä Tässä esitettävät ominaisuudet koskevat myös Schemeä Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 12 *x++=*y++ VI.2.1.1 LISPin symbolit Koostuvat kirjaimista, numeroista ja eräistä sallituista erikoismerkeistä Luvut eivät ole symboleja, koska ne aina edustavat ainoastaan numeerista arvoaan Symboleilla T ja NIL erikoismerkitys: T on totuusarvo tosi ja NIL epätosi Loogisissa lausekkeissa NIL on epätosi ja mikä tahansa siitä poikkeava arvo katsotaan todeksi Schemessä totuusarvot #t ja #f Symbolit ja luvut = atomit (atoms) Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 13 *x++=*y++ VI.2.1.2 LISPin perustietotyypit Atomit (atoms) ja listat (lists) Lista on järjestetty joukko, jonka alkiot ovat atomeja tai toisia listoja Listan rajoittimina toimivat kaarisulut ja alkioiden erottimina sanavälit Lista voi olla tyhjä, merkitään ( ) tai NIL Schemessä null Atomit ja listat = symboliset lausekkeet tai slausekkeet (s-expression) Listan ensimmäinen alkio on sen pää (head) ja kaikki loput sen häntä (tail) Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 14 *x++=*y++ VI.2.1.3. LISPin funktiot Kirjoitetaan listamuodossa (funktio parametri1 parametri2 ...) Noudattaa tiukkaa semantiikkaa Funktion nimi kirjoitetaan aina ensin Esimerkki. Operaatio 2+3 kirjoitetaan (+ 2 3) ja 3*4+5 (+ (* 3 4) 5) Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 15 *x++=*y++ VI.2.1.3. LISPin funktiot (2) QUOTE (‘) Lauseke LISP –tulkille -> määrää lausekkeen arvon laskemalla uloimman funktion kutsun argumenttien arvot vasemmalta oikealle Jos halutaan lauseke sellaisenaan, merkitään lainaukseksi kirjoittamalla ‘ tai QUOTE lausekkeen eteen, esimerkiksi ‘(+ 3 4) ei laske arvoa Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 16 *x++=*y++ VI.2.2 Scheme 1970-luvun puolivälissä syntynyt LISPin murre Pieni ja kompakti Syntaksi ja semantiikka yksinkertaisia Suunnittelussa minimalistinen idea Käytetty ohjelmoinnin opettamisessa Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 17 *x++=*y++ VI.2.2.1 Funktioiden määrittely Schemessä Funktionaalisessa kielessä oltava mahdollisuus määritellä omia funktioita Lambda-lausekkeet Käytetään Schemessä funktioiden määrittelyyn (LAMBDA (x) (* x x)) Parametrien lista = lambda-lista Yleinen laskenta lambda-lauseen rungossa (yllä (* x x)) Abstrakti mekanismi funktion määrittelyä ja laskentaa varten; nimetön funktio, häviää kun muoto on laskettu -> tarvitaan mekanismi, jolla funktioon voidaan sitoa tunniste Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 18 *x++=*y++ VI.2.2.1 Funktioiden määrittely Schemessä (2) Uusien funktioiden määrittely tapahtuu funktiolla define Esimerkki. Edellinen funktio voidaan määritellä (define nelio (x) (* x x) ) -> voidaan ohjelmassa kutsua nimellä: (nelio 5) -> 25 Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 19 *x++=*y++ VI.2.2.2 Schemen kontrollirakenteet Muistuttavat ulkoisesti funktiokutsuja Esitetään sulkulausekkeina, joissa ensimmäinen termi on ohjausrakenteen nimi ja seuraavat termit ikään kuin funktion argumentteja, joihin rakennetta sovelletaan Rakenteen laskennan tuloksena on jokin arvo kuten funktioilla Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 20 *x++=*y++ VI.2.2.2 Schemen kontrollirakenteet (2) if-lause Kahden vaihtoehdon ehtolause, muoto: (if ehto tosi-muoto epätosi-muoto) Esimerkki. Kertoma-funktio (define (kertoma n) (if (<= n 1) 1 (* n (kertoma (- n 1))))) Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 21 *x++=*y++ VI.2.2.2 Schemen kontrollirakenteet (3) cond-lause: monivalintarakenne Haarauttaa laskentaa predikaattien määrittelemien ehtojen nojalla, lauseen muoto: (cond (p1 a1) (p2 a2) … (pN aN) (else a)) Predikaatit pi ja arvolausekkeet ai ja a mielivaltaisia muotoja Arvoksi ensimmäistä tosi-arvoista predikaattia vastaava arvo tai elseä vastaava arvo. Else ei pakollinen -> lauseen arvo voi olla epämääräinen Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 22 *x++=*y++ VI.2.2.2 Schemen kontrollirakenteet (4) Esimerkki cond-lauseesta: Fibonaccin lukuja palauttava funktio (define (fibo n) (cond ((= n 0) 0) ((= n 1) 1) (else (+ (fibo (- n 1)) (fibo (- n 2)))) )) Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 23 *x++=*y++ VI.2.2.3 Schemen listankäsittelyfunktioita Listojen käsittelyn neljä alkeisfunktiota car, cdr, cons, ja list car ja cdr listan purkufunktioita car palauttaa argumenttina saadun listan pään ja cdr listan hännän -> Funktion car paluuarvo on slauseke ja funktion CDR paluuarvo lista Esimerkki (car ‘(a b c d) ) -> s-lauseke a ja (cdr ‘(a b c d) ) -> lista (b c d) Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 24 *x++=*y++ VI.2.2.3 Schemen listankäsittelyfunktioita (2) cons ja list listan muodostajia cons lisää ensimmäisen argumentin toisen listaargumentin alkuun. Esimerkiksi (cons 'C '(A B)) -> lista (C A B) list muodostaa listan parametreistansa. Esimerkiksi (list 'C '(A B) 'D) -> lista (C (A B) D) Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 25 *x++=*y++ VI.2.2.3 Schemen listankäsittelypredikaatteja eq?, null? ja list? Schemen listojen käsittelyn alkeispredikaatit list? : Onko parametri lista vai ei null? : Onko parametrilista tyhjä vai ei eq? : Vertailee ovatko parametrisymbolit samat. Ei toimi järkevästi listoille Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 26 *x++=*y++ VI.2.2.4 Scheme-esimerkkejä Tehtävä: Kirjoita funktio onko_jasen, joka päättelee, onko parametrina saatu alkio toisena parametrina saadun listan alkio. Paluuarvona #t tai #f. Ratkaisun idea: Jos lista on tyhjä palautetaan #f Jos alkio löytyy listan päästä #t Muuten kutsutaan samaa funktiota listan häntä parametrina -> Lista lyhenee -> Rekursio päättyy Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 27 *x++=*y++ VI.2.2.4 Scheme-esimerkkejä (2) Ratkaisufunktio: (define (onko_jasen x lista) (cond ((null? lista) #f) ((eq? (car lista) x) #t) (else (onko_jasen x (cdr lista))) )) Esimerkkejä toiminnasta: (onko_jasen 'a '(b a c)) -> #t (onko_jasen 'a '(b (a c) d)) -> #f Ei tutki sisältyykö alilistoihin Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 28 *x++=*y++ VI.2.2.4 Scheme-esimerkkejä (3) Tehtävä: Kirjoita funktio litista, joka litistää parametrina saadun listan, ts. poistaa kaikki muut paitsi uloimmat sulut. Apuna voi käyttää Schemen varusfunktiota append, joka yhdistää parametreinaan saadut kaksi listaa Ratkaisuidea: Jos lista on tyhjä, palautetaan tyhjä lista Jos parametri on atomi, siitä muodostetaan yksialkioinen lista Muuten litistetään listan ensimmäinen alkio ja listan häntä sekä yhdistetään saadut listat Sovelletaan lyheneviin listoihin -> rekursio päättyy Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 29 *x++=*y++ VI.2.2.4 Scheme-esimerkkejä (4) Ratkaisufunktio: (define (litista lista) (cond ((null? lista) '() ) ((not (list? lista)) (cons lista '())) (else (append (litista (car lista)) (litista (cdr lista)))))) Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 30 *x++=*y++ VI.3. Haskell Julkaistu vuonna 1987 Nimetty matemaatikko Haskell Brooks Curryn mukaan Puhtaasti funktionaalinen kieli Ehkä yleisin käytössä Vahva tyypitys Laiska evaluointi Syntaksi muistuttaa ML-kieltä Yhteisiä piirteitä ML:n kanssa vahva tyypitys ja moduulirakenne Toteutuksia vapaasti saatavilla https://www.haskell.org/ Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 31 *x++=*y++ VI.3.1 Haskellin funktiot Voidaan määritellä hahmontunnistuksella Esimerkki. Kertoma-funktio kertoma 0 = 1 kertoma n = n * kertoma(n-1) Ehtolauseen käyttäminen määrittelyssä kertoma(n) = if n == 0 then 1 else n*kertoma(n-1) Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 32 *x++=*y++ VI.3.1 Haskellin funktiot (2) Esimerkki. Vaihtoehtorakenteen käyttö Fibonacci-lukuja laskevan funktion määrittelyssä fibo n | n == 0 = 0 | n == 1 = 1 | n > 1 = fibo(n-1)+fibo(n-2) Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 33 *x++=*y++ VI.3.1 Haskellin listat Esitetään hakasulkeiden sisällä, alkiot pilkulla erotettuna suunnat = [”N”, ”S”, ”E”, ”W”] Listojen yhdistäminen: operaattori ++ [1,4,5] ++ [2,6,8] -> [1,4,5,2,6,8] Kaksoispisteellä merkitään osa listasta -> Funktio joka palauttaa listan pituuden pituus [] = 0 pituus(x:xs) = 1 + pituus(xs) Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 34 *x++=*y++ VI.3.1 Haskellin listat (2) Listakehitelmillä (list comprehensions) voidaan määritellä listoja. Muoto [runko | määreet] Esimerkki. Lista [1,4,9,16,…,400] [n*n | n <- [1..20]] Laiskan evaluoinnin ansiosta voi olla potentiaalisesti ääretön: parilliset = [2, 4..] neliot = [n*n | n <- parilliset] Listassa periaatteessa kaikkien parillisten lukujen neliöt. Listaa muodostetaan käytettäessä niin pitkälle kuin tarvitaan Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 35 *x++=*y++ VI.4. Muita funktionaalisia kieliä COMMON LISP (1984) Yhdistelmä LISPin murteista -> varsin laaja Sekä dynaaminen että staattinen näkyvyysalueen määräytyminen ML (MetaLanguage, 1973) Syntaksi muistuttaa enemmän Pascalia kuin LISPiä Sisältää imperatiivisia piirteitä Tyypit voidaan esitellä tai määräytyvät implisiittisesti Vahvasti tyypitetty – staattinen tyypintarkistus -> luotettavuus ja tehokkuus lisääntyvät Moduuliominaisuus -> abstraktit tietotyypit Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 36 *x++=*y++ VI.4. Muita funktionaalisia kieliä (2) F# (2005) Kuuluu MS:n .NET-perheeseen Sisältää imperatiivisia piirteitä Tukee olio-ohjelmointia Funktiot muistuttavat Haskellin funktioita Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 37 *x++=*y++ VI.5 Funktionaalisten ja imperatiivisten kielten vertailua Kielen syntaksi ja semantiikka funktionaalisissa kielissä yksinkertaisempi Kiistanalaista kumman paradigman ohjelmointi tuottavampaa Todennäköisesti riippuu sovelluskohteesta Imperatiiviset ohjelmat tehokkaampia Ero ei kaikissa sovelluksissa merkittävä Luettavuus: Funktionaalinen koodi yleensä helpommin tukittavissa Suuri suosioero imperatiivisten kielten hyväksi ehkä tottumuskysymys? Ari Vesanen, Tietojenkäsitttelytieteiden laitos 815338A Ohjelmointikielten periaatteet, Funktionaalinen ohjelmointi 38