Haskell 98. Puhdasta funktionalismia nonstriktissä paketissa. Antti-Juhani Kaijanaho

Koko: px
Aloita esitys sivulta:

Download "Haskell 98. Puhdasta funktionalismia nonstriktissä paketissa. Antti-Juhani Kaijanaho"

Transkriptio

1 Haskell 98 Puhdasta funktionalismia nonstriktissä paketissa Antti-Juhani Kaijanaho

2 Haskell 98: Puhdasta funktionalismia nonstriktissä paketissa Antti-Juhani Kaijanaho Copyright 1999 Antti-Juhani Kaijanaho Tätä esitystä saadaan levittää ja kopioida vapaasti. Muutettuja versioita saadaan myös levittää ja kopioida vapaasti, kunhan sekä alkuperäisen että muutetun tekstin tekijät mainitaan asianmukaisesti, ja muutettuja versioita ei voida erehdyksessä luulla alkuperäiseksi esitykseksi. Esitys on julkaistu Internetissä. (http://www.iki.fi/gaia/tekstit/ohjsem99/)

3 Luku 1 Johdanto Haskell on nonstrikti, puhtaasti funktionaalinen ohjelmointikieli (non-strict purely functional programming language). Tunnetuista ohjelmointikielistä sitä lähimpänä lienevät Lisp-sukuiset kielet, vaikka eroavaisuuksia onkin paljon. Haskell on hyvin erilainen kuin C, Pascal, C++ tai Java. Haskellissa voidaan esimerkiksi manipuloida funktioita ja aktioita (esimerkiksi merkin lukeminen tiedostosta, ikkunan avaaminen ja kahvin keittäminen) täysivaltaisina arvoina. Haskellissa on mahdollista periä rajapintoja vaan ei tyyppejä. Tyypit voivat olla rekursiivisia ja tietorakenteet äärettömiä; nonstriktiyden ansiosta vain tarpeellinen (useimmiten äärellinen) osa tietorakenteesta joudutaan todella konstruoimaan muistiin. Muuttujia ei ole; sen sijaan on olemassa funktiot (myös nollan argumentin funktiot eli vakiot) ja niiden parametrit. Silmukointirakenteita ei ole, vaan käytetään rekursiota, joka ei aina edes tarvitse päättymisehtoa! Onko Haskell sitten toivottoman hidas ja muistisyöppö? Nykyiset kääntäjät kykenevät tuottamaan koodia, joka on riittävän nopeaa melkein kaikkiin tarkoituksiin. Vain kovat reaaliaikasovellukset vaativat liikaa Haskellilta. Muistia Haskell-ohjelma vie enemmän kuin vastaava tyypillinen käsin koodattu C-ohjelma, mutta useimmissa tapauksissa sillä ei ole käytännön merkitystä. Joskus jopa nonstriksti laskenta voi vähentää muistin kulutusta, kun koko välitulosta ei tarvitse pitää muistissa. Haskell luotiin vonna 1987 yhtenäistämään nonstriktien puhtaiden funktionaalisten kielten joukot. Tuolloin nimittäin joka tutkijalla oli oma kielensä ja yhteisen sävelen löytäminen oli hankalaa. Nimi valittiin loogikko Haskell B. Curryn kunniaksi. Tavoite onnistui, ja kieli kehittyi huimaa vauhtia ottaen mukaan muutamia tutkimuksen viimeisimpiä tuloksia 1. Vuonna 1997 päätettiin luoda vakaa versio kielestä, Haskell 98, joka säilyisi samana ja joka toteutettaisiin laajasti, samalla kun tutkimusja kehitystyö keskittyy uuteen Haskell 2:een. Tarkoituksena oli, että Haskell 98 olisi standardoitu kieli, jota käyttäjät uskaltaisivat käyttää ilman muuttuvan kielen aiheuttamia murheita. Haskell 98 valmistui lopulta keväällä 1999 ja kolme neljästä tärkeimmästä Haskell-toteutuksesta tukevat sitä olennaisin osin. Haskell ei ole oliokieli, joten alityyppien luominen perimällä ei ole mahdollista. Sen sijaan monet asiat, jotka voidaan toteuttaa olioilla, voidaan kirjoittaa suunnilleen yhtä helposti käyttäen hyväksi Haskellin parametrisoitua polymorfismia, tyyppiluokkien perintää ja Haskell 98 -standardiin kuulumatonta mutta yleisesti toteutettua toisen kertaluvun polymorfismia ja sen tuomia eksistentialistisesti parametrisoituja tyyppejä. Toisaalta on olemassa kieli nimeltä O Haskell (http://www.cs.chalmers.se/~nordland/ohaskell/) sekä sen toteutus O Hugs, jotka laajentavat Haskellia niin, että olio-ohjelmointikin on mahdollista. Haskellista on olemassa neljä tärkeää toteutusta: Glasgow Haskell Compiler (GHC, saatavissa verkosta (http://www.haskell.org/ghc/)), Hugs (alunperin lyhenne sanoista Haskell Users Gofer System, myös saatavissa verkosta (http://www.haskell.org/hugs/)), Nearly a Haskell Compiler (NHC, saatavissa verkosta (http://www.cs.york.ac.uk/fp/nhc98/)) ja Haskell-B Compiler (HBC, saatavissa 1 Esimerkiksi monadinen I/O on alle kymmenen vuotta vanha tekniikka, ja sen ottivat ensimmäisten joukossa käyttöön Haskell-kielen kehittäjät. 3

4 Luku 1 Johdanto verkosta (http://www.cs.chalmers.se/~augustss/hbc/hbc.html)). Näistä kolme ensimmäistä tukevat Haskell 98:aa. Viimeksi mainittu on vielä vanhemman Haskell 1.4:n toteutus. Toteutuksista Hugs on kielen opiskeluun sekä nopeaan kehitystyöhön tarkoitettu tulkki, muut ovat optimoivia kääntäjiä: NHC on optimoitu minimoimaan tilavaatimukset (sekä ohjelmatiedoston koon että työmuistin osalta), GHC puolestaan optimoi lähinnä nopeutta. HBC on ainoa toteutus, joka tukee Unicode-merkistöä, kuten kielen määrityksen mukaan kuuluisi (muut käyttävät edelleen Latin 1 -merkistöä). Kaikki neljä toteutusta ovat vapaita ohjelmia. Tämä esitys perustuu määrityksen (http://www.haskell.org/definition) mukaiseen Haskell 98:een. Kaikkien täydellisten esimerkkiohjelmien on tarkoitus toimia kaikissa Haskell 98 -toteutuksissa. Osittaiset esimerkkiohjelmat toimivat sellaisenaan Hugs-tulkissa, jossa pääohjelma ei ole koskaan pakollinen. Ohjelmat on testattu vain Hugsissa, ja kun ohjelmointiympäristöä käsitellään, puhutaan vain Hugsista. Haskell-aiheista lukemista löytyy ihan kohtuudella. Kielen määrittelevät raportit Haskell 98: A Non-strict, Purely Functional Language ja Standard Libraries for Haskell 98 (toimittaneet Simon Peyton Jones ja John Hughes) ovat saatavilla verkosta (http://www.haskell.org/definition). Ne eivät kuitenkaan sovellu kielen opetteluun. Kohtuullinen opus opettelemista ajatellen on A Gentle Introduction to Haskell (http://www.haskell.org/tutorial/) (Paul Hudak, John Peterson ja Joseph H. Fasel). Erittäin hyvä johdatus funktionaaliseen ohjelmointiin on Richard Birdin ja Philip Wadlerin kirja Introduction to Functional Programming using Haskell, joka on uudistettu laitos myös erinomaisesta mutta jo hieman vanhasta samojen tekijöiden kirjasta Introduction to Functional Programming. Viimeksi mainittu teos löytyy Mattilanniemen kirjastosta. Kattava kirjallisuusluettelo (http://www.haskell.org/bookshelf/) löytyy Haskell-sivuston kautta. 4

5 Luku 2 Hello World Tässä on Haskell-kielellä kirjoitettu Hello World: {- hello.hs -} main :: IO () main = putstrln "Hello World!" Ohjelman voi ajaa kirjoittamalla komentoriville runhugs hello.hs (runhugs on Hugsin sellainen versio, joka lukee ohjelman sisäänsä ja ajaa sen suoraan; tällöin ei päädytä Hugsin normaaiin interaktiiviseen tilaan). Nyt siis pitäisi ruudulla näyttää jotakuinkin tältä: % runhugs hello.hs Hello World! % Vaihtoehtoisesti tämän ohjelman voi ladata interaktiiviseen Hugs-tulkkiin sanomalla hugs hello.hs Esiin tulee paljon tekstiä ja lopulta kehoite, johon pitää kirjoittaa main. Siihen voisi kirjoittaa minkä tahansa funktionnimen (tai itse asiassa minkä tahansa lausekkeen), mutta tiedostomme hello.hs määrittelee vain yhden: main. Sanomme siis main. Lopulta voi kirjoittaa :q, jolloin pääsee pois tulkista. Tämän kaiken pitäisi näyttää suurin piirtein tältä: % hugs hello.hs Hugs 98: Based on the Haskell 98 standard Copyright (c) World Wide Web: Report bugs to: Version: May 1999 Haskell 98 mode: Restart with command line option -98 to enable extensions Reading file "/usr/share/hugs98/lib/prelude.hs": Reading file "hello.hs": Hugs session for: /usr/share/hugs98/lib/prelude.hs hello.hs Type :? for help Main> main Hello World! Main> :q [Leaving Hugs] % 5

6 Luku 3 Funktionaalisesta ohjelmoinnista Funktionaalisessa ohjelmointityylissä tärkeä abstraktiokeino on sellaisten funktioiden rakentaminen ja käyttö, jotka operoivat funktioilla. On myös olennaisen tärkeää osata käyttää hyväksi nonstriktiyttä, joka mahdollistaa aika yllättävienkin ongelmien jakamisen osiin. Tarkastelemme muutamaa esimerkkiongelmaa, jossa sekä Haskell-kielen että funktionaalisen tyylin perusteet tulevat hyvin esille. Summa, tulo ja foldr Aloitetaan yksinkertaisella ongelmalla: On annettu lista lukuja. Laske niiden summa. Imperatiivisesti ajatteleva ohjelmoija saattaisi ajatella for-silmukkaa. Matemaatikko puolestaan määrittelisi tämän Σ-funktion rekursiivisesti. Haskellissa ei for-silmukoita ole, joten ainoaksi vaihtoehdoksi jää matemaatikon rekursiivinen versio. Tämä ei ole niin paha asia kuin rekursion pahuuteen tottuneen imperaatikon korvin kuulostaa: nonstrikti laskenta ja häntärekursion poisto muuttavat tilannetta olennaisesti. Esimerkki 3-1 Summausfunktio {- sum.hs -} sum [] = 0 sum (x:xs) = x + sum xs Summafunktio vie vain kaksi riviä koodia (katso Esimerkki 3-1). Ensimmäisellä rivillä määritellään rekursion päättymisehto: tyhjän listan summa on nolla. Toinen rivi on funktion yleinen tapaus. Se sanoo, että laskeaksesi epätyhjän listan summan laske yhteen listan ensimmäinen alkio ja lopun listan summa. Haskellissa funktio määritellään rajoitettujen yhtälöiden avulla. Yhtälön oikea puoli voi olla mikä tahansa lauseke, mutta vasemmalle puolelle on asetettu rajoituksia, jottei kääntäjän tarvitsisi toimia myös yleisten yhtälöiden ratkaisukoneena. Vasen puoli tulkitaan monimutkaisten pattern matching -sääntöjen avulla. Lyhyesti sanoen vasemman puolen tulee sisältää määriteltävän funktion nimi sekä sen parametrien kuvaukset. Yleensä funktion nimi on koko vasemman puolen ensimmäinen asia ja sen jälkeen tulevat parametrit, yksi kerrallaan. Parametrin paikalle voidaan laittaa joko muuttuja tai konstruktorilauseke. Edellä summausfunktion määritelmässä [] on tyhjää listaa esittävä listakonstruktori, ja x : xs on konstruktorilauseke, joka liittää muuttujan x arvoksi argumenttina annetun listan ensimmäisen alkion ja muuttujan xs arvoksi listan loppuosan. Varsinainen konstruktori tässä on lausekkeen keskellä oleva kaksoispiste (nimeltään cons), joka jäsennetään kuin se olisi infix-operaattori. Sen "parametrit"ovat tässä muuttujia, mutta ne voisivat ihan yhtä hyvin olla toisia konstruktorilausekkeita. Sulut ovat tarpeen, koska cons sitoo heikommin kuin funktion parametrien esittelyoperaattori (joka on pelkkää tyhjää tilaa). Kuten havaitaan, argumenttiarvot voidaan ikään kuin dekonstruoida jo parametrinvälityksessä: koko parametrille ei tarvitse antaa nimeä, jos tarvitaan vain sen osia. Jos argumentti ei täsmää 6

7 Luku 3 Funktionaalisesta ohjelmoinnista parametrilistan kanssa, yritetään seuraavaa saman funktion määrittävää yhtälöä: ensimmäinen, jola täsmää, on se, jota käytetään. Huomaa: Yhtälön oikealla puolella konstruktoreita voidaan käyttää luomaan uusia olioita. Siinä missä x : xs purkaa vasemmalla puolella listan palasiksi, kokoaa oikealla puolella 5 : [] uuden listan laittamalla tyhjän listan alkuun viitosen. 1 Periaatteessa siis viiden kokonaisluvun listan voisi kirjoittaa 5 : 4 : 3 : 2 : 1 : [], koska cons sitoo oikealta vasemmalle, mutta parempi lienee kuitenkin käyttää yksinkertaisempaa kielioppimakeista [5, 4, 3, 2, 1]. Seuraava ongelma on listan lukujen kertominen keskenään. Innokkaasti voisi joku kirjoittaa leikkaa-liimaa-korvaa-tekniikalla sum -funktiota muistuttavan toteutuksen (ks. Esimerkki 3-2). Esimerkki 3-2 Tulofunktio {- prod.hs -} prod [] = 1 prod (x:xs) = x * prod xs Tähän liittyy kuitenkin hyvin tunnettuja ylläpito-ongelmia. Niinpä olisikin parempi jollakin tavalla abstrahoida summa- ja tulofunktioille yhteinen rekursiokaava ja käyttää sitä näiden funktioiden kirjoittamiseen. Ratkaisu on kirjoittaa funktio, joka ottaa parametrinaan itse listan lisäksi tyhjän listan kuvan sekä rekursiotapauksessa käytettävän operaattorin. Esimerkki 3-3 määrittelee tällaisen funktion, jonka perinteinen nimi on foldr. Esimerkki 3-3 Funktio foldr {- foldr.hs -} foldr _ e [] = e foldr op e (x:xs) = x op foldr op e xs Funktion nimi tulee englannin kielen sanoista fold right. Tämä viittaa siihen, että funktio ikäänkuin laskostaa listan niin, että ennen niin pitkästä listasta tulee yksi naseva tulos, ja siihen, että jos rekursio kirjoitetaan auki, niin sulut kasautuvat lausekkeen oikeaan reunaan. On myös olemassa funktio foldl, joka toimii muuten samoin paitsi että se kasaa sulut vasempaan reunaan. Lisäksi foldl on häntärekursiivinen, mikä saattaa joissakin tilanteissa pienentää ohjelman tilavaatimusta. Huomaa: Funktioiden sum, prod ja foldr nimissä todella on heittomerkki. Se siis on osa näiden funktioiden nimeä. Näin siksi, että kielen standardikirjastoon kuuluu jo funktiot sum ja foldr, joiden nimet menisivät näin päällekäin itsestäänselvien nimiehdokkaiden kanssa. Siispä esimerkkifunktioille täytyy valita jokin toinen nimi, ja heittomerkin lisääminen funktion nimen perään on tällaisissa tapauksissa melko tavallinen ratkaisu. 1 Koska lista yleensä toteutetaan yhteen suuntaan linkittämällä, on cons nopea operaatio (O(1)). 7

8 Luku 3 Funktionaalisesta ohjelmoinnista Edellisessä esimerkissä näkyy eräs Haskellin mukava piirre: jokainen kahden muuttujan funktio voidaan muuttaa binääriseksi operaattoriksi laittamalla funktion nimi graaviaksenttien ("takahipsujen") sisään. Vastaavasti voidaan mikä tahansa binäärinen operaattori muuttaa kahden muuttujan funktioksi laittamalla se yksinään sulkeiden sisään (ks. Esimerkki 3-4). Tässä mielessä funktiot ja operaattorit ovat aivan sama asia. Vertaapa muuten mainitun esimerkin summa- ja tulofunktioiden määrittelyjä aiempiin: tässä esimerkissä ei ole yhtään ylimääräisyyksiä! Esimerkki 3-4 Funktiot sum ja prod toteutettuna foldr:lla {- sumprod.hs -} sum = foldr (+) 0 prod = foldr (*) 1 Funktiota foldr sanotaan korkean kertaluvun funktioksi, koska se operoi funktioilla (tässä tapauksessa yhteenlasku- tai kerto-opreraattorilla). korkean kertaluvun funktiot ovat funktionaalisen ohjelmoinnin kulmakivi, ja niitä kannattaa opetella käyttämään. Esimerkiksi Esimerkki 3-5 määrittelee erään toisen korkean kertaluvun funktion, ja Kuva 3-1 kokoaa muutamien standardikirjastoon kuuluvien funktioiden määrittelyjä. Määrittelyjen lukeminen ja niiden ymmärtäminen on hyvä harjoitustehtävä, erityisesti pisteoperaattori ja funktio map olisi hyvä ymmärtää kunnolla. Esimerkki 3-5 Funktio filter {- filter.hs -} filter _ [] = [] filter p (x:xs) p x = x : filter p xs otherwise = filter p xs Funktion filter määrittelyssä esiintyy eräs uusi kielirakenne. Määrittelevän yhtälön oikea puoli voidaan valita mielivaltaisten loogisten väittämien avulla. Väittämät käydään läpi järjestyksessä, ja ensimmäisen väitteen, jonka totuusarvo on tosi, mukainen oikea puoli valitaan. (Nollan muuttujan funktio otherwise palauttaa aina arvon tosi.) Jokaisen väitteen eteen laitetaan tässä rakenteessa pystyviiva. Tämä rakenne on olennaisesti jonkinlainen if-then-elseif-elseif-else, ja usein ohjelmat ovat helppolukuisempia, kun tätä rakennetta käytetään iffin (joka kielestä silti löytyy) sijasta. Funktio filter kuuluu standardikirjastoon. Haskellissa on voimassa ns. asemointisääntö (layout rule eli offside rule), jonka vuoksi täytyy ohjelmaa kirjoittaessa olla tarkkana siitä, mistä kohtaa riviä mikin ohjelmarivi alkaa. Nyrkkisäännöllä "enemmän oikealle jatkaa edellistä alikohtaa, sama kohta aloittaa uuden alikohdan, takaisin vasemmalle lopettaa"pärjää jonkin aikaa, mutta vakavasti Haskellista kiinnostuneen on parasta tutustua kielen määrittelyn luvun 2.7. antamaan tarkkaan kuvaukseen. Esimerkiksi funktion filter määrittelyssä alikohtia ovat väittämä oikea puoli -parit, joten ne kaikki sisennetään yhtä paljon oikealle funktion määrittelyn alusta alkaen. 8

9 Luku 3 Funktionaalisesta ohjelmoinnista Kuva 3-1 Standardikirjaston (prelude) korkean kertaluvun funktioita {- prelhofs.hs -} (.) f g x = f (g x) {- käytetään: (f. g) x -} flip f x y = f y x curry f x y = f (x,y) {- (, ) on parin konstruktori -} uncurry f (x,y) = f x y until p f x p x = x otherwise = until p f (f x) map _ [] = [] map f (x:xs) = f x : map f xs Huomaa: Funktion määrittelevän yhtälön vasemmalla puolella alaviiva täsmää mihinkä tahansa, mutta siihen ei voi viitata yhtälön oikealla puolella. Sitä on siis hyvä käyttää silloin, kun jonkin parametrin arvo on täysin yhdentekevä. Eratostheneen seula Seuraava ongelma liittyy alkulukuihin: Toteuta Eratostheneen seula, ja kirjoita funktio, joka palauttaa kaikki annettua lukua pienemmät alkuluvut, sekä funktio, joka palauttaa halutun monta ensimmäistä alkulukua. Olisi toivottavaa, että funktiot käyttävät yhteistä seulan toteutusta, jottei leikkaa-liimaa-syndrooma alkaisi vaivaamaan. Osoittautuu, että nonstriktiyden ansiosta tämä on helppoa. Haskell on nonstrikti kieli: se laskee vain sen, mitä se välttämättä tarvitsee. Esimerkiksi C lähtee laskemaan lausekkeen arvoa jäsennyspuun lehdistä käsin: vapaasti kerrottuna se laskee ensin sulkulausekkeet, sitten kertolaskut ja lopulta yhteenlaskut. Samoin C aina laskee funktion argumentit valmiiksi ennen kuin funktiota edes kutsutaan. Haskell sen sijaan lähtee jäsennyspuun juuresta. Se huomaa ensin yhteenlaskut ja toteaa tarvitseansa yhteenlaskun argumenttien arvoja; tällöin se rupeaa laskemaan niitä. Jos Haskell joskus huomaa, että se tietää jo tarpeeksi voidakseen laskea koko lausekkeen arvon, se jättää laskematta kaiken sen, mitä se ei ole siitä lausekkeesta vielä laskenut. C:ssä nonstriktiyttä tavataan kaiketi vain loogisten konnektiivien yhteydessä: jos ja-lausekkeen vasen puoli on epätosi, ei oikeaan puoleen edes katsota. Haskell toimii tällä lailla kaikkialla. Esimerkiksi, jos Haskellissa kutsutaan vakiofunktiota, ei funktion parametria koskaan lasketa. Tästä on paljon iloa, esimerkiksi äärettömät tietorakenteet käyvät mahdollisiksi. Triviaali esimerkki äärettömästä tietorakenteesta on loputon ykkösten jono ones: 9

10 Luku 3 Funktionaalisesta ohjelmoinnista {- ones.hs -} ones = 1 : ones Tätä lienee helpointa ajatella nollan funktion rekursiivisena funktiona, josta puuttuu päättymisehto. Se siis tuottaa, kuten sanottu, loputtoman ykkösten jonon. Huomattava on, että koska ones ei ota yhtään argumenttia ja koska Haskellissa funktioilla ei ole sivuvaikutuksia, voidaan koko sen tuottama lista esittää koneen sisällä äärellisenä, vakiokokoisena syklinä. Jos joku erehtyy pyytämään funktion ones arvoa, koko ohjelma ei välttämättä juutu umpiluuppiin. Nonstriktiys tarkoittaa, että vain välttämätön lasketaan (tai vaikka laskettaisiinkin enemmän, niin ylimääräisyyksiä ei huomioida). Jos siis joku pyytää tuon äärettömän listan viittä ensimmäistä alkiota, ei loppulistaa yritetä laskea. Näin ollen lauseke take 5 ones (funktion take toteuttaminen on harjoitustehtävä) palauttaa listan [1,1,1,1,1]. Sen sijaan listan viimeistä alkiota etsivä last jäisi tätä listaa käsitellessään etsimään omaa häntäänsä vaikka maailmanloppuun asti. Kokeile vaikka! Äärettömiä listoja konstruoi myös standardifunktio iterate, joka iteroi annettua funktiota annetulla alkuarvolla loputtomiin. Funktion määrittelee Esimerkki 3-6. Määritelmässä on huomattava uusi where-avainsana, jolla voidaan sitä edeltävään lausekkeeseen määritellä lokaaleja funktioita. Avainsanan jälkeen tulee yksi tai useampia funktiomäärittelyjä, jotka voivat olla keskenään rekursiivisia. Esimerkki 3-6 Funktio iterate {- iterate.hs -} iterate f x = xs where xs = x : map f xs Palataanpa alkulukuongelmaan. Nonstriktiä laskentaa ja äärettömiä listoja voi käyttää tässä aika jännällä tavalla hyväksi: konstruoidaan ensin lista kaikista alkuluvuista ja otetaan siitä vain se osa, mitä tarvitaan. Jos alkulukulistan konstruoi nollan muuttujan funktio alkuluvut, niin edellä esitettyihin kysymyksiin "mitkä ovat n ensimmäistä alkulukua"ja "mitkä ovat n:ää pienemmät alkuluvut"vastaavat lausekkeet take n alkuluvut ja takewhile (<n) alkuluvut. (Funktion takewhile määritteleminen on harjoitustehtävä.) Huomaa: Funktion viimeisen argumentin voi aina jättää pois (kunhan laittaa syntyneen lausekkeen sulkeiden sisään). Tällaisen lausekkeen arvo on yhden muuttujan funktio. Tämä uusi funktio palauttaa sen, minkä alkuperäinen funktio olisi palauttanut, jos argumentti laitettaisiin listan viimeiseksi. Toisin sanoen: (f a b c) d == f a b c d. Vastaavasti voidaan operaattoria leikata antamalla sille vain toinen operandi ja laittamalla tämä koko lause sulkeiden sisään. Tuloksena on jälleen yhden muuttujan funktio. Esimerkiksi (2*) on funktio, joka ottaa yhden parametrin ja joka palauttaa tämän parametrin kaksinkertaisena; siis (2*) 5 == 10. Jäljelle jää nyt vain itse alkulukujonon konstruointi, minkä tekee Esimerkki 3-7. Merkintä [2..] tarkoittaa ääretöntä listaa kaikista kokonaisluvuista kakkosesta ylöspäin. 10

11 Luku 3 Funktionaalisesta ohjelmoinnista Esimerkki 3-7 Alkulukujonon konstruointi {- primes.hs -} alkuluvut = map hd (iterate seula [2..]) where hd (x:_) = x seula (p:xs) = filter (not. (p jakaa )) xs p jakaa q = q mod p == 0 Esimerkin lukemista auttanee Eratostheneen seulan perusperiaatteen muistaminen: otetaan luettelo kaikista kokonaisluvuista kakkosesta ylöspäin, tiputetaan siitä ensin pois kakkosen monikerrat, sitten kolmosen monikerrat, ja niin edelleen tiputtamalla lopulta kaikki alkulukujen monikerrat pois. Lopputulos on alkulukujen luettelo. 11

12 Luku 4 Tyypeistä Haskellin tietotyyppijärjestelmä on rikas. Se on huomattavasti C:n tai Pascalin tyyppijärjestelmää ilmaisuvoimaisempi ja (yhdessä Haskellin tyyppiluokkien kanssa) pystyy ilmaisemaan monet olio-ohjelmoinnin tyyppikonstruktiot jopa ilman täydellistä oliotukea. Haskell on pääosin staattisesti tyypitetty kieli, joka hallitsee myös hallitun funktioiden kuormituksen. Tässä luvussa tarkastellaan esimerkein Haskellin tyyppijärjestelmän peruspiirteitä. Haskellissa kaikki valmiiksi määritellyt tyypit kokonaisluvut, merkit, listat, merkkijonot, totuusarvot, parit, änniköt, rationaaliluvut, liukuluvut, kompleksiluvut, mielivaltaisen suuret kokonaisluvut, taulukot, funktiot ja niin edelleen voidaan teoriassa konstruoida kielen keinoin, vaikka monet niistä varmasti toteutetaankin primitiivityyppeinä tehokkuuden vuoksi. Osalla niistä on erityissyntaksia, joita ei voi toteuttaa kielen keinoin, mutta mikään niistä ei lisää kielen ilmaisuvoimaa: kaikki asiat voidaan toteuttaa ilmankin tällaisia kielioppimakeisia. Kaiken pohjalla on periaatteessa enumeraatiotyypit. Esimerkiksi totuusarvojen tyyppi määritellään seuraavasti: data Bool = True False Uusien tietotyyppien määritelmä alkaa avainsanalla data, jota seuraa tietotyypin nimi (joka alkaa aina isolla kirjaimella) ja yhtäsuuruusmerkki. Oikealla puolella luetellaan tyypin konstruktorit (tässä tapauksessa vakioarvojen nimet), jotka kirjoitetaan aina isolla alkukirjaimella. Konstruktoreiden väliin laitetaan pystyviiva. Konstruktorien käyttöä kuvannee hyvin Esimerkki 4-1, jossa määritellään eräs tunnettu looginen konnektiivi. Esimerkki 4-1 Looginen konnektiivi and {- andornot.hs -} and True True = True and True False = False and False True = False and False False = False Kuten totuusarvojen tyyppi, myös kokonaislukujen tyyppi Int ja merkkien tyyppi Char voidaan toteuttaa luettelemalla kaikki lailliset arvot (konstruktorit). Nyt vain sattuu olemaan niin, että nämä konstruktorit kirjoitetaan epätavalliseen tapaan: 42 ja p. Listatyyppiä ei voi määritellä edellä esitettyyn tapaan. Lista on polymorfinen astia: se sisältää useita tietoja, jotka ovat samantyyppisiä, mutta eri listoissa voi tämä tyyppi olla eri. Tätä varten tyypin nimen jälkeen kirjoitetaan tyyppimäärittelyssä yksi tai useampiatyyppiparametreja (pienellä kirjaimella alkava nimi); myös konstruktorien jälkeen voidaan kirjoittaa nolla tai useampi tyypin nimen yhteydessä mainittu parametri: data List a = Nil Cons a (List a) Tässä tyypin ja konstruktorien nimet on valittu tavalliseen tapaan. Sisäänrakennettu listatyyppi käyttää samoista asioista nimiä [a] (listatyyppi, List a), [] (tyhjän listan konstruktori, Nil) ja a 12

13 Luku 4 Tyypeistä : [a] (cons-konstruktori, Cons a [a]). Parametrisoidun tyypin konkreettinen esiintymä kirjoitetaan tyyliin List Char, (eli tässä tapauksessa myös [Char]). Tällaisen tyypin parametrisoituja konstruktoreita myös käytetään niin, että parametrin tilalle laitetaan parametria vastavan tyypin arvo, esimerkiksi Cons a Nil (ts. a : []). Merkkijonot ovat yksinkertaisesti merkkilistoja, joten ei tarvita erillistä merkkijonotyyppiä. Siitä huolimatta on kiva käyttää siitä nimeä String, joten määritellään tyyppisynonyymi: type String = [Char] Huomaa uusi avainsana. Jokaisen lausekkeen ja jokaisen funktion tyyppi voidaa kirjoittaa ohjelmaan näkyviin. Joskus se on välttämätöntä, ja funktioiden tapauksessa se on yleensä hyvä idea vaikkapa vain varmistamaan, että funktion tyyppi on se, minkä ohjelmoija kuvittelee sen olevan (sillä tulkki tai kääntäjä valittaa, jos funktion esitelty tyyppi ja todellinen tyyppi eivät ole yhteensopivia). Lausekkeen tyyppi esitellään laittamalla tyyppi lausekkeen perään kahden kaksoipisteen jälkeen. On varminta pistää lauseke tätä ennen sulkeisiin, vaikka se ei kaikissa tilanteissa olekaan välttämätöntä. Funktion tyyppi esitellään suurin piirtein samaan tapaan; tosin kahden kaksoispisteen eteen laitetaan vain funktion nimi. Yhden muuttujan funktion tyyppi kirjoitetaan A -> B, kuten matematiikassakin. Tässä A on argumentin tyyppi ja B on paluuarvon tyyppi. Koska kahden muuttujan funktio on oikeastaan vain yhden muuttujan funktio, joka palauttaa yhden muuttujan funktion (ts. pätee f x y = (f x) y), voidaan kahden muuttujan funktion tyyppi kirjoittaa A -> (B -> C). Tavallisesti juuri samasta syystä on tapana jättää tästä sulkeet pois, joten A -> B -> C on kahden muuttujan funktion tyyppi. Tästä saadaan induktiivisesti kolmen muuttujan funktion tyyppi A -> B -> C -> D ja neljän muuttujan funktion tyyppi A -> B -> C -> D -> E ja niin edelleen. Jos funktio ottaa funktioparametrin, laitetaan parametrifunktion tyyppi sulkeisiin (joita ei voi jättää pois), esimerkiksi näin: Char -> (Char -> String) -> String, joka kuvaa kahden muuttujan funktiota, jonka ensimmäinen parametri on merkki ja toinen parameri on merkin merkkijonoksi muuttava funktio ja joka palauttaa merkkijonon. Funktion tai lausekkeen tyyppi voi olla polymorfinen; tällöin tyypinesittelyssä esiintyy tyyppinimien ja -lausekkeiden seassa pienellä alkukirjaimella kirjoitettuja tyyppiparametreja. Tällöin funktion aktuaalinen tyyppi annetussa tilanteessa riippuu siitä, minkätyyppiset parametrit sille annetaan ja mitä sen halutaan siinä paikassa palauttavan. Tällöin kukin tyyppiparametri saa yhden konkreettisen tyyppiarvon ja nämä arvot ovat voimassa koko tyyppikuvauksessa siinä tilanteessa. Jos esimerkiksi funktion id tyyppi on a -> a, ja sille annetaan parametriksi kokonaisluku, on funktion tämän ilmentymän tyyppi Integer -> Integer. Samassa ohjelmassa ja mahdollisesti jopa samassa lausekkeessa saatetaan samaa funktiota kutsua yhteydessä, jossa se voi palauttaa vain merkkijonoja; tässä tilanteessa sen ilmentymän tyyppi on String -> String. Parametrisoidut tyypit ja polymorfiset funktiot Haskellissa muistuttavat mm. C++:n template-tyyppejä ja -funktioita, ja näiden muistaminen voi auttaa Haskellin ymmärtämistä. Polymorfiset funktiot ja lausekkeet eivät välttämättä kelpuuta mitä tahansa tyyppiä tyyppiparametrinsa arvoksi: esimerkiksi voi olla välttämätöntä, että parametrityypin arvoja täytyy voida vertailla. Tämä vaatimus esitetään tyyppikuvauksessa laittamalla sen alkuun rajoitelauseke ja tämän perään =>. Rajoitelauseke voi koostua vain yhdestä rajoitteesta, tai sitten sulkeiden sisään 13

14 Luku 4 Tyypeistä laitetusta jonosta useita rajoitteita, jotka on erotettu pilkuilla. Kukin rajoite on muotoa Ord a, missä Ord on rajoitteen tyyppiluokka ja a on se tyyppiparametri, jota rajoite koskee. Esimerkiksi Eq a => tarkoittaa, että a:n arvojen yhtäsuuuruutta pitää voida verrata (==)-operaattorilla; vastaavasti (Ord a, Ord b) => tarkoittaa, että sekä a:n että b:n arvoja pitää voida verrata erisuuruusoperaattoreilla (<) yms. Esimerkki 4-2 Binäärinen hakupuu Seuraavassa pätkässä on kirjoitettu Haskellia literate programming -tyyliin, jossa oletuksena kaikki on kommenttia ja jokainen koodirivi täytyy aloittaa vasemmassa reunassa olevalla suurempi kuin -merkillä. {- bintree.lhs -} Binäärinen hakupuu on parametrisoitu rekursiivinen tietotyyppi. Puu voi olla tyhjä. Toisaalta se voi sisältää jonkin tiedonpalasen sekä kaksi alipuuta. > data BinaryTree a = EmptyTree > NonEmptyTree a (BinaryTree a) (BinaryTree a) > deriving (Show) Määrittelyn lopussa olevasta deriving-lauseesta ei kannata välittää, sillä se on mukana vain varmistamassa, että Hugs osaa tulostaa ruudulle tarvittaessa binääripuun. Binäärisen hakupuun syvyys määritellään seuraavasti: - tyhjän puun syvyys on 0 - epätyhjän puun syvyys on yksi enemmän kuin suurempi alipuiden syvyyksistä > depth :: BinaryTree a -> Integer > depth EmptyTree = 0 > depth (NonEmptyTree _ tl tr) = 1 + max (depth tl) (depth tr) Binääripuussa on voimassa seuraavanlaiset ehdot: Kaikki puun vasemmassa alipuussa olevat tiedot ovat aidosti pienempiä kuin puun (juuren) tieto. Kaikki puun oikeassa alipuussa olevat tiedot ovat aidosti suurempia kuin puun (juuren) tieto. Lisäys seuraa näistä ehdoista kohtuullisen helposti. > addtotree :: Ord a => a -> BinaryTree a -> BinaryTree a > addtotree d EmptyTree = NonEmptyTree d EmptyTree EmptyTree > addtotree d (NonEmptyTree d tl tr) > d < d = NonEmptyTree d (addtotree d tl) tr > d == d = error "Puussa on jo tämä alkio!" 14

15 Luku 4 Tyypeistä > d > d = NonEmptyTree d tl (addtotree d tr) Puusta etsiminen ja siitä poistaminen ovat harjoitustehtäviä. Jos funktion tyyppiä ei kirjoiteta näkyviin, tulkit ja kääntäjät olettavat tyypiksi suppeimman mahdollisen, joka kattaa kaikki mahdolliset funktion käytöt. Tietyissä tapauksissa funktion tyyppi on pakko kirjoittaa näkyviin. 15

16 Luku 5 I/O Syöttö ja tulostus ja yleensäkin kaikki ulkomaailman kanssa leikkiminen tehdään Haskellissa monadien avulla. Lisää tästä myöhemmin tällä ja seuraavilla sivuilla. IO-monadi on abstrakti parametrisoitu tietotyyppi, joka ilmaisee tietyntyyppistä tekemistä: merkkijonon lukemista, tekstin tulostamista, merkkijonon lukemista ja sen muokatun version tulostamista ja niin edelleen. Tämä vaatii yleensä imperatiivista ohjelmointia harrastaneelta ohjelmoijalta hieman totuttelua, joten kaikki se, mitä tässä luvussa sanotaan, voi aluksi tuntua täysin käsittämättömältä. Jokaisessa Haskell-ohjelmassa tulee olla funktio nimeltä main. Tämä funktio ei koskaan ota parametreja, ja se palauttaa IO a -tyyppisen arvon (missä a on mikä tahansa tyyppi, tavallisesti triviaali tyyppi, C:n void-tyyppiä vastaava ()). Tämän funktion paluuarvo kuvaa jotakin aktiota, tekemistä, ja tämä aktio toteutetaan, kun main on palannut. On äärimmäisen tärkeää ymmärtää, että Haskell-ohjelma suoritetaan vasta kuin main on palannut: koko "ohjelmakoodi"on vain tulkille tai kääntäjälle tarkoitettu kuvaus siitä, minkälainen varsinainen ohjelma on, ja tämä ohjelma palautetaan main-funktion paluuarvona. Yksinkertaisin teko, minkä voi tehdä, on olla tekemättä mitään. Tämän teon (puutteen) kuvauksen palauttaa return, jonka ainoa argumentti kertoo, minkä arvon tämä teko tuottaa: tässä tapauksessa se tuottaa ei-mitään, siis triviaalin tyypin () ainoan arvon (). Siipä maailman yksinkertaisin toimiva Haskell-ohjelma on {- trivial.hs -} main :: IO () main = return () joka ei tee yhtikäs mitään. Muistakaamme, että Luku 2 tarkastelee perinteistä yksinkertaista ohjelmaa, sellaista, joka tervehtii maailmaa. Sen main palauttaa teon, joka tulostaa ruudulle tervehdyksen. Tällaisen teon tuottaa funktio putstrln, jonka ainoa argumentti on tulostettava merkkijono. Kuten nimestä voi päätellä, tulostetaan rivinvaihto merkkijonon perään. Tässä Hello World uudestaan: {- hello.hs -} main :: IO () main = putstrln "Hello World!" Ohjelma voi myös pyytää käyttäjää kirjoittamaan jotain ruudulle. Tämän teon kuvaa funktio getline, joka ei huomaa! palauta käyttäjän kirjoittamaa riviä vaan kirjoittamispyyntöä kuvaavan abstraktin arvon. Tässä vaiheessa osaame vain palauttaa sen pääohjelman paluuarvona, mutta pian pääsemme myös itse riviin käsiksi. Seuraava ohjelma kysyy käyttäjältä rivin, muttei tee saamallaan tiedolla mitään. {- ask.hs -} main :: IO String main = getline 16

17 Luku 5 I/O Ei riitä, että osataan tehdä yksi asia; tekoja pitää voida yhdistää. Operaattori (>>) tuottaa aktion, joka ensin tekee vasemmanpuoleisen ja sitten oikeanpuoleisen teon. Se siis yhdistää nämä jonoksi tekoja. Seuraava ohjelma tulostaa ensin pyynnön kirjoittaa jotain, lukee rivin käyttäjältä ja tulostaa lopuksi kiitoksen. {- ask1.hs -} main :: IO () main = putstrln "Kirjoittaisitko jotain?" >> getline >> putstrln "Kiitos." Jotkin teot tuottavat tuloksenaan tietoa esimerkki tällaisesta on funktion getline palauttama teko. Tähän tulokseen päästään käsiksi operaattorin (>>=) avulla. Sen vasen operandi on jokin teko, joka tuottaa tiedon. Oikea puoli on funktio, jonka argumentiksi tämä tieto kelpaa ja joka palauttaa toisen aktion. Operaattori tuotta aktion, joka ensin tekee vasemman argumentin kertoman teon, antaa tämän tuloksen oikeanpuoleiselle funktiolle argumentiksi ja tekee lopuksi tämän palauttaman teon. {- pallo.hs -} main :: IO () main = putstrln "Minkä muotoinen pallo on?" >> getline >>= vastaus where vastaus rivi = putstrln ("Pallo on " ++ rivi ++ ".") Useimmiten oikeanpuolen funktioita tulee paljon, joten nimien keksiminen käy hankalaksi. Tämän (ja monen muunkin asian) vuoksi Haskellissa on olemassa lambda-abstraktioksi kutsuttu rakenne, joka määrittelee nimettömän funktion lennossa. Rakenne alkaa kenoviivalla, jonka jälkeen tulee parametrien kuvaukset ja lopulta nuoli ->. Funktion määrittely jatkuu tästä niin pitkälle kuin se on mahdollista. Äskeinen ohjelma voidaan nyt kirjoittaa helpommin: {- pallolambda.hs -} main :: IO () main = putstrln "Minkä muotoinen pallo on?" >> getline >>= \rivi -> putstrln ("Pallo on " ++ rivi ++ ".") Huomaa, että sopivalla vaakatilan käytöllä näin kirjoitettu ohjelma alkaa olla helppolukuinen: operaattori (>>) on kuin puolipiste muissa kielissä, ja rakenne >>= \x -> on kuin sijoituslause. Tähän havaintoon perustuu erittäin mukava syntaksimakeinen, jota sanotaan do-rakenteeksi avainsanansa mukaan. Sen käyttö muistuttaa päällisin puolin kovasti imperatiivista ohjelmointia, vaikka se on mekaanisesti ja vieläpä helposti muutettavissa edellä kuvatuiksi funktionaalisiksi rakenteiksi. Do-rakenne alkaa avainsanalla do, jota seuraa yksi tai useampi alikohta. Kukin alikohta on kahta mutoa: se voi koostua pelkästä lausekkeesta, tai sitten se voi koostua muuttujannimestä, nuolesta <- ja lausekkeesta. Edellisessä tapauksessa lausekkeen tuottama teko liitetään yhteen muun do-rakenteen kanssa (»)-operaattorilla. Jälkimmäinen, muotoa muuttuja <- lauseke 17

18 Luku 5 I/O oleva alikohta muutetaan muotoon lauseke >>= \muuttuja -> Näin pallo-ohjelma voidaan kirjoittaa seuraavasti: {- pallodo.hs -} main :: IO () main = do putstrln "Minkä muotoinen pallo on?" rivi <- getline putstrln ("Pallo on " ++ rivi ++ ".") Do-notaatiolla useimmat simppelit I/O-toiminnot onnistuvat helposti. Sen etu on, että sen kanssa voi useimmiten ajatella imperatiivisesti. Sen haittapuolena on se, että monet itsestäänselvältä tuntuvat muunnokset eivät ole sallittuja; esimerkiksi do l <- getline putstrln l ei ole sama asia kuin do putstrln getline Itse asiassa tämä jälkimmäinen ohjelmanpätkä ei edes mene tulkista tai kääntäjästä läpi! (Miksi? Ajattele tyyppejä.) Näin esoteerinen I/O-kieli on itse asiassa hyvä asia. Puhtaasti funktionaalisessa kielessä sivuvaikutukset ovat kiellettyjä, koska ne rikkovat viittausten läpinäkyvyyden (referential transparency). Esimerkiksi C:ssä tarpeettomalta näyttävää funktiokutsua ei saa poistaa, ellei kääntäjä näe, miten tuo on määritelty; tällaisen poistaminen voisi rikkoa koko ohjelman, koska jokin tärkeä muuttuja jäisi päivittymättä. Haskellissa ja muissa puhtaasti funktionaalisissa kielissä tämä ei ole ongelma: on taattua, että kaikki funktiokutsut, jotka "näyttävät samalta"(so. samaa funktiota kutsutaan samoilla argumenteilla), palauttavat aina saman tuloksen eikä niillä ole muita huomioonotettavia vaikutuksia. Näin kääntäjä voi järjestellä, poistella ja yhdistellä funktiokutsuja mielensä mukaan. Koska Haskellissa sivuvaikutukset kuvataan ohjelman aikana arvoina, jotka toteutetaan vasta ohjelman "päätyttyä", säilyy viittausten läpinäkyvyys. Koska syöttö- ja tulostus teot ovat täysivaltaisia arvoja, voidaan niitä käsitellä monin tavoin. Esimerkiksi teot voidaan tallettaa listaan ja niitä voi antaa funktiolle argumentteina. Esimerkki 5-1 sisältää hauskan ohjelman, joka tulostaa ruudulle erään juomalaulun sanat. Katso myös 99 Bottles of Beer, 227 Computer Beer Styles (http://www.ionet.net/~timtroyr/funhouse/beer.html). Esimerkki 5-1 Ninety-nine bottles of beer on the wall {- bottles.hs -} beer :: Integer -> IO () beer n = putstrln (bottles n ++ " bottles of beer on the wall,") >> putstrln (bottles n ++ " bottles of beer.") >> 18

19 Luku 5 I/O putstrln ("Take " ++ one n ++ " down and pass it around,") >> putstrln (bottles (n-1) ++ " bottles of beer on the wall.") >> putstrln where bottles 0 = "No bottles" bottles 1 = "One bottle" bottles 2 = "Two bottles" bottles 3 = "Three bottles" bottles 4 = "Four bottles" bottles 5 = "Five bottles" bottles 6 = "Six bottles" bottles 7 = "Seven bottles" bottles 8 = "Eight bottles" bottles 9 = "Nine bottles" bottles 10 = "Ten bottles" bottles 11 = "Eleven bottles" bottles 12 = "Twelve bottles" bottles n = show n ++ " bottles" one 1 = "it" one _ = "one" main :: IO () main = foldl (>>) (return ()) (map beer (reverse [1..99])) Huomaa, kuinka ohjelmassa ei näy silmukkaa eikä rekursiota. Tämän abstrahoi pois funktio foldl, joka tässä tapauksessa muuttaa listan aktioita uudeksi aktioksi, joka tekee nuo teot järjestyksessä. Tämän listan konstruoi map, joka tässä kuvaa kunkin luvun 99 1 yhden säkeistön tuottavaksi teoksi. Luettelo luvuista saadaan kääntämällä luettelo luvuista 1 99 ylösalaisin. 19

20 Liite A Lopuksi Jos et Haskellista muista mitään muuta, muista nämä asiat: Funktiot ovat arvoja siinä missä kaikki muutkin. Tietorakenteet voivat olla äärettömiä. Osa-algoritmin ei tarvitse pysähtyä, kunhan koko ohjelma käyttää tuloksesta vain äärellisessä ajassa laskettavissa olevan osan. Teot ovat arvoja siinä missä kaikki muutkin. Sivuvaikutuksia ei ole. Tietorakenteita ei voi muuttaa. Haskell on hauska kieli, vaikka sen oppiminen vaatiikin aikansa. 20

Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005 Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005 Tällä luennolla Algebralliset tietotyypit Hahmonsovitus (pattern matching) Primitiivirekursio Esimerkkinä binäärinen hakupuu Muistattehan...

Lisätiedot

tään painetussa ja käsin kirjoitetussa materiaalissa usein pienillä kreikkalaisilla

tään painetussa ja käsin kirjoitetussa materiaalissa usein pienillä kreikkalaisilla 2.5. YDIN-HASKELL 19 tään painetussa ja käsin kirjoitetussa materiaalissa usein pienillä kreikkalaisilla kirjaimilla. Jos Γ ja ovat tyyppilausekkeita, niin Γ on tyyppilauseke. Nuoli kirjoitetaan koneella

Lisätiedot

Tyyppejä ja vähän muutakin. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Tyyppejä ja vähän muutakin. TIEA341 Funktio ohjelmointi 1 Syksy 2005 Tyyppejä ja vähän muutakin TIEA341 Funktio ohjelmointi 1 Syksy 2005 Viime luennolla... Haskellin alkeita pääasiassa Hello World!... ja muita tutunoloisia ohjelmia Haskellilla Haskellin voima on kuitenkin

Lisätiedot

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset 815338A Ohjelmointikielten periaatteet 2015-2016. Harjoitus 6 Vastaukset Harjoituksen aiheena on funktionaalinen ohjelmointi Scheme- ja Haskell-kielillä. Voit suorittaa ohjelmat osoitteessa https://ideone.com/

Lisätiedot

Tämän vuoksi kannattaa ottaa käytännöksi aina kirjoittaa uuden funktion tyyppi näkyviin, ennen kuin alkaa sen määritemää kirjoittamaan.

Tämän vuoksi kannattaa ottaa käytännöksi aina kirjoittaa uuden funktion tyyppi näkyviin, ennen kuin alkaa sen määritemää kirjoittamaan. 3.1. LISTAT 35 destaan pisteittäisesti: init :: [α] [α] init (x : []) = [] init (x : xs) = x : init xs Varuskirjastoon kuuluu myös funktiot take ja drop, jotka ottavat tai tiputtavat pois, funktiosta riippuen,

Lisätiedot

TIEA341 Funktio-ohjelmointi 1, kevät 2008

TIEA341 Funktio-ohjelmointi 1, kevät 2008 TIEA341 Funktio-ohjelmointi 1, kevät 2008 Luento 5 Ympärysmitta. Puut. Antti-Juhani Kaijanaho Jyväskylän yliopisto Tietotekniikan laitos 21. tammikuuta 2008 CASE: YMPÄRYSMITTA Lasketaan kuvioiden ympärysmittoja

Lisätiedot

TIEA341 Funktio-ohjelmointi 1, kevät 2008

TIEA341 Funktio-ohjelmointi 1, kevät 2008 TIEA341 Funktio-ohjelmointi 1, kevät 2008 Luento 10 Todistamisesta Antti-Juhani Kaijanaho Jyväskylän yliopisto Tietotekniikan laitos 21. tammikuuta 2008 Samuuden todistaminen usein onnistuu ihan laskemalla

Lisätiedot

Laajennetaan vielä Ydin-Haskellia ymmärtämään vakiomäärittelyt. Määrittely on muotoa

Laajennetaan vielä Ydin-Haskellia ymmärtämään vakiomäärittelyt. Määrittely on muotoa 2.6. TIETOKONE LASKIMENA 23 Edellä esitetty Ydin-Haskell on hyvin lähellä sitä kieltä, jota GHCi (Glasgow Haskell Compiler, Interactive) sekä muut Haskell-järjestelmät suostuvat ymmärtämään. Esimerkiksi:

Lisätiedot

Java-kielen perusteet

Java-kielen perusteet Java-kielen perusteet Tunnus, varattu sana, kommentti Muuttuja, alkeistietotyyppi, merkkijono, literaalivakio, nimetty vakio Tiedon merkkipohjainen tulostaminen 1 Tunnus Java tunnus Java-kirjain Java-numero

Lisätiedot

ITKP102 Ohjelmointi 1 (6 op)

ITKP102 Ohjelmointi 1 (6 op) ITKP102 Ohjelmointi 1 (6 op) Tentaattori: Antti-Jussi Lakanen 7. huhtikuuta 2017 Vastaa kaikkiin tehtäviin. Tee jokainen tehtävä erilliselle konseptiarkille. Kirjoittamasi luokat, funktiot ja aliohjelmat

Lisätiedot

Java-kielen perusteet

Java-kielen perusteet Java-kielen perusteet Tunnus, varattu sana, kommentti Muuttuja, alkeistietotyyppi, merkkijono, Vakio Tiedon merkkipohjainen tulostaminen Ohjelmointi (ict1tx006) Tunnus (5.3) Javan tunnus Java-kirjain Java-numero

Lisätiedot

TIEA341 Funktio-ohjelmointi 1, kevät 2008

TIEA341 Funktio-ohjelmointi 1, kevät 2008 TIEA341 Funktio-ohjelmointi 1, kevät 2008 Luento 4 Antti-Juhani Kaijanaho Jyväskylän yliopisto Tietotekniikan laitos 17. tammikuuta 2008 Modulin viimeistelyä module Shape ( Shape ( Rectangle, E l l i p

Lisätiedot

Haskell ohjelmointikielen tyyppijärjestelmä

Haskell ohjelmointikielen tyyppijärjestelmä Haskell ohjelmointikielen tyyppijärjestelmä Sakari Jokinen Helsinki 19. huhtikuuta 2004 Ohjelmointikielten perusteet - seminaarityö HELSINGIN YLIOPISTO Tietojenkäsittelytieteen laitos 1 Johdanto 1 Tyyppien

Lisätiedot

815338A Ohjelmointikielten periaatteet 2014-2015. Harjoitus 7 Vastaukset

815338A Ohjelmointikielten periaatteet 2014-2015. Harjoitus 7 Vastaukset 815338A Ohjelmointikielten periaatteet 2014-2015. Harjoitus 7 Vastaukset Harjoituksen aiheena on funktionaalinen ohjelmointi Scheme- ja Haskell-kielillä. Voit suorittaa ohjelmat osoitteessa https://ideone.com/

Lisätiedot

Tyyppiluokat II konstruktoriluokat, funktionaaliset riippuvuudet. TIES341 Funktio-ohjelmointi 2 Kevät 2006

Tyyppiluokat II konstruktoriluokat, funktionaaliset riippuvuudet. TIES341 Funktio-ohjelmointi 2 Kevät 2006 Tyyppiluokat II konstruktoriluokat, funktionaaliset riippuvuudet TIES341 Funktio-ohjelmointi 2 Kevät 2006 Alkuperäislähteitä Philip Wadler & Stephen Blott: How to make ad-hoc polymorphism less ad-hoc,

Lisätiedot

Luku 3. Listankäsittelyä. 3.1 Listat

Luku 3. Listankäsittelyä. 3.1 Listat Luku 3 Listankäsittelyä Funktio-ohjelmoinnin tärkein yksittäinen tietorakenne on lista. Listankäsittely on paitsi käytännöllisesti oleellinen aihe, se myös valaisee funktio-ohjelmoinnin ideaa. 3.1 Listat

Lisätiedot

Alkuarvot ja tyyppimuunnokset (1/5) Alkuarvot ja tyyppimuunnokset (2/5) Alkuarvot ja tyyppimuunnokset (3/5)

Alkuarvot ja tyyppimuunnokset (1/5) Alkuarvot ja tyyppimuunnokset (2/5) Alkuarvot ja tyyppimuunnokset (3/5) Alkuarvot ja tyyppimuunnokset (1/5) Aiemmin olemme jo antaneet muuttujille alkuarvoja, esimerkiksi: int luku = 123; Alkuarvon on oltava muuttujan tietotyypin mukainen, esimerkiksi int-muuttujilla kokonaisluku,

Lisätiedot

TIEA341 Funktio-ohjelmointi 1, kevät 2008

TIEA341 Funktio-ohjelmointi 1, kevät 2008 TIEA34 Funktio-ohjelmointi, kevät 2008 Luento 3 Antti-Juhani Kaijanaho Jyväskylän yliopisto Tietotekniikan laitos 2. tammikuuta 2008 Ydin-Haskell: Syntaksi Lausekkeita (e) ovat: nimettömät funktiot: \x

Lisätiedot

Ohjelmointitaito (ict1td002, 12 op) Kevät 2008. 1. Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen raine.kauppinen@haaga-helia.

Ohjelmointitaito (ict1td002, 12 op) Kevät 2008. 1. Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen raine.kauppinen@haaga-helia. Ohjelmointitaito (ict1td002, 12 op) Kevät 2008 Raine Kauppinen raine.kauppinen@haaga-helia.fi 1. Java-ohjelmoinnin alkeita Tietokoneohjelma Java-kieli ja Eclipse-ympäristö Java-ohjelma ja ohjelmaluokka

Lisätiedot

Luku 4. Tietorakenteet funktio-ohjelmoinnissa. 4.1 Äärelliset kuvaukset

Luku 4. Tietorakenteet funktio-ohjelmoinnissa. 4.1 Äärelliset kuvaukset Luku 4 Tietorakenteet funktio-ohjelmoinnissa Koska funktio-ohjelmoinnissa ei käytetä tuhoavaa päivitystä (sijoituslausetta ja sen johdannaisia), eivät läheskään kaikki valtavirtaohjelmoinnista tutut tietorakenteet

Lisätiedot

2.4 Normaalimuoto, pohja ja laskentajärjestys 2.4. NORMAALIMUOTO, POHJA JA LASKENTAJÄRJESTYS 13

2.4 Normaalimuoto, pohja ja laskentajärjestys 2.4. NORMAALIMUOTO, POHJA JA LASKENTAJÄRJESTYS 13 2.4. NORMAALIMUOTO, POHJA JA LASKENTAJÄRJESTYS 13 Toisinaan voi olla syytä kirjoittaa α- tai β-kirjain yhtäsuuruusmerkin yläpuolelle kertomaan, mitä muunnosta käytetään. Esimerkki 4 1. (λx.x)y β = y 2.

Lisätiedot

Johdatus Ohjelmointiin

Johdatus Ohjelmointiin Johdatus Ohjelmointiin Syksy 2006 Viikko 2 13.9. - 14.9. Tällä viikolla käsiteltävät asiat Peruskäsitteitä Kiintoarvot Tiedon tulostus Yksinkertaiset laskutoimitukset Muuttujat Tiedon syöttäminen Hyvin

Lisätiedot

Laiska laskenta, korekursio ja äärettömyys. TIEA341 Funktio ohjelmointi Syksy 2005

Laiska laskenta, korekursio ja äärettömyys. TIEA341 Funktio ohjelmointi Syksy 2005 Laiska laskenta, korekursio ja äärettömyys TIEA341 Funktio ohjelmointi Syksy 2005 Muistatko graafinsievennyksen? DAG esitys ja graafinsievennys DAG esitys Lausekkeen rakennepuu, jossa yhteiset alilausekkeet

Lisätiedot

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset 815338A Ohjelmointikielten periaatteet 2015-2016. Harjoitus 2 vastaukset Harjoituksen aiheena on BNF-merkinnän käyttö ja yhteys rekursiivisesti etenevään jäsentäjään. Tehtävä 1. Mitkä ilmaukset seuraava

Lisätiedot

ITKP102 Ohjelmointi 1 (6 op)

ITKP102 Ohjelmointi 1 (6 op) ITKP102 Ohjelmointi 1 (6 op) Tentaattori: Antti-Jussi Lakanen 22. huhtikuuta 2016 Vastaa kaikkiin tehtäviin. Tee jokainen tehtävä erilliselle konseptiarkille! Kirjoittamasi luokat, funktiot ja aliohjelmat

Lisätiedot

TIEA341 Funktio-ohjelmointi 1, kevät 2008

TIEA341 Funktio-ohjelmointi 1, kevät 2008 TIEA341 Funktio-ohjelmointi 1, kevät 2008 Luento 3 Antti-Juhani Kaijanaho Jyväskylän yliopisto Tietotekniikan laitos 14. tammikuuta 2008 Viittausten läpinäkyvyyden 1 periaatteet 1. Lausekkeen arvo ei riipu

Lisätiedot

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python Ohjelmoinnin perusteet Y Python T-106.1208 1.4.2009 T-106.1208 Ohjelmoinnin perusteet Y 1.4.2009 1 / 56 Tentti Ensimmäinen tenttimahdollisuus on pe 8.5. klo 13:00 17:00 päärakennuksessa. Tämän jälkeen

Lisätiedot

TIEA341 Funktio-ohjelmointi 1, kevät 2008

TIEA341 Funktio-ohjelmointi 1, kevät 2008 TIEA341 Funktio-ohjelmointi 1, kevät 2008 Luento 14: Monadit Antti-Juhani Kaijanaho Jyväskylän yliopisto Tietotekniikan laitos 21. tammikuuta 2008 Tyyppien tyypit eli luonteet engl. kind tyyppinimet, kuten

Lisätiedot

Approbatur 3, demo 1, ratkaisut A sanoo: Vähintään yksi meistä on retku. Tehtävänä on päätellä, mitä tyyppiä A ja B ovat.

Approbatur 3, demo 1, ratkaisut A sanoo: Vähintään yksi meistä on retku. Tehtävänä on päätellä, mitä tyyppiä A ja B ovat. Approbatur 3, demo 1, ratkaisut 1.1. A sanoo: Vähintään yksi meistä on retku. Tehtävänä on päätellä, mitä tyyppiä A ja B ovat. Käydään kaikki vaihtoehdot läpi. Jos A on rehti, niin B on retku, koska muuten

Lisätiedot

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python Ohjelmoinnin perusteet Y Python T-106.1208 2.3.2009 T-106.1208 Ohjelmoinnin perusteet Y 2.3.2009 1 / 28 Puhelinluettelo, koodi def lue_puhelinnumerot(): print "Anna lisattavat nimet ja numerot." print

Lisätiedot

Osoitin ja viittaus C++:ssa

Osoitin ja viittaus C++:ssa Osoitin ja viittaus C++:ssa Osoitin yksinkertaiseen tietotyyppiin Osoitin on muuttuja, joka sisältää jonkin toisen samantyyppisen muuttujan osoitteen. Ohessa on esimerkkiohjelma, jossa määritellään kokonaislukumuuttuja

Lisätiedot

Se mistä tilasta aloitetaan, merkitään tyhjästä tulevalla nuolella. Yllä olevassa esimerkissä aloitustila on A.

Se mistä tilasta aloitetaan, merkitään tyhjästä tulevalla nuolella. Yllä olevassa esimerkissä aloitustila on A. Tehtävä. Tämä tehtävä on aineistotehtävä, jossa esitetään ensin tehtävän teoria. Sen jälkeen esitetään neljä kysymystä, joissa tätä teoriaa pitää soveltaa. Mitään aikaisempaa tehtävän aihepiirin tuntemusta

Lisätiedot

Tutoriaaliläsnäoloista

Tutoriaaliläsnäoloista Tutoriaaliläsnäoloista Tutoriaaliläsnäolokierroksella voi nyt täyttää anomuksen läsnäolon merkitsemisestä Esim. tagi ei toiminut, korvavaltimon leikkaus, yms. Hyväksyn näitä omaa harkintaa käyttäen Tarkoitus

Lisätiedot

58131 Tietorakenteet ja algoritmit (syksy 2015)

58131 Tietorakenteet ja algoritmit (syksy 2015) 58131 Tietorakenteet ja algoritmit (syksy 2015) Harjoitus 2 (14. 18.9.2015) Huom. Sinun on tehtävä vähintään kaksi tehtävää, jotta voit jatkaa kurssilla. 1. Erään algoritmin suoritus vie 1 ms, kun syötteen

Lisätiedot

Tietueet. Tietueiden määrittely

Tietueet. Tietueiden määrittely Tietueet Tietueiden määrittely Tietue on tietorakenne, joka kokoaa yhteen eri tyyppistä tietoa yhdeksi asiakokonaisuudeksi. Tähän kokonaisuuteen voidaan viitata yhteisellä nimellä. Auttaa ohjelmoijaa järjestelemään

Lisätiedot

Rekursiolause. Laskennan teorian opintopiiri. Sebastian Björkqvist. 23. helmikuuta Tiivistelmä

Rekursiolause. Laskennan teorian opintopiiri. Sebastian Björkqvist. 23. helmikuuta Tiivistelmä Rekursiolause Laskennan teorian opintopiiri Sebastian Björkqvist 23. helmikuuta 2014 Tiivistelmä Työssä käydään läpi itsereplikoituvien ohjelmien toimintaa sekä esitetään ja todistetaan rekursiolause,

Lisätiedot

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin peruskurssi Y1 Ohjelmoinnin peruskurssi Y1 CSE-A1111 30.9.2015 CSE-A1111 Ohjelmoinnin peruskurssi Y1 30.9.2015 1 / 27 Mahdollisuus antaa luentopalautetta Goblinissa vasemmassa reunassa olevassa valikossa on valinta Luentopalaute.

Lisätiedot

Koottu lause; { ja } -merkkien väliin kirjoitetut lauseet muodostavat lohkon, jonka sisällä lauseet suoritetaan peräkkäin.

Koottu lause; { ja } -merkkien väliin kirjoitetut lauseet muodostavat lohkon, jonka sisällä lauseet suoritetaan peräkkäin. 2. Ohjausrakenteet Ohjausrakenteiden avulla ohjataan ohjelman suoritusta. peräkkäisyys valinta toisto Koottu lause; { ja } -merkkien väliin kirjoitetut lauseet muodostavat lohkon, jonka sisällä lauseet

Lisätiedot

TIEA341 Funktio-ohjelmointi 1, kevät 2008

TIEA341 Funktio-ohjelmointi 1, kevät 2008 TIEA341 Funktio-ohjelmointi 1, kevät 2008 Antti-Juhani Kaijanaho Jyväskylän yliopisto Tietotekniikan laitos 10. tammikuuta 2008 Arvot... ovat laskutoimituksen lopputuloksia... ovat lausekkeita, joihin

Lisätiedot

Tietorakenteet ja algoritmit

Tietorakenteet ja algoritmit Tietorakenteet ja algoritmit Rekursio Rekursion käyttötapauksia Rekursio määritelmissä Rekursio ongelmanratkaisussa ja ohjelmointitekniikkana Esimerkkejä taulukolla Esimerkkejä linkatulla listalla Hanoin

Lisätiedot

TIEA341 Funktio-ohjelmointi 1, kevät 2008

TIEA341 Funktio-ohjelmointi 1, kevät 2008 TIEA341 Funktio-ohjelmointi 1, kevät 2008 Luento 11 Antti-Juhani Kaijanaho Jyväskylän yliopisto Tietotekniikan laitos 21. tammikuuta 2008 Listakomprehensio Uusi tapa luoda (ja muokata) listoja: [ lauseke

Lisätiedot

Sisällys. 1. Omat operaatiot. Yleistä operaatioista. Yleistä operaatioista

Sisällys. 1. Omat operaatiot. Yleistä operaatioista. Yleistä operaatioista Sisällys 1. Omat operaatiot Yleistä operaatioista. Mihin operaatioita tarvitaan? Oman operaation määrittely. Yleisesti, nimeäminen ja hyvä ohjelmointitapa, määreet, parametrit ja näkyvyys. HelloWorld-ohjelma

Lisätiedot

Jatkeet. TIES341 Funktio ohjelmointi 2 Kevät 2006

Jatkeet. TIES341 Funktio ohjelmointi 2 Kevät 2006 Jatkeet TIES341 Funktio ohjelmointi 2 Kevät 2006 Havainto: häntäkutsu (1) Funktiokutsun yleinen toimintaperiaate: (koskee vain täysiä kutsuja, ts. jotka eivät palauta funktiota) kutsuja kirjaa pinoon paluuosoitteen

Lisätiedot

ATK tähtitieteessä. Osa 3 - IDL proseduurit ja rakenteet. 18. syyskuuta 2014

ATK tähtitieteessä. Osa 3 - IDL proseduurit ja rakenteet. 18. syyskuuta 2014 18. syyskuuta 2014 IDL - proseduurit Viimeksi käsiteltiin IDL:n interaktiivista käyttöä, mutta tämä on hyvin kömpelöä monimutkaisempia asioita tehtäessä. IDL:llä on mahdollista tehdä ns. proseduuri-tiedostoja,

Lisätiedot

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python Ohjelmoinnin perusteet Y Python T-106.1208 25.2.2009 T-106.1208 Ohjelmoinnin perusteet Y 25.2.2009 1 / 34 Syötteessä useita lukuja samalla rivillä Seuraavassa esimerkissä käyttäjä antaa useita lukuja samalla

Lisätiedot

IDL - proseduurit. ATK tähtitieteessä. IDL - proseduurit

IDL - proseduurit. ATK tähtitieteessä. IDL - proseduurit IDL - proseduurit 25. huhtikuuta 2017 Viimeksi käsiteltiin IDL:n interaktiivista käyttöä, mutta tämä on hyvin kömpelöä monimutkaisempia asioita tehtäessä. IDL:llä on mahdollista tehdä ns. proseduuri-tiedostoja,

Lisätiedot

Metodit. Metodien määrittely. Metodin parametrit ja paluuarvo. Metodien suorittaminen eli kutsuminen. Metodien kuormittaminen

Metodit. Metodien määrittely. Metodin parametrit ja paluuarvo. Metodien suorittaminen eli kutsuminen. Metodien kuormittaminen Metodit Metodien määrittely Metodin parametrit ja paluuarvo Metodien suorittaminen eli kutsuminen Metodien kuormittaminen 1 Mikä on metodi? Metodi on luokan sisällä oleva yhteenkuuluvien toimintojen kokonaisuus

Lisätiedot

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä Ohjelmoinnin peruskurssien laaja oppimäärä Luento 7: Funktionaalista ohjelmointia (mm. SICP 3.5) Riku Saikkonen 13. 11. 2012 Sisältö 1 Laiskaa laskentaa: delay ja force 2 Funktionaalinen I/O 3 Funktionaalista

Lisätiedot

Abstraktit tietotyypit. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Abstraktit tietotyypit. TIEA341 Funktio ohjelmointi 1 Syksy 2005 Abstraktit tietotyypit TIEA341 Funktio ohjelmointi 1 Syksy 2005 Data abstraktio Abstraktio on ohjelmoinnin tärkein väline Data abstraktio abstrahoi dataa Abstrakti tietotyyppi Koostuu kolmesta asiasta:

Lisätiedot

TIEA341 Funktio-ohjelmointi 1, kevät 2008

TIEA341 Funktio-ohjelmointi 1, kevät 2008 TIEA341 Funktio-ohjelmointi 1, kevät 2008 Luento 9 Kombinaattoreista Antti-Juhani Kaijanaho Jyväskylän yliopisto Tietotekniikan laitos 21. tammikuuta 2008 Currying Haskell-funktio ottaa aina vain yhden

Lisätiedot

Informaatioteknologian laitos Olio-ohjelmoinnin perusteet / Salo 15.2.2006

Informaatioteknologian laitos Olio-ohjelmoinnin perusteet / Salo 15.2.2006 TURUN YLIOPISTO DEMO III Informaatioteknologian laitos tehtävät Olio-ohjelmoinnin perusteet / Salo 15.2.2006 1. Tässä tehtävässä tarkastellaan erääntyviä laskuja. Lasku muodostaa oman luokkansa. Laskussa

Lisätiedot

Demo 7 ( ) Antti-Juhani Kaijanaho. 9. joulukuuta 2005

Demo 7 ( ) Antti-Juhani Kaijanaho. 9. joulukuuta 2005 Demo 7 (14.12.2005) Antti-Juhani Kaijanaho 9. joulukuuta 2005 Liitteenä muutama esimerkki Ydin-Haskell-laskuista. Seuraavassa on enemmän kuin 12 nimellistä tehtävää; ylimääräiset ovat bonustehtäviä, joilla

Lisätiedot

1. Omat operaatiot 1.1

1. Omat operaatiot 1.1 1. Omat operaatiot 1.1 Sisällys Yleistä operaatioista. Mihin operaatioita tarvitaan? Oman operaation määrittely. Yleisesti, nimeäminen ja hyvä ohjelmointitapa, määreet, parametrit ja näkyvyys. HelloWorld-ohjelma

Lisätiedot

815338A Ohjelmointikielten periaatteet Harjoitus 4 vastaukset

815338A Ohjelmointikielten periaatteet Harjoitus 4 vastaukset 815338A Ohjelmointikielten periaatteet 2015-2016. Harjoitus 4 vastaukset Harjoituksen aiheena ovat imperatiivisten kielten lauseisiin, lausekkeisiin ja aliohjelmiin liittyvät kysymykset. Tehtävä 1. Mitä

Lisätiedot

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä Ohjelmoinnin peruskurssien laaja oppimäärä Luento 2: SICP kohdat 22.2.3 Riku Saikkonen 2. 11. 2010 Sisältö 1 Linkitetyt listat 2 Listaoperaatioita 3 Listarakenteet 4 Gambit-C:n Scheme-debuggeri Linkitetyt

Lisätiedot

Operaattoreiden ylikuormitus. Operaattoreiden kuormitus. Operaattoreiden kuormitus. Operaattoreista. Kuormituksesta

Operaattoreiden ylikuormitus. Operaattoreiden kuormitus. Operaattoreiden kuormitus. Operaattoreista. Kuormituksesta C++ - perusteet Java-osaajille luento 5/7: operaattoreiden ylikuormitus, oliotaulukko, parametrien oletusarvot, komentoriviparametrit, constant, inline, Operaattoreiden ylikuormitus Operaattoreiden kuormitus

Lisätiedot

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 30. marraskuuta 2015

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 30. marraskuuta 2015 TIEA241 Automaatit ja kieliopit, syksy 2015 Antti-Juhani Kaijanaho TIETOTEKNIIKAN LAITOS 30. marraskuuta 2015 Sisällys t Väitöstilaisuus 4.12.2015 kello 12 vanhassa juhlasalissa S212 saa tulla 2 demoruksia

Lisätiedot

Tietotekniikan valintakoe

Tietotekniikan valintakoe Jyväskylän yliopisto Tietotekniikan laitos Tietotekniikan valintakoe 2..22 Vastaa kahteen seuraavista kolmesta tehtävästä. Kukin tehtävä arvostellaan kokonaislukuasteikolla - 25. Jos vastaat useampaan

Lisätiedot

Tietotyypit ja operaattorit

Tietotyypit ja operaattorit Tietotyypit ja operaattorit Luennossa tarkastellaan yksinkertaisten tietotyyppien int, double ja char muunnoksia tyypistä toiseen sekä esitellään uusia operaatioita. Numeeriset tietotyypit ja muunnos Merkkitieto

Lisätiedot

Java-kielen perusteita

Java-kielen perusteita Java-kielen perusteita valintalauseet 1 Johdantoa kontrollirakenteisiin Tähän saakka ohjelmissa on ollut vain peräkkäisyyttä eli lauseet on suoritettu peräkkäin yksi kerrallaan Tarvitsemme myös valintaa

Lisätiedot

Injektio. Funktiota sanotaan injektioksi, mikäli lähtöjoukon eri alkiot kuvautuvat maalijoukon eri alkioille. Esim.

Injektio. Funktiota sanotaan injektioksi, mikäli lähtöjoukon eri alkiot kuvautuvat maalijoukon eri alkioille. Esim. Injektio Funktiota sanotaan injektioksi, mikäli lähtöjoukon eri alkiot kuvautuvat maalijoukon eri alkioille. Esim. Funktio f on siis injektio mikäli ehdosta f (x 1 ) = f (x 2 ) seuraa, että x 1 = x 2.

Lisätiedot

Vaihtoehtoinen tapa määritellä funktioita f : N R on

Vaihtoehtoinen tapa määritellä funktioita f : N R on Rekursio Funktio f : N R määritellään yleensä antamalla lauseke funktion arvolle f (n). Vaihtoehtoinen tapa määritellä funktioita f : N R on käyttää rekursiota: 1 (Alkuarvot) Ilmoitetaan funktion arvot

Lisätiedot

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset 815338A Ohjelmointikielten periaatteet 2015-2016. Harjoitus 3 vastaukset Harjoituksen aiheena ovat imperatiivisten kielten muuttujiin liittyvät kysymykset. Tehtävä 1. Määritä muuttujien max_num, lista,

Lisätiedot

Tietorakenteet ja algoritmit - syksy 2015 1

Tietorakenteet ja algoritmit - syksy 2015 1 Tietorakenteet ja algoritmit - syksy 2015 1 Tietorakenteet ja algoritmit - syksy 2015 2 Tietorakenteet ja algoritmit Johdanto Ari Korhonen Tietorakenteet ja algoritmit - syksy 2015 1. JOHDANTO 1.1 Määritelmiä

Lisätiedot

Tietorakenteet (syksy 2013)

Tietorakenteet (syksy 2013) Tietorakenteet (syksy 2013) Harjoitus 1 (6.9.2013) Huom. Sinun on osallistuttava perjantain laskuharjoitustilaisuuteen ja tehtävä vähintään kaksi tehtävää, jotta voit jatkaa kurssilla. Näiden laskuharjoitusten

Lisätiedot

Johdatus matematiikkaan

Johdatus matematiikkaan Johdatus matematiikkaan Luento 7 Mikko Salo 11.9.2017 Sisältö 1. Funktioista 2. Joukkojen mahtavuus Funktioista Lukiomatematiikassa on käsitelty reaalimuuttujan funktioita (polynomi / trigonometriset /

Lisätiedot

Taas laskin. TIES341 Funktio ohjelmointi 2 Kevät 2006

Taas laskin. TIES341 Funktio ohjelmointi 2 Kevät 2006 Taas laskin TIES341 Funktio ohjelmointi 2 Kevät 2006 Rakennepuutyyppi data Term = C Rational T F V String Term :+: Term Term : : Term Term :*: Term Term :/: Term Term :==: Term Term :/=: Term Term :

Lisätiedot

Kirjoita oma versio funktioista strcpy ja strcat, jotka saavat parametrinaan kaksi merkkiosoitinta.

Kirjoita oma versio funktioista strcpy ja strcat, jotka saavat parametrinaan kaksi merkkiosoitinta. Tehtävä 63. Kirjoita oma versio funktiosta strcmp(),joka saa parametrinaan kaksi merkkiosoitinta. Tee ohjelma, jossa luetaan kaksi merkkijonoa, joita sitten verrataan ko. funktiolla. Tehtävä 64. Kirjoita

Lisätiedot

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python Ohjelmoinnin perusteet Y Python T-106.1208 17.2.2010 T-106.1208 Ohjelmoinnin perusteet Y 17.2.2010 1 / 41 Sanakirja Monissa sovelluksissa on tallennettava rakenteeseen avain arvo-pareja. Myöhemmin rakenteesta

Lisätiedot

C++11 lambdat: [](){} Matti Rintala

C++11 lambdat: [](){} Matti Rintala C++11 lambdat: [](){} Matti Rintala bool(*)(int) Tarve Tarve välittää kirjastolle/funktiolle toiminnallisuutta Callback-funktiot Virhekäsittely Käyttöliittymät Geneeristen kirjastojen räätälöinti STL:n

Lisätiedot

Rekursio. Funktio f : N R määritellään yleensä antamalla lauseke funktion arvolle f (n). Vaihtoehtoinen tapa määritellä funktioita f : N R on

Rekursio. Funktio f : N R määritellään yleensä antamalla lauseke funktion arvolle f (n). Vaihtoehtoinen tapa määritellä funktioita f : N R on Rekursio Funktio f : N R määritellään yleensä antamalla lauseke funktion arvolle f (n). Vaihtoehtoinen tapa määritellä funktioita f : N R on käyttää rekursiota: Rekursio Funktio f : N R määritellään yleensä

Lisätiedot

AS-0.1103 C-ohjelmoinnin peruskurssi 2013: C-kieli käytännössä ja erot Pythoniin

AS-0.1103 C-ohjelmoinnin peruskurssi 2013: C-kieli käytännössä ja erot Pythoniin AS-0.1103 C-ohjelmoinnin peruskurssi 2013: C-kieli käytännössä ja erot Pythoniin Raimo Nikkilä Aalto-yliopiston sähkötekniikan korkeakoulu - Automaation tietotekniikan tutkimusryhmä 17. tammikuuta 2013

Lisätiedot

811120P Diskreetit rakenteet

811120P Diskreetit rakenteet 811120P Diskreetit rakenteet 2016-2017 ari.vesanen (at) oulu.fi 5. Rekursio ja induktio Rekursio tarkoittaa jonkin asian määrittelyä itseensä viittaamalla Tietojenkäsittelyssä algoritmin määrittely niin,

Lisätiedot

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python Ohjelmoinnin perusteet Y Python T-106.1208 28.2.2011 T-106.1208 Ohjelmoinnin perusteet Y 28.2.2011 1 / 46 Ohjelmointiprojektin vaiheet 1. Määrittely 2. Ohjelman suunnittelu (ohjelman rakenne ja ohjelman

Lisätiedot

Harjoitus 1 -- Ratkaisut

Harjoitus 1 -- Ratkaisut Kun teet harjoitustyöselostuksia Mathematicalla, voit luoda selkkariin otsikon (ja mahdollisia alaotsikoita...) määräämällä soluille erilaisia tyylejä. Uuden solun tyyli määrätään painamalla ALT ja jokin

Lisätiedot

ja λ 2 = 2x 1r 0 x 2 + 2x 1r 0 x 2

ja λ 2 = 2x 1r 0 x 2 + 2x 1r 0 x 2 Johdatus diskreettiin matematiikkaan Harjoitus 4, 7.10.2015 1. Olkoot c 0, c 1 R siten, että polynomilla r 2 c 1 r c 0 on kaksinkertainen juuri. Määritä rekursioyhtälön x n+2 = c 1 x n+1 + c 0 x n, n N,

Lisätiedot

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python Ohjelmoinnin perusteet Y Python T-106.1208 16.2.2010 T-106.1208 Ohjelmoinnin perusteet Y 16.2.2010 1 / 41 Kännykkäpalautetteen antajia kaivataan edelleen! Ilmoittaudu mukaan lähettämällä ilmainen tekstiviesti

Lisätiedot

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen Ohjelmointitaito (ict1td002, 12 op) Kevät 2009 Raine Kauppinen raine.kauppinen@haaga-helia.fi 1. Java-ohjelmoinnin alkeita Tietokoneohjelma Java-kieli ja Eclipse-kehitysympäristö Java-ohjelma ja luokka

Lisätiedot

3. Muuttujat ja operaatiot 3.1

3. Muuttujat ja operaatiot 3.1 3. Muuttujat ja operaatiot 3.1 Sisällys Imperatiivinen laskenta. Muuttujat. Nimi ja arvo. Muuttujan nimeäminen. Muuttujan tyyppi. Operaattorit. Operandit. Arvon sijoitus muuttujaan. Aritmeettiset operaattorit.

Lisätiedot

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 5. marraskuuta 2015

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 5. marraskuuta 2015 TIEA24 Automaatit ja kieliopit, syksy 205 Antti-Juhani Kaijanaho TIETOTEKNIIKAN LAITOS 5. marraskuuta 205 Sisällys Käsiteanalyysiä Tarkastellaan koodilukkoa äärellisenä automaattina. Deterministinen äärellinen

Lisätiedot

Matematiikan tukikurssi

Matematiikan tukikurssi Matematiikan tukikurssi Kurssikerta 4 Jatkuvuus Jatkuvan funktion määritelmä Tarkastellaan funktiota f x) jossakin tietyssä pisteessä x 0. Tämä funktio on tässä pisteessä joko jatkuva tai epäjatkuva. Jatkuvuuden

Lisätiedot

Sisällys. 3. Muuttujat ja operaatiot. Muuttujat ja operaatiot. Muuttujat. Operaatiot. Imperatiivinen laskenta. Muuttujat. Esimerkkejä: Operaattorit.

Sisällys. 3. Muuttujat ja operaatiot. Muuttujat ja operaatiot. Muuttujat. Operaatiot. Imperatiivinen laskenta. Muuttujat. Esimerkkejä: Operaattorit. 3. Muuttujat ja operaatiot Sisällys Imperatiivinen laskenta. Muuttujat. Nimi ja arvo. Muuttujan nimeäminen. Muuttujan tyyppi.. Operandit. Arvon sijoitus muuttujaan. Aritmeettiset operaattorit. Arvojen

Lisätiedot

Perusteet. Pasi Sarolahti Aalto University School of Electrical Engineering. C-ohjelmointi Kevät Pasi Sarolahti

Perusteet. Pasi Sarolahti Aalto University School of Electrical Engineering. C-ohjelmointi Kevät Pasi Sarolahti C! Perusteet 19.1.2017 Palautteesta (1. kierros toistaiseksi) (Erittäin) helppoa Miksi vain puolet pisteistä? Vaikeinta oli ohjelmointiympäristön asennus ja käyttö Ei selvää että main funktion pitikin

Lisätiedot

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä Ohjelmoinnin peruskurssien laaja oppimäärä Luento 6: Funktionaalista ohjelmointia: todistamisesta, virrat ja I/O, hahmonsovitus (mm. SICP 3.5) Riku Saikkonen 8. 11. 2011 Sisältö 1 Vähän funktionaalisten

Lisätiedot

Matriisit ovat matlabin perustietotyyppejä. Yksinkertaisimmillaan voimme esitellä ja tallentaa 1x1 vektorin seuraavasti: >> a = 9.81 a = 9.

Matriisit ovat matlabin perustietotyyppejä. Yksinkertaisimmillaan voimme esitellä ja tallentaa 1x1 vektorin seuraavasti: >> a = 9.81 a = 9. Python linkit: Python tutoriaali: http://docs.python.org/2/tutorial/ Numpy&Scipy ohjeet: http://docs.scipy.org/doc/ Matlabin alkeet (Pääasiassa Deni Seitzin tekstiä) Matriisit ovat matlabin perustietotyyppejä.

Lisätiedot

7/20: Paketti kasassa ensimmäistä kertaa

7/20: Paketti kasassa ensimmäistä kertaa Ohjelmointi 1 / syksy 2007 7/20: Paketti kasassa ensimmäistä kertaa Paavo Nieminen nieminen@jyu.fi Tietotekniikan laitos Informaatioteknologian tiedekunta Jyväskylän yliopisto Ohjelmointi 1 / syksy 2007

Lisätiedot

Z-skeemojen animointi Haskellilla

Z-skeemojen animointi Haskellilla Z-skeemojen animointi Haskellilla Antti-Juhani Kaijanaho 6. toukokuuta 2001 Sisältö 1 Johdanto 2 2 Joitakin funktionaalisen ohjelmoinnin käsitteitä 3 2.1 Imperatiivinen funktionaalinen ohjelmointi 3 2.2

Lisätiedot

Tarkastelemme ensin konkreettista esimerkkiä ja johdamme sitten yleisen säännön, joilla voidaan tietyissä tapauksissa todeta kielen ei-säännöllisyys.

Tarkastelemme ensin konkreettista esimerkkiä ja johdamme sitten yleisen säännön, joilla voidaan tietyissä tapauksissa todeta kielen ei-säännöllisyys. Ei-säännöllisiä kieliä [Sipser luku 1.4] Osoitamme, että joitain kieliä ei voi tunnistaa äärellisellä automaatilla. Tulos ei sinänsä ole erityisen yllättävä, koska äärellinen automaatti on äärimmäisen

Lisätiedot

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python Ohjelmoinnin perusteet Y Python T-106.1208 16.3.2009 T-106.1208 Ohjelmoinnin perusteet Y 16.3.2009 1 / 40 Kertausta: tiedostosta lukeminen Aluksi käsiteltävä tiedosto pitää avata: tiedostomuuttuja = open("teksti.txt","r")

Lisätiedot

Nimitys Symboli Merkitys Negaatio ei Konjuktio ja Disjunktio tai Implikaatio jos..., niin... Ekvivalenssi... jos ja vain jos...

Nimitys Symboli Merkitys Negaatio ei Konjuktio ja Disjunktio tai Implikaatio jos..., niin... Ekvivalenssi... jos ja vain jos... 2 Logiikkaa Tässä luvussa tutustutaan joihinkin logiikan käsitteisiin ja merkintöihin. Lisätietoja ja tarkennuksia löytyy esimerkiksi Jouko Väänäsen kirjasta Logiikka I 2.1 Loogiset konnektiivit Väitelauseen

Lisätiedot

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari 1 1. JOHDANTO 1.1 Määritelmiä 1.2 Tietorakenteen ja algoritmin valinta 1.3 Algoritmit ja tiedon määrä 1.4 Tietorakenteet ja toiminnot 1.5 Esimerkki:

Lisätiedot

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python Ohjelmoinnin perusteet Y Python T-106.1208 21.1.2009 T-106.1208 Ohjelmoinnin perusteet Y 21.1.2009 1 / 32 Tyypeistä Monissa muissa ohjelmointikielissä (esim. Java ja C) muuttujat on määriteltävä ennen

Lisätiedot

Prolog kielenä Periaatteet Yhteenveto. Prolog. Toni ja Laura Fadjukoff. 9. joulukuuta 2010

Prolog kielenä Periaatteet Yhteenveto. Prolog. Toni ja Laura Fadjukoff. 9. joulukuuta 2010 kielenä 9. joulukuuta 2010 Historia kielenä Historia Sovelluksia kehitettiin vuonna 1972 Kehittäjinä ranskalaiset Pääkehittäjä Alain Colmerauer Philippe Roussel programmation en logique Robert Kowalski

Lisätiedot

Kerta 2. Kerta 2 Kerta 3 Kerta 4 Kerta 5. 1. Toteuta Pythonilla seuraava ohjelma:

Kerta 2. Kerta 2 Kerta 3 Kerta 4 Kerta 5. 1. Toteuta Pythonilla seuraava ohjelma: Kerta 2 Kerta 3 Kerta 4 Kerta 5 Kerta 2 1. Toteuta Pythonilla seuraava ohjelma: 2. Tulosta Pythonilla seuraavat luvut allekkain a. 0 10 (eli, näyttää tältä: 0 1 2 3 4 5 6 7 8 9 10 b. 0 100 c. 50 100 3.

Lisätiedot

2. Lisää Java-ohjelmoinnin alkeita. Muuttuja ja viittausmuuttuja (1/4) Muuttuja ja viittausmuuttuja (2/4)

2. Lisää Java-ohjelmoinnin alkeita. Muuttuja ja viittausmuuttuja (1/4) Muuttuja ja viittausmuuttuja (2/4) 2. Lisää Java-ohjelmoinnin alkeita Muuttuja ja viittausmuuttuja Vakio ja literaalivakio Sijoituslause Syötteen lukeminen ja Scanner-luokka 1 Muuttuja ja viittausmuuttuja (1/4) Edellä mainittiin, että String-tietotyyppi

Lisätiedot

Yhtälönratkaisusta. Johanna Rämö, Helsingin yliopisto. 22. syyskuuta 2014

Yhtälönratkaisusta. Johanna Rämö, Helsingin yliopisto. 22. syyskuuta 2014 Yhtälönratkaisusta Johanna Rämö, Helsingin yliopisto 22. syyskuuta 2014 Yhtälönratkaisu on koulusta tuttua, mutta usein sitä tehdään mekaanisesti sen kummempia ajattelematta. Jotta pystytään ratkaisemaan

Lisätiedot

Tietorakenteet ja algoritmit syksy Laskuharjoitus 1

Tietorakenteet ja algoritmit syksy Laskuharjoitus 1 Tietorakenteet ja algoritmit syksy 2012 Laskuharjoitus 1 1. Tietojenkäsittelijä voi ajatella logaritmia usein seuraavasti: a-kantainen logaritmi log a n kertoo, kuinka monta kertaa luku n pitää jakaa a:lla,

Lisätiedot

815338A Ohjelmointikielten periaatteet 2015-2016. Harjoitus 5 Vastaukset

815338A Ohjelmointikielten periaatteet 2015-2016. Harjoitus 5 Vastaukset 815338A Ohjelmointikielten periaatteet 2015-2016. Harjoitus 5 Vastaukset Harjoituksen aiheena ovat aliohjelmat ja abstraktit tietotyypit sekä olio-ohjelmointi. Tehtävät tehdään C-, C++- ja Java-kielillä.

Lisätiedot

Kielioppia: toisin kuin Javassa

Kielioppia: toisin kuin Javassa Object Pascal Pascal kielen oliolaajennus (Inprise/Borland:n oma) luokat Voit uudelleenkäyttää luomiasi objekteja esim. komponentteja Periytyminen Kielioppia: toisin kuin Javassa Ei eroa isojen ja pienien

Lisätiedot

Matematiikan tukikurssi, kurssikerta 3

Matematiikan tukikurssi, kurssikerta 3 Matematiikan tukikurssi, kurssikerta 3 1 Epäyhtälöitä Aivan aluksi lienee syytä esittää luvun itseisarvon määritelmä: { x kun x 0 x = x kun x < 0 Siispä esimerkiksi 10 = 10 ja 10 = 10. Seuraavaksi listaus

Lisätiedot