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