Luku 1 Johdanto Edward Sapir ja Benjamin Whorf esittivät viime vuosisadan alkupuolella kielitieteellisen hypoteesin, joka tunnetaan nykyisin nimellä Sapirin Whorfin hypoteesi. Sen heikompi muoto, johon nykyisetkin kielitieteilijät enemmän tai vähemmän uskovat, kuuluu: Kieli vaikuttaa ajatteluun. Myös ohjelmoinnin yhteydessä tämä heikompi muoto on totta: se, mitä ohjelmointikieltä osaa, vaikuttaa siihen, miten ohjelmointiongelmia ryhtyy ratkaisemaan. Kaikki kielet eivät ole tässä suhteessa samanarvoisia: esimerkiksi Pascalin ja C:n tukema ajattelutapa on niin samanlainen, että kummastakin kielestä voi varsin vähällä vaivalla siirtyä toiseen. Vastaavanlainen samankaltaisuus pätee, tosin vähemmässä määrin, myös C++:aan ja Javaan. Jotkin kielet puolestaan suosivat niin erilaisia ajattelutapoja, että ne tuntuvat aluksi aivan eri maailmoilta, eikä toisen osaamisesta ole kovin suurta apua toisen osaamisessa. Ajatustavoiltaan läheisten kielten katsotaan yleensä kuuluvan samaan kieliparadigmaan, mutta niiden väliset rajapyykit eivät ole useinkaan kovin selvät. Kieliparadigmoille sukua ovat ohjelmointiparadigmat, tosin aika usein näiden välistä eroa ei nähdä (myös tämän kirjoittaja on ne monesti sekoittanut!). Kukin ohjelmointiparadigma on oikeastaan idealisoitu versio niistä ajattelutavoista, joita vastaava kieliparadigma suosii. Alan Perlis kirjoitti kaksi vuosikymmentä sitten: A language that doesn t affect the way you think about programming, is not worth knowing. 1 Minä kääntäisin tämän väitteen toisin päin: A language that affects the way you think about programming is worth knowing. Itse asiassa väittäisin, että jokaisen ohjelmointiin vakavissaan suhtautuvan tulisi tuntea ainakin pari-kolme eri kieliparadigmoihin kuuluvaa kieltä eli oikeastaan pari-kolme eli ohjelmointiparadigmaa. 1. Alan J. Perlis, Epigrams in Programming, ACM SIGPLAN Notices, vol 17 no 9 (September 1982). 1
2 LUKU 1. JOHDANTO Jyväskylän yliopiston informaatioteknologian tiedekunnassa pääasiassa opetetaan olioparadigman mukaista ajattelua. Tässä tässä monisteessa tutustutaan funktioparadigmaan. Muita suhteellisen tunnettuja ovat 1970-luvulla suosittu toimintoparadigma (procedural paradigm) sekä erityisesti tekoälyn yhteydessä tavattava logiikkaparadigma. Funktio-ohjelmointi tunnetaan maailmalla nimellä functional programming, ja meilläkin on käytössä tuosta suoraan väännetty suomennos funktionaalinen ohjelmointi. Ongelmana tuossa termissä on se, että functional on helppo käsittää tarkoittamaan toimivaa eikä funktioihin liittyvää. Termi funktioohjelmointi kertoo paremmin, mistä on kyse, on hyvä vastine tutulle käsitteelle olio-ohjelmointi ja lisäksi se on samaa sukua kuin Tietotekniikan liiton ATK-sanakirjan ehdotus funktiokieli functional language. Funktio-ohjelmoinnissa on monta koulukuntaa, joilla kullakin on oma näkemyksensä siitä, mitä funktio-ohjelmointi on. Tässä on joitakin (osin keskenään ristiriitaisia) luonnehdintoja: Funktio-ohjelmat ovat (matemaattisia) funktioita syötteeltä tulokselle. (formalistinen näkemys) Funktio-ohjelmointi on ohjelmointityyli, jossa funktioita (aliohjelmia) käsitellään rutiininomaisesti datana. (pragmaattinen näkemys) Funktio-ohjelmassa ei sovi käyttää sijoituslausetta eikä muuttujien arvoja sovi muuttaa sen jälkeen, kun ne on alustettu. Funktio-ohjelmilla ei ole tilaa. (puristinen näkemys, bondage & discipline) Funktio-ohjelma on ohjelma, joka on kirjoitettu funktiokielellä. (väistöliike) Yhteistä kaikille on funktioiden korostaminen ohjelmoinnissa. 1.1 Miksi opiskella? Yksi syy opiskella funktio-ohjelmointia tuli esille jo yllä: ohjelmoijan on hyvä tuntea mahdollisimman monta ohjelmointiparadigmaa, ja funktio-ohjelmointi on yksi niistä. Toinen syy seuraa siitä havainnosta, että funktio-ohjelmoinnissa kehitetyt tekniikat ovat hiljalleen soljuneet osaksi ohjelmoinnin valtavirtaa tosin osa niistä on toki valtavirtaohjelmoinnissa itsenäisesti uudelleen keksitty. Esimerkiksi GoF-suunnittelumalli 2 COMMAND on puhtaimmillaan oleellisesti täysi- 2. Erich Gamma, Richard Helm, Ralph Johnson ja John Vlissides: Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, 1995.
1.2. MUUTA MATERIAALIA 3 valtaisen funktion simulointia. Javan tuleva geneerisyyslaajennus on tiettävästi perua Pizza-kielestä, jonka kehittäjien joukossa on tunnettuja funktioohjelmoinnin harjoittajia ja tutkijoita. Näin ollen funktio-ohjelmoinnin tuntemus näyttäisi antavan ohjelmoijalle etukäteisvilkaisun siitä, minkälaista tulevaisuuden valtavirtaohjelmointi saattaisi olla. Kolmas syy johtuu funktio-ohjelmoinnin pohjalla olevan ohjelmointikäsityksen selkeydestä ja yksinkertaisuudesta. Funktio-ohjelmointi tarjoaa selkeän näkymän modernin ohjelmoinnin tärkeisiin piirteisiin kuten abstraktioon, geneerisyyteen, polymorfismiin ja ylikuormitukseen. 1.2 Muuta materiaalia 1.2.1 Kirjallisuus Funktio-ohjelmointi on ensisijaisesti taitolaji, ja siten sen voi oppia monien lähteiden kautta, kunhan muistaa harjoitella sitä myös käytännössä. Kuten ohjelmointikirjat yleensäkin, funktio-ohjelmoinninkin oppikirjat lähestyvät aihettaan yhden, tietyn kielen näkökulmasta unohtaen muut (ja epäilemättä tämä moniste on yhtä syyllinen kuin muutkin). Ainakin seuraavat ovat varteenotettavia oppikirjoja: Simon Thompsonin mainio Haskell: The Craft of Functional Programming (toinen laitos) opettaa funktio-ohjelmoinnin alkeet Haskellin näkökulmasta. Harold Abelsonin, Gerald Jay Sussmanin ja Julie Sussmanin Structure and Interpretation of Computer Programs (toinen laitos) on ohjelmoinnin alkeisoppikirja, joka lähestyy aihettaan Schemen kautta ja päätyy pidemmälle kuin useimmat muut saman lähtötason kirjat ja on hyvää luettavaa myös kokeneemmillekin ohjelmoijille. SICP on saavuttanut jo eräänlaisen legendan aseman alallaan. Paul Hudakin The Haskell School of Expression: Learning Functional Programming through Multimedia ottaa aiheeseensa erilaisen lähestymistavan kuin useimmat muut. Hudakin kirja painottaa siirräntää ja löytää esimerkkinsä grafiikkaohjelmoinnin piiristä. Kielenä sekin käyttää Haskellia. Richard Birdin Introduction to Functional Programming using Haskell (toinen laitos) on (tämän monisteen tapaan) matemaattisuutta korostava Haskell-koulukuntaan kuuluva esitys funktio-ohjelmoinnista. Chris Okasakin Purely Functional Data Structures esittää funktio-ohjelmointiin sopivia tietorakenneratkaisuja. Okasaki on tällä osa-alalla edelläkävijä. Esimerkit Okasaki kirjoittaa ML:llä ja Haskellilla.
4 LUKU 1. JOHDANTO Feth Rabhin ja Guy Lapalmen Algorithms: A Functional Programming Approach on funktio-ohjelmoinnin näkökulmasta kirjoitettu aineopintotasoisen tietorakenteet ja algoritmit -kurssin oppikirja. Lisäksi mainio kirja on Jeremy Gibbonsin ja Oege de Moorin toimittama The Fun of Programming, joka käsittelee funktio-ohjelmoinnin sovelluksia ja tekniikoita. Se kuitenkin olettaa lukijaltaan jo funktio-ohjelmoinnin perustaidot, joten tämän kurssin oppikirjaksi siitä ei ole. 1.2.2 Merkittäviä artikkeleita Funktio-ohjelmointi on aina ollut enemmän käytännöllinen kuin teoreettinen aihe, joten merkittävät uudistukset tapahtuvat usein akateemisten ympyröiden ulkopuolella. Nykyisin tosin myös akateeminen julkaisuperinne on saanut jalansijaa funktio-ohjelmoinnin alalla. Muutama akateeminen artikkeli on kuitenkin ansainnut merkittävän aseman: John Backus: Can programming be liberated from the von Neumann style? A functional style and its algebra of programs. Communications of the ACM, Volume 21, Issue 8 (August 1978). John Hughes: Why functional programming matters. http://www.md. chalmers.se/ rjmh/papers/whyfp.html, 1984/2002. Philip Wadler: How to declare an imperative. ACM Computing Surveys, Volume 29, Issue 3 (September 1997). Funktio-ohjelmointia käsittelevät ainakin seuraavat tieteelliset aikakauslehdet Journal of Functional Programming Higher-Order and Symbolic Computation 3 Journal of Functional and Logic Programming 4 -lehdet sekä International Conference on Functional Programming (ICFP) 5 -konferenssi. 1.2.3 Netti Internetissä on runsaasti funktio-ohjelmointiin liittyviä resursseja. Tämän kurssin kannalta hyödyllisiä ovat ainakin seuraavat: Nyysiryhmä comp.lang.functional Haskell-kielen sivusto, http://www.haskell.org/ IRC-kanava #haskell Freenode-ircverkossa (lähin palvelin on orwell.freenode.net) 3. http://www.kluweronline.com/issn/1388-3690 4. http://danae.uni-muenster.de/lehre/kuchen/jflp/ 5. http://www.math.luc.edu/icfp/
1.3. ESITIEDOT 5 1.3 Esitiedot Tämä moniste on kirjoitettu Jyväskylän yliopiston tietotekniikan laitoksen kurssin TIE 328 Funktio-ohjelmointi käyttöön. Koska kyseessä on syventävä opintojakso (lue: laudatur-kurssi), oletan monistetta käyttävältä opiskelijalta jo kaikenlaista: Ensinnäkin oletan, että hän on opiskellut alaa jo useamman vuoden. Hänellä on syytä olla suuri osa tietotekniikan aineopinnoista (lue: cumusta) suoritettuna tai, totta kai, vastaavat tiedot. Oletan, että hän osaa ohjelmoida ja on ohjelmoinut mielellään muutakin kuin pakollisten kurssien harjoitustyöt. Toisekseen oletan, että hän on sinut matemaattisen ajattelutavan ja formaalin kaavanpyörittelyn kanssa. En vaadi tiettyjä matemaattisia tietoja tosin logiikan alkeet ja yliopistomatematiikassa käytetty funktiokäsite (joka muuten on erilainen kuin lukiosta tuttu!) on hyvä olla hallussa. Kolmanneksi oletan, että hän tietää, mikä on kontekstiton kielioppi ja osaa sitä soveltaa käytännössä. Jos hän ei osaa kirjoittaa kontekstitonta kielioppia, joka kuvaa yksinkertaisten laskentalausekkeiden kuten 4 (5+6) 9 3 rakenteen, on hänen syytä kerrata tämä esimerkiksi kurssin TIE 264 Automaatit ja kieliopit materiaaleista. Neljänneksi oletan, että hän tietää, mikä on Turingin kone (tai mahdollisesti RAM-kone) ja mitä tekemistä sillä on tietojenkäsittelyn kanssa. Mitenkään kovin formaalisti Turingin konetta (tai RAM-konetta) ei tarvitse hallita. Tarvittaessa tämänkin voi kerrata kurssin TIE 264 Automaatit ja kieliopit materiaaleista. Mitään näistä ei välttämättä tarvita funktio-ohjelmoinnin oppimiseen, mutta tällaiset lähtötasovaatimukset toivottavasti mahdollistavat hieman edistyneempienkin asioiden käsittelyn kurssilla. 1.4 Kielikysymys Ohjelmointikursseista puhuttaessa nousee aina esiin kysymys opetuskielestä. Vaikka ohjelmointikurssien varsinainen opetettava sisältö onkin kielestä riippumattomissa ohjelmointitekniikassa ja -taidossa, on jokin kieli kuitenkin valittava, jotta opetus olisi konkreettista. Ohjelmoinnin oppimisessa tärkeää on tekeminen, ja se ei onnistu ilman kieltä. Funktiokielet voidaan karkeasti jaotella kahdella kriteerillä: ovatko ne puhtaita funktiokieliä ja ovatko niillä kirjoitetut aliohjelmat oletusarvoisesti tiukkoja
6 LUKU 1. JOHDANTO (strict) vai väljiä (non-strict) näihin käsitteisiin palataan vielä, nyt niitä ei tarvitse ymmärtää. Joitakin tunnettuja funktiokieliä on kuvailtu tuolla jaottelulla ja muutenkin seuraavassa: Standard ML (SML) on 1970-luvulla kehitetyn ML:n (metalanguage) jälkeläinen. Standard ML on varsin suosittu epäpuhdas, tiukka funktiokieli. O Caml kuuluu myös ML-perheeseen. Kuten SML, myös O Caml on epäpuhdas ja tiukka, mutta se myös tukee olio-ohjelmointia. Scheme on Lisp-murre, joka aikoinaan toi Lisp-maailmaan (ja myös yleisemminkin) uusia, moderneja piirteitä ja on edelleenkin ohjelmoinninopetuksessa suosittu. Schemen erityispiirre on minimaalisuuden tavoittelu. Funktiokielenä Scheme on epäpuhdas ja tiukka. Erlang on Ericssonin ensisijaisesti omaan käyttöönsä kehittämä tiukka, epäpuhdas funktiokieli. Pizza on Javan laajennos, joka tukee funktio-ohjelmoinnista tuttuja ominaisuuksia. Funktiokielenä se on tiukka ja epäpuhdas. Haskell on yksi harvoista onnistuneista komiteatyönä suunnittelluista kielistä. Haskell suunniteltiin 1980-luvun loppupuolella yhdistämään väljien, puhtaiden funktiokielten käyttäjät ja tutkijat saman kielen taakse silloin sellaisia kieliä oli useita kymmeniä ilman, että millään niistä yksinään oli kovin vahvaa asemaa. Haskell standardoitiin 1990-luvun loppupuolella stabiiliksi Haskell 98 -kieleksi, mutta siihen kehitetään jatkuvasti uusia laajennoksia. Clean on Haskellin kaltainen puhdas ja väljä funktiokieli. Kielten huomattavin ero on tavassa, jolla ne käsittelevät siirräntää. Tällä kurssilla käytettäväksi olen valinnut Haskellin useasta syystä: Se on puhdas funktiokieli Siitä on olemassa työkaluntekijöiden tukema standardi Sille on olemassa useita laadukkaita kääntäjiä Se on löyhä funktiokieli (viimeisenä mutta ei vähäisimpänä:) Minä tunnen sen kohtuullisen hyvin.