Turingin koneet määritteli sen laitelähtöisesti: Laskenta etenee suorittamalla yksinkertaisia käskyjä siten kuin sen ohjelma

Koko: px
Aloita esitys sivulta:

Download "Turingin koneet määritteli sen laitelähtöisesti: Laskenta etenee suorittamalla yksinkertaisia käskyjä siten kuin sen ohjelma"

Transkriptio

1 1 Johdanto Aloitetaan lyhyellä kuvauksella funktionaalisen ohjelmoinnin ja siihen kannustavien ohjelmointikielten historiasta. Sitten kuvaillaan lyhyesti, mitä funktionaalisella ohjelmoinnilla tarkoitetaan ja millaisia piirteitä sillä on. 1.1 Historiaa 1936 eli jo ennen tietokoneita (joita alettiin rakentaa II maailmansodan jälkeen): Britanniassa loogikko Alan M. Turing julkaisi ns. Turingin koneet. Se oli hänen vastauksensa matemaattisen logiikan senhetkiseen polttavaan ongelmaan Miten pitäisi määritellä mitä käsite mekaanisesti laskettava tarkalleen tarkoittaa? Turingin koneet määritteli sen laitelähtöisesti: Laskenta etenee suorittamalla yksinkertaisia käskyjä siten kuin sen ohjelma määrää. Yhdysvalloissa loogikko Alonzo Church julkaisi muutamaa kuukautta myöhemmin Turingista riippumatta ns. λ- eli lambda-laskennan (λ-calculus) joka oli hänen vastauksensa samaan kysymykseen. Lambda-laskennassa mekaaninen laskenta eteneekin lausekkeita sieventämällä kuten matemaatikko tekisi kynällä ja paperilla. Churchin-Turingin teesi. Myöhemmin osoitettiin, että erilaisuudestaan huolimatta molemmat määritelmät ehdottivat mekaanisen laskennan tarkoittavan samaa asiaa. Saman asian oli jo 1933 määritellyt loogikko Kurt Gödel Itävallassa nimellä rekursiiviset funktiot. Hänen lähtökohtanaan taas oli kuvailla ja ymmärtää mitä matemaattinen induktio tarkoittaa. Niinpä Church muotoili kaksiosaisen teesinsä: Rekursiiviset funktiot ovat mekaanisen laskettavuuden oikea matemaattinen määritelmä. Turingin koneet ovat rekursiivisten funktioiden luonteva esitystapa alkoi nykyisten ohjelmointikielten aika: IBM julkaisi ohjelmointikielen Fortran (Formula translator) ensimmäisen version määrittelyn. Se oli käskypohjainen eli imperatiivinen kieli. Sen nykyiset versiot ovat yhä laajalti käytettyjä esimerkiksi laskennallisessa tieteessä ja supertietokonelaskennassa. Muutamaa kuukautta myöhemmin tutkija John McCarthy julkaisi ohjelmointikielen Lisp (List processing). Se pohjautui vahvasti lambda-laskentaan ja siten rohkaisi funktionaaliseen ohjelmointiin mutta sisälsi myös käskypohjaisia ominaisuuksia. Sen eri versioita on käytetty pitkään erityisesti tekoälyohjelmoinnissa luvuilla ohjelmoinnin ja ohjelmointikielten tutkimus kehittyi edelleen. 1

2 Lambda-laskenta havaittiin hyvin hyödylliseksi työvälineeksi tässä tutkimuksessa. Koska funktionaaliset ohjelmointikielet pohjautuivat siihen suoremmin kuin monet muut, useita tämän tutkimuksen ideoita ja tuloksia sovellettiin ensimmäiseksi juuri niihin. Vielä Lisp-kielessä ei ole käännösaikaista tyypitystä: tyyppivirheet kuten numeroa ei voi laskea yhteen merkkijonon kanssa havaitaan vasta ohjelman suoritusaikana luvulle tultaessa funktionaalisten ohjelmointikielten tutkimus oli edennyt niin pitkälle, että niitä voitiin alkaa standardoimaan. Ohjelmointikielen SML (Standard MetaLanguage) ensimmäinen standardi ilmestyi 1990 ja jälkimmäinen Sen kehitystyön osana syntyi käännösaikainen ns. Hindley-Milner- eli HMtyyppijärjestelmä, joka on sittemmin ollut pohjana useimmille myöhäisemmille tyyppijärjestelmille ohjelmointikielestä ja -paradigmasta riippumatta. J. Roger Hindley on loogikko, Robin Milner taas skotlantilainen tietojenkäsittelijä. Tyyppiteoria onkin syntynyt alun perin logiikan puolella, ja on sittemmin löytänyt uuden sovellusalueen ohjelmoinnista. SML rohkaisee Lisp-kieltä enemmän funktionaaliseen ohjelmointiin, mutta sisältää yhä myös käskypohjaisia ominaisuuksia. Erityisesti SML-kielen suoritusmekanismi on ns. ahkera (strict): Ohjelmaa suoritetaan eli sen lausekkeita sievennetään arvoikseen oleellisesti samassa järjestyksessä kuin ne ohjelmakoodissa määritelläänkin. Oman ohjelmointikielemme Haskell ensimmäinen standardi ilmestyi 1990, toinen 1998 (ns. Haskell 98) ja uusin Siinäkin on käännösaikainen HM-tyyppijärjestelmä, jota on edelleen laajennettu ns. tyyppiluokilla sekä muillakin kehittyneillä piirteillä. Se on puhdas (pure) funktionaalinen kieli: Siinä ei ole enää lainkaan käskypohjaisia piirteitä, vaan ohjelman suoritus etenee pelkästään soveltamalla funkioita niiden parametreihin. Lisäksi tämä suoritusmekanismi on laiska (lazy): Lausekkeen arvoa ei lasketakaan heti silloin kun se määritellään, vaan vasta myöhemmin silloin kun tai jos! sitä arvoa tarvitaan jonkin toisen arvon laskemiseksi. Laiskuus oikeastaan vaatii puhtauden toimiakseen aina järkevästi: Jos kielessä olisi käskyjä, joiden suoritusaika tai -järjestys ei määräytyisikään suoraan ohjelmakoodista, niin ohjelmoijan olisi hyvin hankala hahmottaa, mitä hänen ohjelmakoodinsa oikein tarkoittaakaan! Haskell-kehityksen alkupeäisenä ajatuksena olikin määritellä standardi laiska funktionaalinen kieli standardin ahkeran SML-kielen tapaan. Siksi kieli piti määritellä puhtaaksi. Sittemmin motivaatio on kääntynyt osin päinvastaiseksi: On haluttu kehittää puhdasta kieltä, ja sellaisen kannattaa olla samalla myös laiska. 2

3 1.2 Puhtaan funktionaalisen ohjelmoinnin periaatteista Churchin lambda-laskenta siis mallinsi mekaanista laskentaa, eli sitä mitä tietokoneet tekevät, lausekkeiden sieventämisenä. Matematiikassa voimme sieventää esimerkiksi vaikkapa lausekkeen tai vaihtoehtoisesti (f(x) f(x)) g(y) = 0 g(y) (1) (f(x) f(x)) g(y) = f(x) g(y) f(x) g(y) (2) ja tulos on molemmilla tavoilla silti sama riippumatta siitä, millaisia funktioita nämä f ja g ovat. = 0 (3) Yleisemminkin matematiikassa pätee viittausten läpinäkyvyyden (referential transparency) periaate: Lauseke voidaan aina korvata arvollaan ilman että lopputulos siitä muuttuu. Mutta tämä järkevä periaate ei pädekään ohjelmoinnissa! Jos funktion g suorittamisella olisi sivuvaikutuksena tulostaa "Hei" niin laskentatavalla (1) tulostuisi kerran "Hei"... mutta tavalla (2) kahdesti "HeiHei"... vaikka tuloksen (3) näkökulmasta ei ole edes selvää, pitäisikö sen tulostua kertaakaan. Tai entäpä jos g sivuvaikutuksenaan lukee syötettä käyttäjältä? Jos f puolestaan muuttaa jonkin globaalin muuttujan z arvoa jota g puolestaan lukee, niin silloin emme edes tiedä päteekö yhtälö (2) ollenkaan! Ongelman syy on se, että tämä ohjelmointikielen muuttuja z onkin nimi jollekin muistipaikalle jonka sisällön voi paitsi lukea myös kirjoittaa uudelleen uuteen arvoon. Siis tällaiset sivuvaikutukset ja ohjelmointikielen muuttujat rikkovat helposti viittausten läpinäkyvyden periaatetta. Tavallisesti ohjelmointikielet eivät noudatakaan viittausten läpinäkyvyyttä (tai tarkemmin sanoen, sallivat myös siitä poikkeamisenkin). Funktion arvon laskemisen sijasta puhutaankin funktion kutsumisesta ja ymmärretäänkin sen tarkoittavan, että suoritetaan kyseisen aliohjelman sisältämät käskyt kaikkine sivuvaikutuksineen. So what? Miksi ohjelmoinnin ja ohjelmointikielten pitäisikään noudattaa sitä? Koska ne matemaattiset menetelmät, joilla pyrimme perustelemaan että ohjelmamme tekevät mitä niiden pitääkin, tyypillisesti olettavat sen! Se siis parantaa laadunvalvontaa joka on sitä tärkeämpää mitä laajemmin tietokoneistamme yhteiskuntaamme. 3

4 Tarkastellaan siten millaisia piirteitä ohjelmointi saa, kun tämä periaate otetaan vakavasti. Matemaattiset funktiot. Funktiot eivät ole aliohjelmia vaan kuvauksia matemaattisessa mielessä, eli: Ainoa informaatio, joka funktiosta tulee ulos, on sen arvo. Ainoa informaatio, josta tämä ulos tuleva arvo riippuu, on funktion saamissa parametreissä. Tällöin sama funktio antaa aina samoilla parametriensa arvoilla tuloksekseen saman arvon. Matemaattiset muuttujat. Myöskään muuttujat eivät tarkoita muistipaikkoja vaan matemaattisia, eli: Kun muuttuja esitellään, niin silloin sille annetaan jokin arvo. Tämä arvo ei muutu toiseksi ohjelman edetessä. Siis uudelleensijoituslausetta ei ole. Toisto rekursiolla. Ilman uudelleensijoitusta ei tavallisista toistorakenteista ole hyötyä. Miten esimerkiksi tavallinen silmukka kuten 1 v = 0; z = alkuarvo 2 while z 0 3 v = v + z; z = lauseke 4 return v voisi toimia, ellei muistipaikan nimeltä z sisältöä voisi päivittää silmukan rungossa? Kaikki toisto tehdäänkin rekursiolla: tässä kutsulla silmukka(0, alkuarvo) apufunktioon silmukka(v, z): 1 if z 0 2 return silmukka(v + z, lauseke) 3 else return v koska kyllähän tämän funktion parametreilla v ja z voi olla eri arvot sen eri kutsuissa. Rajatut sivuvaikutukset. Tavallisesti ohjelmointikielissä syöte- ja tulostusoperaatiot perustuvat sivuvaikutuksiin, joten niitä on hankala ajatella matemaattisina funktioina: Operaatiota tulosta teksti... käytetään, koska tämä teksti halutaan näyttää, eikä koska haluttaisiin tietää minkä arvon se palauttaa tuloksenaan. Operaation lue seuraava syöterivi halutaan palauttavan eri käyttökerroillaan eri tulokset: ensimmäisen syöterivin, toisen, kolmannen,... 4

5 Funktionaalisessa ohjelmoinnissa ne pyritäänkin eristämään omaksi pieneksi osakseen koko ohjelmaa, jotta sen muut osat voidaan silti ajatella matemaattisina funktioina. Haskell-kieli vie tämänkin idean äärimmilleen: Siinä näillä operaatioilla on oma erityinen tyyppinsä, ja se pakottaa eristämään ne omaksi osakseen muualla niitä ei voi käyttää, koska se olisi tyyppivirhe, joten kääntäjä hylkäisi sellaisen ohjelman. Tietovuo kontrollivuon sijaan. Tavallisessa ohjelmoinnissa ohjelma pohjimmiltaan kuvaa tarkasti jonon (syötteenluku-, tulostus- ja sijoitus)käskyjä, jotka suoritettuina juuri tässä järjestyksessään tuottavat halutun lopputuloksen. Niiden yhteydessä puhutaankin kontrollivuosta (control flow): siitä, miten kontrolli eli missä käskyssä nyt ollaan menossa kulkee läpi ohjelma(teksti)n. Funktionaalisessa ohjelmoinnissa tavoitteena on taas laskea kysytyn lausekkeen arvo. Jos on noudatettu viittausten läpinäkyvuuden periaatetta, niin silloin ei ole väliä, miten se tarkkaan ottaen tapahtuu. Niinpä funktionaalisessa ohjelmassa ilmaistaankin vain tietovuot (control flows) eli vain se, mitä tietoja eri ohjelmanosissa tarvitaan ja mistä ne saadaan laskettua; kielen toteutus huolehtii kontrollista. Tämä vaikuttaakin hyvin lupaavalta ohjelmointityyliltä esimerkiksi nykyaikaisille moniprosessori- ja -ydinarkkitehtuureille... Deklaratiivisuus. Yleisemminkin funktionaalisessa ohjelmoinnissa pyritään ilmaisemaan se mitä halutaan laskea selittämättä yksityiskohtaisesti miten se voidaan tehdä. Funktiot abstraktion välineenä. Funktionaalisessa ohjelmoinnissa on luontevaa kirjoittaa esimerkiksi funktio map f l = se lista, joka saadaan soveltamalla funktiota f listan l jokaiseen alkioon vuorollaan. Se kuvaa abstraktisti yhden hyvin yleisen tavan käydä läpi listan l sisältöä ja operoida sillä; ohjelmoijan ei tarvitse kirjoittaa oleelliselle samaa silmukkaa aina uudelleen jokaiselle eri funktiolle f, vaan tämän silmukan kaikille yhteiset osat on abstrahoitu omaksi funktiokseen. Tämäkin tukee osaltaan tietovuo-ohjelmointia: lauseke map sqrt l lukee vuota l ja tuottaa siitä tulosvuon soveltamalla sen jokaiseen alkioon operaatiota neliöjuuri, ja niin edelleen. Funktiot ohjelmointikielen täysvaltaisina jäseninä. ( Functions as first-class citizens. ) Edellä funktio map sai ensimmäisenä parametrinaan funktion f. Funktionaalisessa ohjelmoinnissakin myös funktioita voi käyttää rajoituksetta samoin kuin muitakin arvoja: lähettää argumentteina toisiin funktioihin kirjoittaa funktioita jotka palauttavat muita funktioita arvoinaan tallettaa tietorakenteisiin,... Oliokielten myötä tämä idea on levinnut (tosin ei tällä nimellä) ohjelmointiin yleisemminkin. Mutta ennen sitä ohjelmointikielissä oli usein toteutusteknisistä syistä johtuvia rajoituksia, jotka estivät funktioiden täysin vapaan käytön. 5

6 Tilattomuus. Uudelleensijoitusta käyttävä ohjelmointi on pohjimmiltaan Turingin koneen filosofian mukaista: Ohjelman suoritus etenee tarkkaan kontrolloituna sarjan sellaisia askeleita, joissa koneen muistia muokataan ja siirrytään uuteen tilaan. Tämä tilan käsite onkin yleisellä tasolla juuri se, mikä rikkoo viittausten läpinäkyvyyden periaatteen: Lauseke voidaankin korvata arvollaan vain jos se ei muuta tilaa. Funktionaalisessa ohjelmoinnissa ei käytetäkään tällaista tilan käsitettä ja askellusta. Sen sijaan laskenta eteneekin sieventämällä annettua lauseketta kohti arvoaan. Silloin ei ohjelmoijan ja ohjelmointikielen näkökulmasta olekaan sellaista käsitettä kuin tila. Sellaista käyttää vain kielen toteutus, joka toimii välittäjänä tilattoman ohjelmointitavan ja tilaperustaisen laitteiston välillä. Tämäkin vaikuttaa lupaavalta moniprosessori- ja -ydinarkkitehtuureille... Millaisiin tehtäviin funktionaalinen ohjelmointi sopii erityisen hyvin? Sellaisiin, joissa käsitellään rakenteista kuten vaikkapa puumaista tietoa: XML-dokumenttien, luonnollisen kielen, ohjelmointikielten, sekä matemaattisten ja loogisten lausekkeiden jäsentäminen ja käsittely,... Niitä on erityisen helppo esittää funktionaalisten kielten tarjoamilla ns. algebrallisilla tietotyypeillä. Sellaisiin, joissa ohjelman ennakoidaan olevan dynaaminen kokonaisuus, johon tulee tämän tästä lisäyksiä ja muutoksia. Funktioiden selkeät sisään vain parametreissa ulos vain tuloksessa -rajapinnat sekä sivuvaikutusten rajattu käyttö eristävät ohjelman eri osat toisistaan. Silloin yhtä osaa voi muuttaa rauhassa pelkäämättä rikkovansa muita osia. Millaisiin tehtäviin funktionaalinen ohjelmointi sopii erityisen huonosti? Sellaisiin, joissa ohjelman käyttämät resurssit (eli aika ja muistin määrä) ovat tarkkaan rajoitetut. Funktionaaliset ohjelmat eivät välttämättä ole resurssisyöppöjä, mutta niissä ei ohjelmoija yleensä voi koska hänen ei tavallisesti tarvitse ilmaista esimerkiksi milloin hän ei enää tarvitse jotakin muistialuetta. Sellaisiin, joissa ei halutakaan oikeastaan laskea mitään tulosta, vaan halutaankin suorittaa juuri jokin tietty käskysarja. Tällaisia ovat esimerkiksi laiteajurit. Kummassakin tapauksessa kyse on oleellisesti siitä, että funktionaalinen ohjelma ei ohjaa käytössä olevaa tietokonetta, vaan laskee haluttuja vastauksia sitä käyttäen. 6

7 2 Haskell-kielen perusteet Tavoitteena on käsitellä Haskell-kielen perusrakenteet siten, että pääsemme kirjoittamaan omia funktioitamme. Erityisesti tyyppijärjestelmää käsitellään myöhemmin tätä yleiskuvaa tarkemmin. Haskell-lähdekoodissa voi käyttää kahdenlaisia kommentteja: Lyhyitä jotka alkavat -- ja jatkuvat tämän rivin loppuun. Pitkiä jotka kirjoitetaan merkkien {-... -} väliin. Luentoesimerkkejä ei ole kommentoitu, jotta ne mahtuisivat dataprojektorille. Kommentoi silti oma koodisi! 2.1 GHCi-tulkki Kurssin laskuharjoitusten tekemiseen tarvitaan jokin Haskell-kielen toteutus. Yksinkertaisimmin sen saa asentamalla itselleen the Haskell Platformin. Sen voi ladata ilmaiseksi Haskell-kielen kotisivustolta Samalla sivustolla on paljon muutakin Haskell-kieleen liittyvää materiaalia, kuten esimerkiksi sen standardimäärittelyt. Tähän pakkaukseen kuuluu mm. Haskell-kielen laajimmin käytetty toteutus the Glasgow Haskell Compiler (GHC). Erityisesti tulemme käyttämään sen tulkkia ghci ( GHC interactive ). 2.2 Arvot ja tyypit Haskell on vahvasti tyypitetty ohjelmointikieli: Jokaisella arvolla (value) jota Haskell-ohjelma käsittelee on tietty määrätty tyyppinsä (type). Tämä arvon tyyppi pysyy samana koko Haskell-ohjelman suorituksen ajan: Haskell-kielessä ei ole eksplisiittisiä eikä implisiittisiä tyyppimuunnoksia. Haskell on staattisesti tyypitetty: Haskell tarkistaa jo käännösaikana, että ohjelmassa käytetään näitä tyyppejä oikein. Jos ohjelma siis kääntyy virheittä, niin sen suorituksen aikana ei enää ilmaannu tyyppivirheitä. Haskell päättelee tyypit itse: Ohjelmoijan ei ole pakko määritellä funktioidensa tyyppejä, vaan Haskell päättelee käyttöyhteydestä mitä tyyppiä milloinkin käytetään. Se yhdistää vahvan tyypityksen edut ohjelmoinnin vaivattomuuteen. 7

8 Arvo omaa tuottaa Tyyppi sopii omaa omaa Lauseke sisältää hahmo Kuva 1: Käsitteiden suhteet. Haskell-ohjelman suoritus tarkoittaa jonkin lausekkeen (expression) määrittelemän arvon laskemista. Siten jokaisella Haskell-lausekkeellakin on tietty määrätty tyyppinsä: niiden arvojen tyyppi joita se voi tuottaa. Näissä Haskell-ohjelman lausekkeissa voi esiintyä hahmoja (pattern) joilla ohjelma voi tutkia käsittelemiään arvoja ja haarautua sen mukaan millaisia ne ovat. Siten jokaisella hahmollakin on tietty määrätty tyyppinsä: niiden arvojen tyyppi joita sillä voi tutkia. Jatkossa esitellään siksi yhtä aikaa tyyppi itse lausekkeet jotka tuottavat sen tyypin omaavia arvoja hahmot joilla sen tyyppisiä hahmoja voi tutkia. (Kuva 1.) Haskell-kielen suunnittelussa on pyritty siihen, että (myös tyypitkin mutta varsinkin) lausekkeet ja hahmot muistuttaisivat toisiaan: Silloin hahmon voi lukea sellaiset arvot jotka olisivat voineet syntyä näin eli...jotka ovat tämän muotoisia. 8

9 2.3 Funktionmäärittelyt Funktionmäärittelyn perusmuoto fnimi :: Ptyyppi -> Tulostyyppi fnimi pnimi = tuloslauseke esittelee ja määrittelee funktion nimeltään fnimi. Merkintä nimi :: Tyyppi esittelee muuttujan jonka nimi on tämä ja jonka Tyyppi on tuo. Tyyppi Ptyyppi -> Tulostyyppi taas on funktio, jonka sisään menevän parametrin tyyppi on Ptyyppi ulos tulevan arvon tyyppi on Tulostyyppi jotka ovat vuorostaan toisia tyyppeja. Merkintä fnimi pnimi = tuloslauseke määrittelee, että tämän muuttujan nimeltään fnimi arvona on tuo tuloslauseke, jonka sisällä tuo pnimi tarkoittaa tämän määriteltävän funktion parametria. Itse asiassa Haskell sallii myös merkintätavan fnimi = \ pnimi -> tuloslauseke joka ilmoittaa selkeästi, että tässä annetaan nimi fnimi sille nimettömälle funktiolle, jonka parametrin nimi on pnimi ja jonka arvot antaa tuloslauseke. Tässä merkinnässä \ on valittu muistuttamaan kreikkalaista kirjainta λ joka luetaan lambda ja jota Church käytti tähän tarkoitukseen λ-laskennassa. Tämä toinen merkintätapa osoittaa myös että parametri voi puuttua: Silloin esitelläänkin vakio jonka tyyppi voi olla funktiokin. Nämä arvot, jotka tuloslauseke antaa parametrin pnimi eri arvoilla, ovat vuorostaan tyyppiä Tulostyyppi. 9

10 Esitellään ja määritellään nyt kummallakin tavalla se funktio, jonka parametri nimeltään kuka on tyyppiä merkkijono eli String ja tuloksena on toinen merkkijono "Terve, parametrin arvo,!": terve1,terve2 :: String -> String terve1 kuka = "Terve, " ++ kuka ++ "!" terve2 = \ kuka -> "Terve, " ++ kuka ++ "!" Kaksiparametrinen funktio esitellään ja määritellään gnimi :: Ptyyppi 1 -> Ptyyppi 2 -> Tulostyyppi gnimi pnimi 1 pnimi 2 = tuloslauseke Itse asiassa Haskell-kielessä on vain yksiparametrisia funktiota. Tämä gnimi onkin itse asiassa funktio, jonka ainoa parametri on nimeltään Ptyyppi 1 ja jonka arvo on toinen yksiparametrinen funktio, jonka ainoa parametri taas on nimeltään Ptyyppi 2, ja jonka arvot antaa tämä tuloslauseke. Voimme korostaa tätä merkitsemällä vaihtoehtoisesti esimerkiksi gnimi :: Ptyyppi 1 -> (Ptyyppi 2 -> Tulostyyppi) gnimi pnimi 1 = \ pnimi 2 -> tuloslauseke Monessa ohjelmointikielessä ali(eka,toka) tms. tarkoittaa kaksi parametrisen aliohjelman nimeltään ali kutsua, jossa näiden kahden eri parametrin arvot ovat nimiltään eka ja toka. Haskell-kielessä se tarkoittaakin yksi parametrisen funktion nimeltään ali arvoa, jonka ainoan parametrin arvo onkin yksi pari, jonka ensimmäinen osa on nimeltään eka ja jälkimmäinen toka. Tämän funktion esittely on ali :: (Ekantyyppi,Tokantyyppi) -> Tulostyyppi joka on siis erilainen tyyppi kuin esimerkiksi kaksiparametrisen funktion gnimi tyyppi edellä. Haskell-ohjelma koostuu erilaisista määrittelyistä: tällaisista funktioiden määrittelyistä 10

11 tyyppien (ja tyyppisynonyymien ja tyyppiluokkien ja...) määrittelyistä (joihin tutustutaan siis myöhemmin). Tällainen Haskell-ohjelma voidaan ladata Haskell-tulkkiin sen komennolla :load tiedostonimi (ilman loppuliitettään.hs). Sen jälkeen voidaan kirjoittaa Haskell-lausekkeita, joissa käytetään näitä määriteltyjä funktioita, ja tulkki laskee niiden arvot. Nimennästä Haskell-kieli erottelee SUURET ja pienet kirjaimet toisistaan: pienellä alkukirjaimella alkavat kaikki muuttujannimet: muuttujien nimet, funktioiden parametrit, tyyppien parametrit (joihin tutustutaan myöhemmin),... SUURELLA alkukirjaimella alkavat kaikki sellaiset nimet, joille on annettu arvo jo ohjelman käännösaikana ennen suoritusta: konstruktoreiden nimet kuten True, tyyppien nimet kuten String, ns. tyyppiluokkien nimet, ohjelman eri modulien nimet,... Tässä ero osoitetaan kursivoitujen osien alkukirjaimissa. Nnimen syntaksi on pääosin kuten muissakin ohjelmointikielissä: alkaa (pienellä tai suurella) kirjaimella, jonka jälkeen on kirjaimia, numeroita, aliviivoja (underscore) ) tai heittomerkkejä (apostrophe) Haskell-ohjelmoijat haluavat käyttää sellaisia muuttujannimiä kuin x koska matemaatikotkin kirjoittavat x Haskell-kielen omat tyypit Tutustutaan suraavaksi millainen tuo esittelyissä mainittu Tyyppi voi olla. Keskitytään aluksi niihin konkreettisiin tyyppeihin, jotka Haskell itse tarjoaa ohjelmoijalle. Haskell tarjoaa myös varsin rikkaita tapoja joilla ohjelmoija voi käyttää omia tyyppejään geneerisiä tyyppejä mutta niihin tutustumme vasta myöhemmin ja perusteellisemmin. Tutustutaan vain Haskell-standardimäärittelyyn kuuluviin tyyppeihin. Muissa Haskell-kirjastoissa on paljon muitakin tyyppejä niiden lisäksi Atomiset tyypit Atomiset tyypit ovat sellaisia, joiden arvoja ohjelmoija käsittelee vain jakamattomina (olettaen, ettei hän halua työskennellä bitti- ja laitetasolla). Esimerkiksi ASCII-merkit on jakamaton tyyppi, koska ohjelmoija ei (bittitason yläpuolella) käsittele osaa yhdestä merkistä. 11

12 Rakenteiset tyypit ovat sellaisia, joiden arvoja ohjelmoija voi käsitellä ei vain jakamattomina kokonaisuuksina vaan myös pienemmistä osista koostuvina rakenteina, ja ohjelmoija pääsee haluessaan käsiksi myös näihin osiin. Esimerkiksi ASCII-merkkijonot on rakenteinen tyyppi, koska ohjelmoija voi esimerkiksi kysyä mikä on tämän merkkiijonon kolmas merkki? ja käsitellä sitä. Edellä mainitut hahmot ovat Haskell-kielen tapa päästä käsiksi näihin osiin. Tyyppien määrittely on induktiivista: Lähdemme liikkeelle atomisista perustyypeistä. Niiden lisäksi Haskell-kielessä on tyyppikonstruktoreita joilla yksinkertaisemmista tyypeistä voidaan koota uusia mutkikkaampia tyyppejä. Esimerkiksi edellä nähty -> on tällainen tyyppikonstruktori: Sillä voi koota kahdesta yksinkertaisemmasta tyypistä Ptyyppi ja Tulostyyppi uuden mutkikkaamman tyypin funktiot, joiden parametri on Ptyyppi ä ja tulokset Tulostyyppi ä. Myös lausekkeiden ja hahmojen määrittely on samoin induktiivista. Huomaa: Tyyppikonstruktoreilla voi luoda myös atomisia tyyppejä atomisuus tai rakenteisuus on sen tyyppisten arvojen ominaisuus. Erityisesti funktiotyyppikonstruktori -> luo atomisia tyyppejä: ohjelmoija ei voi kysyä anna minulle jokin osa tästä funktiosta. Totuusarvotyyppi Yksinkertaisin atominen tyyppi on totuusarvot. Haskell-kielessä tämän tyypin nimi on Bool. Tällä tyypillä on kaksi arvoa: False eli epätosi, ja True eli tosi. Ne kirjoitetaan Suurella alkukirjaimella, koska ne ovat käännösaikaisia vakioita. Kumpikin näistä arvoista on samalla sellaisenaan lauseke joka tuottaa tämän arvon hahmo joka sopii vain tähän arvoon (muttei siis siihen toiseen). Sama pätee muillakin atomisten tyyppien vakioilla. Merkkityyppi Tyypin yksi merkki nimi on Char. Merkkivakio kirjoitetaan yksinkertaisten lainausmerkkien sisään, siis esimerkiksi: a, 0, jne. 12

13 Kokonaislukutyypit Haskell-standardissa määritellään kaksi etumerkillistä kokonaislukutyyppiä: ohjelmoijan kokonaislukutyypin nimeltään Int matemaatikon kokonaislukutyypin nimeltään Integer. Tyyppi Int on jokin käytetyn tietokoneen tarjoama kokonaislukutyyppi. Se on äärellinen: Esimerkiksi liian suuri positiivinen arvo pyörähtää ympäri hyvin pieneksi negatiiviseksi. Standardi takaa, että ne ovat ainakin 30-bittisiä, eli että ainakin arvoja 2 29,..., 3, 2, 1, ±0, +1, +2, +3,..., voi käsitellä pyörähtämättä ympäri. Sitä käytetään tavallisessa ohjelmoinnissa nopeutensa vuoksi. Tyyppi Integer taas (yrittää) esittää kaikki kokonaisluvut vaikka niitä onkin ääretön määrä...., 3, 2, 1, ±0, +1, +2, +3,... Käytännössä Haskell pystyy laskemaan näillä aidoilla kokonaisluvuilla aina siihen saakka, kunnes ne kasvavat niin suuriksi, etteivät ne enää mahdu koneen keskusmuistiin. Silloin ohjelma pysähtyy ajonaikaiseen "Out of Memory" -virheeseen. Niiden käsittely on huomattavasti hitaampaa kuin tyypin Int joten niitä kannattaa käyttää vain silloin, kun on vältettävä ympäri pyörähtämisen vaarat. Kuten edellä, myös näiden kokonaislukutyyppien vakiot ovat samalla vastaavia lausekkeita ja hahmoja. Kokonaislukuvakion tyyppi mukautuu käyttöyhteyteensä: Esimerkiksi lausekkeessa x + 1 vakion 1 tyypiksi tulee sama kuin muuttujan x. Liukulukutyypit Haskell-kielessä on kaksi liukulukutyyppiä: Float nimeää käytetyn tietokoneen lyhyemmän eli epätarkemman liukulukutyypin Double taas pidemmän eli tarkemman. Sitä käytetään, ellei tyypinmäärittelyillä muuta sanota. Kuten edellä, myös näiden liukulukutyyppien vakiot ovat samalla vastaavia lausekkeita ja hahmoja. Liukulukuvakioissa ei ole omaa notaatioita erottamaan näitä tyyppejä toisistaan, vaan se tehdään tyypinmäärittelyillä. Esimerkiksi 13

14 pi :: Float pi = antaa tälle vakiolle pi tyypin Float, kun taas ilman tyyppimäärittelyä se olisikin saanut oletustyypin eli Double Funktiotyypit Olemme jo tavanneet sen, miten funktiotyyppejä merkitään: ParametrinTyyppi -> TulosTyyppi Näin siis ilmaistaan yksiparametrisen funktion tyyppi. Moniparametrisen funktion tyyppi ilmaistaan PT 1 -> PT 2 -> PT 3 -> -> PT k -> TulosTyyppi jossa PT i on järjestyksessä i. parametrin tyyppi. Funktiotyyppien tyyppikonstruktori -> assosioi oikealle, joten tässä on vastaavasti jätetty sulut merkitsemättä näkyviin. Jos ne merkitään näkyviin, niin saadaan PT 1 -> (PT 2 -> (PT 3 -> ( (PT k -> TulosTyyppi)))) eli funktio, jonka ainoan parametrin tyyppi on PT 1 ja jonka tuloksen tyyppi on (funktio, jonka ainoan parametrin tyyppi on PT 2 ja jonka tuloksen tyyppi on (...ja jonka tuloksen tyyppi on TuloksenTyyppi)). Tämä tapa palauttaa moniparametriset funktiot yksiparametrisiksi tunnetaan nimellä Currying. Suomen kielessä ei ole vakiintunutta vastinetta. Sellaisena voisimme käyttää kuritusta. Tavan vakiintunut nimitys kunnioittaa yhdysvaltalaista loogikkoa Haskell B. Currya. Myös ohjelmointikielemme on nimetty hänen mukaansa. Tosin alun perin kielen nimeksi suunniteltiin Currya... Tapaa olivat tosin käyttäneet jo häntä varhaisemmat loogikot Moses Schönfinkel ja F. L. Gottlob Frege. Haskell-kielessä funktiot on siis tapana määritellä kuritettuina, kun taas useimmissa muissa kielissä ne määritellään kuritta eli tyypiltään (PT 1,PT 2,PT 3,...,PT k ) -> TuloksenTyyppi 14

15 jossa Haskell-kielen näkökulmasta ainoana parametrina onkin siis k-osainen monikko. Yleensä kahta samantyyppistä arvoa voi verrata toisiinsa ja selvittää ovatko ne samat tai onko toine suurempi toista: Esimerkiksi merkeillä on aakkosjärjestys, ja siten myös merkkijonoillakin. Funktiotyyppisiä arvoja ei kuitenkaan voi verrata toisiinsa: Testi onko funktio f sama kuin funktio g? olisi algoritmisesti ratkeamatonta (Ricen lauseen nojalla). Vastaavasti funktiotyyppisiä arvoja ei myöskään voi esimerkiksi lukea tiedostosta (joka on eri asia kuin ladata ja kääntää lähdekooditiedosto suorituskelpoiseksi) tai tulostaa näytölle suorituskelpoisessa muodossaan (joka on eri asia kuin katsella lähdekooditiedostoja). Oikeastaan niitä voi vain luoda määrittelyillä (nimetyt funktiot) tai lambda-lausekkeilla (nimettömät) välittää argumentteina sisään toisiin funktioihin ja arvoina ulos niistä kutsua annetuilla argumenteilla Monikkotyypit Sellainen (tyyppi 1,tyyppi 2,tyyppi 3,...,tyyppi k ) jossa jokainen tyyppi i on jokin yksinkertaisempi tyyppi on monikkotyyppi. Tämän tyypin arvossa on k eri nimetöntä kenttää kirjoitusjärjestyksessä: 1. kentässä on arvo, jonka tyyppi on tyyppi 1 2. kentässä on arvo, jonka tyyppi on tyyppi 2 3. kentässä on arvo, jonka tyyppi on tyyppi 3. ja viimeisessä eli k. kentässä on arvo, jonka tyyppi on tyyppi k. Se on ensimmäinen rakenteinen tyyppimme: Sen arvoa voi sekä käsitellä kokonaisena että tutkia sen kenttiä. Esimerkiksi tyypin (Bool,Integer) arvot ovat lueteltuina 15

16 . (False,-2), (False,-1), (False,-0), (False,1), (False,2),. (True,-2), (True,-1), (True,-0), (True,1), (True,2),. eli jokainen (eli kumpikin) totuusarvo jokaisen kokonaisluvun kanssa pareittain. Monikkotyypin arvoja voi puolestaan tuottaa lausekkeilla muotoa (lauseke 1,lauseke 2,lauseke 3,...,lauseke k ) jossa jälleen kirjoitusjärjestyksessä kunkin kentän i sisältö saadaan laskemalla vastaava lauseke i. Siten kyseisen lausekkeenkin tyypin pitää myös olla vastaavaa tyyppiä tyyppi i. Näin tuotettuja arvoja voi puolestaan sovittaa hahmoihin muotoa (hahmo 1,hahmo 2,hahmo 3,...,hahmo k ) jossa jälleen kirjoitusjärjestyksessä kunkin kentän i sisältöä sovitetaan sitä vastaavaan hahmoon hahmo i. Siten kyseisen hahmonkin tyypin pitää myös olla vastaavaa tyyppiä tyyppi i. Haskell-ohjelmoinnissa monikkotyyppiä käytetään funktion tulostyyppinä silloin, kun se tuottaa sellaisen arvon, jossa on monta eri osaa, ja näiden osien välillä on jokin sellainen suhde, jonka tämä funktio muodostaa sille annetuista parametreistaan. Esimerkiksi standardikirjastoon kuuluu sellainenkin kokonaislukujen jakolasku nimeltään quotrem joka palauttaa vastauksenaan parin eli 2-kenttäisen monikon, jossa jakolaskun kokonaisosa on ensimmäisenä ja jakojäännös jälkimmäisenä kenttänä eli osana. Siis jakolaskun quotrem m n tuloksena on se kokonaislukupari (p,q) jolla m = n p + q. Erityisesti on olemassa tyhjä monikkotyyppi,jossa on k = 0 kenttää: 16

17 Tämän tyypin nimi on (). Siihen kuuluu yksi ainoa arvo. Sen tuottaa lauseke (). Tämä arvo sopii hahmoon () Listatyypit Monikkotyyppiä käytetään siis silloin, kun funktion tuottama tulos koostuu monesta eri osasta jotka saavat olla keskenään eri tyyppisiä mutta joiden lukumäärä k tiedetään jo ohjelmointivaiheessa. Toinen hyvin monikäyttöinen rakenteinen tyyppi on lista, joka myöskin koostuu monesta eri osasta eli alkiosta jotka kaikki ovat keskenään samaa tyyppiä mutta joiden lukumäärä eli listan pituus voi vaihdella. Tyyppi [τ] on ne listat, joiden alkiot ovat tyyppiä τ. Tämän tyypin peruslausekkeita on kahdenlaisia: [] on vakio, joka tarkoittaa tyhjää listaa eli sitä listaa jossa ei ole yhtään alkiota. eka:muut tuottaa sellaisen epätyhjän listan, jonka ensimmäinen alkio saadaan laskemalla lausekkeen eka arvo, ja jonka loppulista (eli toinen, kolmas, neljäs,... alkio) saadaan laskemalla lausekkeen muut arvo. Siten lausekkeen eka pitää olla alkiotyyppiä τ ja lausekkeen muut tyyppiä[τ]. Tämä vastaa suoraan tyypin [τ] arvojen induktiivista määritelmää: Perustapauksessa tyhjä lista [] on tätä tyyppiä. Induktiivisessa tapauksessa eka:muut on tätä tyyppiä, jos tämä eka alkio on tyyppiä τ ja nämä muut alkiot tätä tyyppiä. Siten myös toinen, kolmas, neljäs,... eli jokainen alkio on tyyppiä τ. Vastaavasti tämän tyypin perushahmoja on myöskin kahdenlaisia: [] on hahmo, joka sopii vain tyhjään listaan. ekahahmo:muuthahmo on hahmo, joka sopii vain sellaisiin epätyhjiin listoihin, joiden ensimmäinen alkio sopii ekahahmoon ja jonka loppulista sopii muuthahmoon. Siten ekahahmon pitää olla tyyppiä τ ja muuthahmon tyyppiä [τ]. Syntaktista sokeria Esimerkiksi kokonaislukulista, jonka alkiot ovat 1, 3, 5 ja 7, voidaan tuottaa lausekkeella 1:(3:(5:(7:[]))). jossa on suluilla osoitettu laskujärjestys. 17

18 Operaattorin : (jota kutsutaan nimellä cons Lisp-perinteiden vuoksi) assosiatiivisuus on onneksi määritelty siten, että nämä sulut voi jättää poiskin: 1:3:5:7:[]. Lisäksi tällaista kokonaista listaa voi merkitä siistimmin viemällä sen alkiota hakasulkujen sisään pilkuin eroteltuina: [1,3,5,7]. Samat merkinnät käyvät myös listahahmoille: Listahahmo [hahmo 1,hahmo 2,hahmo 3 ] sopii kaikkiin sellaisiin listoihin, joissa on tasan kolme alkiota, joista 1. ensimmäinen sopii hahmoon hahmo 1 2. keskimmäinen hahmoon hahmo 2, ja 3. viimeinen hahmoon hahmo 3 joiden kaikkien tyyppinä on alkiotyyppi τ. Listahahmo hahmo 1 :hahmo 2 :hahmo 3 Merkkijonot taas sopii kaikkiin sellaisiin listoihin, joissa on ainakin kaksi alkiota, joista 1. ensimmäinen sopii hahmoon hahmo 1 2. toinen hahmoon hahmo 2, ja 3. kaikki loput hahmoon hahmo 3. joista ensimmäisen ja toisen tyyppinä on alkiotyyppi τ mutta kolmannen tyyppinä onkin itse listatyyppi [τ]. Haskell-kielessä merkkijonotyyppi String onkin itse asiassa tyyppi [Char] eli lista merkkejä. Edellä kuvattu syntaktinen sokeri on viety niissä vieläkin pidemmälle: Merkkijonon, joka koostuu merkeistä H, e, l, l ja o voi kirjoittaa paitsi [ H, e, l, l, o ] myös vielä tutummassa muodossa "Hello" jossa siis hakasulkeet [...] on korvattu kaksinkertaisilla lainausmerkeillä "..." ja niiden väliin on jätetty pelkät merkkivakiot sellaisinaan. Samalla notaatiolla tyhjä merkkijonokin on siis tutusti "". 18

19 2.4.5 Tyyppinimet Merkkijonotyyppi String on siis pelkkä yksinkertaisempi nimi mutkikkaammalle tyypille [Char]. Haskell-kielessä voi antaa tyypeille tällaisia lyhennenimiä seuraavalla määrittelyllä: type Lyhenne = tyyppi Siis Haskell-kirjasto sisältää esimerkiksi seuraavan määrittelyn: type String = [Char] Tällainen type-määrittely ei siis luo uutta tyyppiä, vaan antaa pelkästään uuden vaihtoehtoisen nimen, jolla myös voi kutsua tätä tyyppiä. 2.5 Lausekkeet Tutustutaan seuraavaksi Haskell-kielen lausekkeisiin. Tavoitteena on päästä kirjoittamaan mahdollisimman pian omia Haskell-funktioitamme, joilla sitten pääsemme tutustumaan funktionaalisen ohjelmoinnin periaatteisiin Funktionkutsulauseke Nimettyä funktiota voidaan kutsua lausekkeella muotoa nimi arg 1 arg 2 arg 3... arg k jossa nimi on sen funktion nimi, jota kutsutaan arg i on lauseke, joka antaa arvon sen i. parametrille. Siis kutsussa ei ole mitään ylimääräisiä välimerkkejä, vaan nimi ja arg umenttilausekkeet kirjoitetaan suoraan peräkkäin välilyönneillä erotetuina. Jos esimerkiksi halutaan laskea osamäärä ja jakojäännös, kun luku jaetaan luvulla 789, niin edellä mainittua kirjastofunktiota kusutaan suoraan kirjoittamalla quotrem Koska Haskell-funktiot ovat kuritettuja, niin niitä voidaan kutsua myös osittain eli antamalla niille vain ensimmäiset muttei kaikkia parametrejä. Siis sallitaan, että k tämännimisen funktion parametrien lukumäärä. 19

20 Esimerkiksi kutsu quotrem on sallittu, ja sen intuitio on se yksiparametrinen funktio, joka saadaan kaksiparametrisesta funktiosta quotrem kiinnittämällä sen ensimmäisen parametrin arvoksi Toisin sanoen, arvona on funktio \ y -> quotrem y jossa on käytetty edellä mainittua nimettömän funktion luontilauseketta (eli sitä lambdaa ). Tyyppien tasolla tapahtuu tällöin seuraavaa: Kutsuttavan funktion tyyppi on quotrem :: Integer -> Integer -> (Integer,Integer) (Sen tyyppi on oikeasti tätä jonkin verran yleisempi eli a -> a ->(a,a) jossa a on mikä tahansa kokonaislukutyyppi, mutta palataan siihen myöhemmin ns. monimuotoisten tyyppien yhteydessä.) Koska vakion tyyppi on Integer (eli se on todellakin sallittu ensimmäisen parametrin arvoksi) niin lausekkeen tyypiksi tulee quotrem :: Integer -> (Integer,Integer) joka todellakin on tämän tuloksena saadun funktion tyyppi: Jos saan vielä kokonaisluvun y, niin palautan arvonani kokonaislukuparin quotrem y. Haskell-ohjelmoinnissa käytetäänkin usein sellaista tapaa luoda funktio, jossa annetaan arvot sen ensimmäisille parametreille, ja muut jätetään merkitsemättä. Esimerkiksi: omani :: Integer -> (Integer,Integer) omani = quotrem Myös kutsuttavan funktion nimi voikin olla mikä tahansa mutkikkaampikin lauseke, kunhan sen tyyppinä on oikeanlainen funktiotyyppi. Erityisesti se voi olla jonkin parametrin nimi silloin kun kirjoitetaan sellaisia funktioita, jotka saavat muita funktioita parametreinaan ja kutsuvat niitä. Esimerkiksi kirjastofunktion 20

21 comparing f x y = compare (f x) (f y) ensimmäisenä parametrina on jokin funktio nimeltään f muina parametreinä on kaksi alkiota nimiltään x ja y tuloksena on arvojen f x ja f y verailun tulos kirjastofunktiosta compare. Silloin esimerkiksi funktio comparing tolower vertailee kahta merkkiä x ja y muunnettuaan ne ensin isoista pieniksi kirjaimiksi kirjastofunktiolla tolower Hahmonsovituslauseke Lausekkeet ja hahmot kohtaavat (vihdoinkin!) hahmonsovituslausekkeessa jonka perusmuoto on: case lauseke of hahmo 1 -> tuloslauseke 1 hahmo 2 -> tuloslauseke 2 hahmo 3 -> tuloslauseke 3. hahmo m -> tuloslauseke m Sen intuitio on: 1. Sovita tämän lausekkeen lauseke arvoa a ensimmäiseen hahmoon hahmo 1. Jos se sopii, tämän case-lausekkeen arvo on se, mitä vastaava tuloslauseke 1 antaa. 2. Muuten siirry kokeilemaan sopisiko tämä arvo a seuraavan haaran hahmoon hahmo 2, ja niin edelleen......kunnes ensimmäinen sopiva haara löytyy. Jos mikään näistä haaroista ei sovikaan tähän arvoon a, niin silloin koko Haskellohjelman suoritus päättyy suoritusaikaiseen virheeseen: Tämän case-lausekkeen arvoa ei olekaan määritelty tällä arvolla a. Tämän lausekkeen lauseke ja kaikkien näiden hahmojen hahmo i pitää olla keskenään samaa tyyppiä sitä tyyppiä, jota tutkittava arvo a on. Samoin kaikkien näiden lausekkeiden tuloslauseke j pitää olla keskenään samaa tyyppiä sitä tyyppiä, joka tämän case-lausekkeen antamalla arvolla on. 21

22 Yksinkertaisin esimerkki on Haskell-kielen if-lause kahdella eri tavalla: if ehto then niin else noin case ehto of True -> niin False -> noin Molemmissahan ensin tutkitaan onko ehtolauseke totta vai epätotta ja sitten haaraudutaan sen mukaan. Otetaan seuraavaksi esimerkiksemme tunnettu Ackermann(-Péter)in funktio: n + 1 jos m = 0 ack(m, n) = ack(m 1, 1) jos m > 0 mutta n = 0 ack(m 1, ack(m, n 1)) jos m > 0 ja n > 0. Se on suunniteltu siten, että sen arvot kasvavat hyvin nopeasti: Esimerkiksi jo ack(4, 2) on numeroinen luku! Lisäksi näiden arvojen laskeminen tapahtuu hyvin hitaasti: Joka askeleessa toinen parametreista pienenee vain yhdellä. Toinen taas ei pienene, vaan saattaa kasvaa hyvinkin paljon. Hahmossa voi käyttää muuttujannimiä (jotka siis kirjoitetaan pienellä alkukirjaimella). Sellainen tarkoittaa annan tämän nimen tälle osalle sitä arvoa jota tähän hahmoon nyt sovitetaan. Sitten tähän osaan voi viitata tällä nimellä tässä haarassa (mutta ei muissa haaroissa). Näitä nimiä käyttäen funktio ack voidaan ilmaista Haskell-kielellä seuraavasti: ack1 :: (Integer,Integer) -> Integer ack1 x = case x of (0,n) -> n+1 (m,0) -> ack1 (m-1,1) (m,n) -> ack1 (m-1,ack1 (m,n-1)) Esimerkiksi sen ensimmäinen hahmo 1. testaa, että parametrin x arvon (joka on funktion tyypin perusteella kokonaislukupari) ensimmäinen osa on 0 2. antaa sen jälkimmäisen osan nimeksi n ja tätä nimeä käytetään sitten sen tuloslausekkeessa n+1. Jos emme nyt ole lainkaan kiinnostuneita jostakin osasta, niin voimme antaa sille nimeksi pelkän alaviivan jonka voi siis lukea tällä kohdalla ei ole mitään kiinnostavaa. Tämä ack1 on esimerkki hyvin yleisestä ilmiöstä Haskell-funktioissa: Se haarautuu heti eri tapauksiin saamansa parametriarvon x perusteella. 22

23 Haskell salliikin tällaisen haarautumisen kirjoittamisen suoraan: mutkikkaasti suoraan sanoen f x = case x of h 1 -> t 1 h 2 -> t 2 h 3 -> t 3. h m -> t m f h 1 = t 1 f h 2 = t 2 f h 3 = t 3. f h m = t m Silloin haara i voidaan lukea suoraan jos funktion f parametri sopii tähän hahmoon h i niin silloin sen arvo on tuo t i. Siten ack1 voidaan kirjoittaa suoremminkin: ack2 :: (Integer,Integer) -> Integer ack2 (0,n) = n+1 ack2 (m,0) = ack2 (m-1,1) ack2 (m,n) = ack2 (m-1,ack2 (m,n-1)) Sama kirjoitustapa käy myös monen parametrin funktioihin: ack3 :: Integer -> Integer -> Integer ack3 0 n = n+1 ack3 m 0 = ack3 (m-1) 1 ack3 m n = ack3 (m-1) (ack3 m (n-1)) Nyt jokaisessa haarassa on kaksi hahmoa, yksi kummallekin parametrille. Esimerkiksi toinen haara antaa ensimmäiselle parametrille nimen m ja testaa että jälkimmäinen on 0. Otetaan sitten esimerkki listojen käsittelystä hahmoilla. Kirjoitetaan funktio merge joka saa syötteineen kaksi järjestettyä kokonaislukulistaa, ja palauttaa tuloksenaan yhden listan, johon niiden alkiot on lomitettu siten, että sekin on järjestyksessä. Siis esimerkiksi merge [1,2,4,8] [2,3,5] antaa tuloksena[1,2,2,3,4,5,8]. Listojen käsittelyssä kannattaa aloittaa miettimällä Mikä on oikea vastaus tyhjälle listalle? merge :: [Int] -> [Int] -> [Int] merge [] yl =? merge xl [] =? merge (x:xs) (y:ys) =? Tässä siis 1. haarassa ensimmäinen parametri xl ( x-llista ) on tyhjä 23

24 2. haarassa toinen parametri yl 3. haarassa ensimmäisellä parametrilla onkin ensimmäinen alkio nimeltään x ja loppulista nimeltään xs ( x:t ), ja toisella samoin y ja ys. Jos funktion merge yksi parametri on tyhjä, niin silloin sen tulos on se toinen parametri (olipa se tyhjä tai ei): merge :: [Int] -> [Int] -> [Int] merge [] yl = yl merge xl [] = xl merge (x:xs) (y:ys) =? Tarkastellaan sitten sitä jäljellä olevaa kolmatta haaraa, jossa kumpikaan parametri ei ole tyhjä. Silloin tuloksen pitää alkaa pienemmällä niiden ensimmäisistä alkioista: merge :: [Int] -> [Int] -> [Int] merge [] yl = yl merge xl [] = xl merge (x:xs) (y:ys) = if x > y then y :? else x :? Nyt then-haarassa alkio y on siirtynyt loppulistan ys edestä koko tuloksen alkuun. Loput tuloksesta saadaan sitten lomittamalla xl ja ys; tämä voidaan tehdä rekursiivisesti, koska rekursiokutsussa on nyt yhtä alkiota pienemmät parametriarvot kuin ennen, joten rekursio pysähtyy. Vastaavasti myös else-haarassa: merge :: [Int] -> [Int] -> [Int] merge [] yl = yl merge xl [] = xl merge (x:xs) (y:ys) = if x > y then y : merge (x:xs) ys else x : merge xs (y:ys) Haskell sallii myös ehtojen liittämiseen case-lausekkeen hahmoon seuraavalla syntaksilla: hahmo ehto 1 = tulos 1 ehto 2 = tulos 2 ehto 3 = tulos 3. ehto q = tulos q Ideana on, että jos tutkittava arvo sopii tähän hahmoon, niin sitten aletaan tarkastella sen näitä ehtoja. 24

25 1. Jos ehto 1 on tosi, niin saadaan vastaava tulos 1 2. muuten jos ehto 2 on tosi, niin saadaan vastaava tulos 2 3. muuten jos ehto 3 on tosi, niin saadaan vastaava tulos 3. muuten jos ehto q on tosi, niin saadaan vastaava tulos q muuten jos mikään niistä ei ole tosi, niin sitten siirrytään sovittamaan tätä arvoa seuraavaan hahmo on tätä viimeistä siirtymää olisi hankalaa tehdä if-lausekkeilla. Tällainen ehto j on mielivaltainen lauseke totuusarvotyyppiä Bool. Siinä voi käyttää kaikkia niitä nimiä, jotka tämä hahmo antaa tutkittavan arvon eri osille. Esimerkkimme voidaan kirjoittaa näitä ehtoja käyttäen: merge :: [Int] -> [Int] -> [Int] merge [] yl = yl merge xl [] = xl merge (x:xs) (y:ys) x > y = y : merge (x:xs) ys otherwise = x : merge xs (y:ys) Standardikirjasto määrittelee vakion otherwise :: Bool otherwise = True jolla voi ilmaista siististi sen, että viimeistään hahmon viimeinen ehto pätee. Lisäksi hahmoihin kuuluu myös muoto nimi@hahmo joka samalla kertaa sekä nimeää tämän osan tarkasteltavasta arvosta tällä nimellä että sovittaa sitä tähän hahmoon joka voi vuorostaan nimetä sen osia. Funktion merge kolmannessa haarassa voidaan käyttää sitä samalla kertaa sekä nimeämään koko parametrin xl että sen osat x ja xs (kuten myös yl, y ja ys vastaavasti): merge :: [Int] -> [Int] -> [Int] merge [] yl = yl merge xl [] = xl merge xl@(x:xs) yl@(y:ys) x > y = y : merge xl ys otherwise = x : merge xs yl 25

26 2.5.3 Lohkorakenne ja sisennys Haskell-kielessä on lohkorakenne useimpien muiden nykyisten ohjelmointikielten tapaan. Lohko merkitään aalkosulkeilla{...} joiden sisällä eri osat erotellaan puolipistein ; toisistaan. Esimerkiksi case-lausekkeen lohkorakenne on tarkkaan ottaen case lauseke of { hahmo 1 -> tuloslauseke 1 ; hahmo 2 -> tuloslauseke 2 ; hahmo 3 -> tuloslauseke 3. ; hahmo m -> tuloslauseke m } Haskell-kielessä lohkorakenteen voi ilmaista myös ilman näitä aaltosulkeita ja puolipisteitä sisentämällä ohjelmakoodinsa sopivasti. Nämä sisennyssäännöt (layout rules) ovat seuraavat: 1. Lausekkeen muut osat sisennetään sen alkukohdan oikealle puolelle. Esimerkiksi case-lausekkeen sisältämät haarat sisennetään case-sanan alkukohdan oikealle puolelle. Samoin jokaisen haaran tuloslauseke sisennetään oman hahmo nsa oikealle puolelle. 2. Samalla tasolla olevat lausekkeen osat sisennetään alkamaan keskenään samasta kohdasta. Esimerkiksi case-lausekkeen kaikki haarat eli niiden hahmot sisennetään alkamaan keskenään samasta kohdasta. Muutenhan sisennyssäännön 1 mukaan tulkittaisiinkin, että jokin niistä haara olisikin toisen haaran osa eikä sen kanssa rinnakkain kuten oli tarkoitus. Sisennyssääntöjen etuna on, että ohjelmakoodi sisältää enemmän itse asiaa ja vähemmän välimerkkejä. Siksi Haskell-ohjelmissa käytetäänkin yleensä sisennystä aaltosulkujen ja puolipisteiden sijasta, niin näissäkin luennoissa. Haittana taas on, että ohjelman merkitys muuttuu, kun siitä poistetaan tai siihen lisätään välilyöntejä tai sarkainmerkkejä. Siksi Haskell-ohjelmia kannattaa kirjoittaa sellaisella editorilla, joka tuntee Haskellsyntaksin ja nämä sisennyssäännöt. (Luennoija itse käyttää XEmacs-editoria ja sen Haskell-moodia.) 26

27 2.5.4 Paikalliset määrittelyt Ohjelmoinnissa on usein tarpeen lausua paikallisia määrittelyjä, jotka näkyvät vain jossakin osassa ohjelmaa, mutta eivät muualla. Haskell-kielessä sellainen lauseke on let määrittely 1 määrittely 2 määrittely 3. määrittely m in runkolauseke jossa nämä funktion- ja vakionmäärittely t näkyvät vain runkolausekke ssa ja toisissaan joten rekursio on sallittu. Lisäksi näissä määrittely issä ja tässä runkolausekke ssa näkyvät kaikki ne muut nimet, jotka on määritelty niissä lausekkeissa ja hahmoissa, joiden sisällä tämä let on eli muistakin ohjelmointikielistä tutut näkyvyyssäännöt. Kirjoitetaan esimerkiksi silmukka, joka laskee annetun liukulukulistan lukujen summan: summa :: [Double] -> Double summa = let silmukka :: Double -> [Double] -> Double silmukka a [] = a silmukka a (x:xs) = silmukka (a+x) xs in silmukka 0 Tässä apufunktio silmukka on paikallinen eikä näy varsinaisen funktion summa ulkopuolelle. Tämä on samalla esimerkki argumenttien pois jättämisestä: apufunktiolla silmukka on kaksi parametria mutta in-osassa sille annetaankin vain ensimmäinen parametri joten in-osan tyyppi on sama kuin koko funktion summa, kuten pitääkin. Siten summattavaa syötelistaa ei kirjoitettukaan omana parametrinaan. Nämä let-määrittelyt kirjoitetaan ennen niiden käyttöä in-osassa. Haskell-kielessä voi kirjoittaa määrittelyt vaihtoehtoisesti myös käytön jälkeen: runkolauseke where määrittely 1 määrittely 2 27

28 määrittely 3. määrittely m Se muistuttaa matemaattisissa teksteissä usein käytettyä kirjoitustapaa tarkastellaan runkolauseke tta jossa.... Tämä where-jälkimäärittelysyntaksi on erityisen hyödyllinen case-lauseen sellaisessa haarassa, jossa yhteen hahmoon liittyy monia eri ehtoja: hahmo ehto 1 = tulos 1 ehto 2 = tulos 2 ehto 3 = tulos 3. ehto q = tulos q where määrittely 1 määrittely 2 määrittely 3. määrittely m Nämä määrittely t voivat nimittäin käyttää hahmo n antamia nimiä, ja niissä määriteltyjä nimiä voi puolestaan käyttää näitä ehtoja kirjoittaessaan. Tämä olisi vaikeaa let-lausekkeella, erityisesti kun kaikkien ehto jen ollessa epätosia pitää siirtyä seuraavaan hahmoon. Tähän mennessä olemme käsitelleet vain sellaisia määrittelyjä, joissa on annettu jokin nimi jollekin funktiolle. On olemassa myös toinenkin määrittelytapa: hahmo = lauseke jossa tuon lausekkeen arvo sovitetaan tähän hahmoon. Tämä toinen tapa on erityisen hyödyllinen silloin, kun lauseke tuottaa arvonaan jonkin monikon, koska silloin hahmolla voi nimetä monikon kentät. Esimerkiksi lausekkeen let q, r :: Integer (q,r) = quotrem x y in... in-osassa voidaan käyttää nimeä q Integereiden x ja y osamäärästä (quotient), ja nimeä r niiden jakojäännöksestä (remainder). 28

29 x y tarkoittaa == x on sama kuin y /= x ei ole sama kuin y < x on pienempi kuin y > x on pienempi kuin y <= x on pienempi tai yhtäsuuri kuin y >= x on suurempi tai yhtäsuuri kuin y + lukujen yhteenlasku, - vähennuslasku, * kertolasku, / jakolasku ja ^ potenssiinkorotus && x ja y x tai y ++ listojen (ja siis myös merkkijonojen) x ja y yhdistäminen peräkkäin. yhdistetty funktio x y Taulukko 1: Haskell-kielen valmiiksi määriteltyjä operaattoreita. 2.6 Operaattoreista Haskell-kielessä operaattori on kaksiparametrisen funktion nimi, joka kirjoitetaankin argumenttiensa väliin eikä eteen. Siis sen kutsu kirjoitetaankin tuttuun tapaan x y eikä x y. Kielessä on valmiiksi määriteltyinä monia tuttuja operaattoreita joista osa on taulukossa 1. Kaikki valmiiksi määritellyt operaattorit on esitetty Haskell-standardin taulukossa 4.1. Kun tällaiselle operaattorille ei annetakaan molempia sen haluamia parametreja (eli hyödynnetään kuritusta) niin puhutaan viipaleista (section): (x ) on se funktio, jossa on annettu ensimmäinen argumentti x muttei toista argumenttia. Esimerkiksi (1.0 /) on liukulukujen funktio käänteisluku : (1.0 /) 4.0 on 0.25 jne. ( y) taas on se funktio, jossa toinen argumentti y on annettu muttei ensimmäistä. Esimerkiksi (/ 2.0) on liukulukujen funktio puolita : (/ 2.0) 8.0 on 4.0 jne. ( ) taas on se funktio, jossa kumpaakaan argumenttia ei ole annettu eli tämän operaattorin nimi silloin kun sitä tarvitaan. Esimerkiksi (<=) on testin pienempi tai yhtäsuuri kuin nimi. Syntaktisesti tällaiset operaattorit ovat funktionnimiä, jotka koostuvatkin pelkästään erikoismerkeistä. 29

30 Haskell-ohjelmoija voi määritellä omia operaattoreitaan yksinkertaisesti määrittelemällä itse kaksiparametrisia funktioita, joilla on sellainen nimi. Tällainen määritelmä voisi alkaa esimerkiksi: (+++) :: String -> Bool -> Int x +++ y =... Tässä määriteltäisiin siis operaattoria nimeltä (+++) jonka vasen operandi x on merkkijono, oikea operandi y on totuusarvo ja tulos on kokonaisluku. Siten esimerkiksi"hei" +++ True olisi sen luvallinen kutsu, ja se tuottaisi arvonaan jonkin kokonaisluvun. Se voitaisiin kirjoittaa myös (+++) "Hei" True. Kääntäen, Haskell-ohjelmoija voi käyttää myös tavallisia funktionnimiä operaattoreina kirjoittamalla ne takaperoisten lainausmerkkien... sisään. Standardikirjastossa on esimerkiksi kaksiparametrinen funktio nimeltään mod joka palauttaa jakojäännöksen, kun sen ensimmäinen argumentti jaetaan toisella (jotka molemmat ovat kokonaislukuja). Se on luontevaa kirjoittaa argumenttiensa väliin, siis esimerkiksi mod 789 samaa tarkoittavan normaalin notaation mod sijaan. Operaattoreihin liittyy usein myös presedenssi joka kertoo miten eri operaattoreiden esiintymät suhtautuvat toisiinsa. Onko lausekkeessa x y z näkymättömät sulut (x y) z jolloin sitoo vahvemmin kuin, vaiko x (y z) jolloin heikommin? Esimerkiksi matematiikassa kertolasku sitoo vahvemmin kuin yhteenlasku. assosiatiivisuus joka kertoo miten saman operaattorin eri esiintymät suhtautuvat toisiinsa. Onko lausekkeessa x y z näkymättömät sulut (x y) z jolloin on vasemmalle assosiatiivinen, vaiko x (y z) jolloin oikealle? 30

JFO: Johdatus funktionaaliseen ohjelmointiin

JFO: Johdatus funktionaaliseen ohjelmointiin JFO: Johdatus funktionaaliseen ohjelmointiin Matti Nykänen Tietojenkäsittelytieteen laitos, Itä-Suomen yliopisto matti.nykanen@uef.fi Lukuvuosi 2010-11, IV periodi Sisältö 1 Johdanto 1 1.1 Historiaa.....................................

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

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

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

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, Vakio Tiedon merkkipohjainen tulostaminen Ohjelmointi (ict1tx006) Tunnus (5.3) Javan tunnus Java-kirjain Java-numero

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

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

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

ELM GROUP 04. Teemu Laakso Henrik Talarmo

ELM GROUP 04. Teemu Laakso Henrik Talarmo ELM GROUP 04 Teemu Laakso Henrik Talarmo 23. marraskuuta 2017 Sisältö 1 Johdanto 1 2 Ominaisuuksia 2 2.1 Muuttujat ja tietorakenteet...................... 2 2.2 Funktiot................................

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

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

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

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python Ohjelmoinnin perusteet Y Python T-106.1208 20.1.2010 T-106.1208 Ohjelmoinnin perusteet Y 20.1.2010 1 / 40 Arvon pyytäminen käyttäjältä Käyttäjän antaman arvon voi lukea raw_input-käskyllä. Käskyn sulkujen

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

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

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

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

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

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

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

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) Toistaiseksi helppoa Miksi vain puolet pisteistä? Vaikeinta oli ohjelmointiympäristön asennus ja käyttö Vaikeaa eroavuudet Pythonin ja C:n

Lisätiedot

Python-ohjelmointi Harjoitus 2

Python-ohjelmointi Harjoitus 2 Python-ohjelmointi Harjoitus 2 TAVOITTEET Kerrataan tulostuskomento ja lukumuotoisen muuttujan muuttaminen merkkijonoksi. Opitaan jakojäännös eli modulus, vertailuoperaattorit, ehtorakenne jos, input-komento

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

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

TIES542 kevät 2009 Tyyppijärjestelmän laajennoksia

TIES542 kevät 2009 Tyyppijärjestelmän laajennoksia TIES542 kevät 2009 Tyyppijärjestelmän laajennoksia Antti-Juhani Kaijanaho 16. helmikuuta 2009 Tyypitetyt ohjelmointikielet sisältävät paljon muitakin konstruktioita kuin yksinkertaisesti tyypitetyn lambda-kielen,

Lisätiedot

fix e e (fix e). fix = λf.(λx.f (x x)) (λx.f (x x)) (9)

fix e e (fix e). fix = λf.(λx.f (x x)) (λx.f (x x)) (9) Käytännön funktionaaliset ohjelmointikielet esittävät rekursion tällä tavalla. Teorian näkökulmasta olisi kuitenkin eleganttia, jos oikean puolen Termissä ei tarvittaisi vasemman puolen Muuttujannimeä,

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

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

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

Ohjelmointiharjoituksia Arduino-ympäristössä

Ohjelmointiharjoituksia Arduino-ympäristössä Ohjelmointiharjoituksia Arduino-ympäristössä Yleistä Arduino-sovelluksen rakenne Syntaksi ja käytännöt Esimerkki ohjelman rakenteesta Muuttujat ja tietotyypit Tietotyypit Esimerkkejä tietotyypeistä Ehtolauseet

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

Zeon PDF Driver Trial

Zeon PDF Driver Trial Matlab-harjoitus 2: Kuvaajien piirto, skriptit ja funktiot. Matlabohjelmoinnin perusteita Numeerinen integrointi trapezoidaalimenetelmällä voidaan tehdä komennolla trapz. Esimerkki: Vaimenevan eksponentiaalin

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

811120P Diskreetit rakenteet

811120P Diskreetit rakenteet 811120P Diskreetit rakenteet 2018-2019 1. Algoritmeista 1.1 Algoritmin käsite Algoritmi keskeinen laskennassa Määrittelee prosessin, joka suorittaa annetun tehtävän Esimerkiksi Nimien järjestäminen aakkosjärjestykseen

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

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

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

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

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

811120P Diskreetit rakenteet

811120P Diskreetit rakenteet 811120P Diskreetit rakenteet 2016-2017 1. Algoritmeista 1.1 Algoritmin käsite Algoritmi keskeinen laskennassa Määrittelee prosessin, joka suorittaa annetun tehtävän Esimerkiksi Nimien järjestäminen aakkosjärjestykseen

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 9 Kombinaattoreista Antti-Juhani Kaijanaho Jyväskylän yliopisto Tietotekniikan laitos 21. tammikuuta 2008 Currying Haskell-funktio ottaa aina vain yhden

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

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin peruskurssi Y1 Ohjelmoinnin peruskurssi Y1 CS-A1111 13.9.2017 CS-A1111 Ohjelmoinnin peruskurssi Y1 13.9.2017 1 / 19 Oppimistavoitteet: tämän luennon jälkeen osaat kirjoittaa Python-ohjelman, joka pyytää käyttäjältä lukuja,

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

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

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

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

Chapel. TIE Ryhmä 91. Joonas Eloranta Lari Valtonen

Chapel. TIE Ryhmä 91. Joonas Eloranta Lari Valtonen Chapel TIE-20306 Ryhmä 91 Joonas Eloranta Lari Valtonen Johdanto Chapel on Amerikkalaisen Cray Inc. yrityksen kehittämä avoimen lähdekoodin ohjelmointikieli. Chapel on rinnakkainen ohjelmointikieli, joka

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

7. Näytölle tulostaminen 7.1

7. Näytölle tulostaminen 7.1 7. Näytölle tulostaminen 7.1 Sisällys System.out.println- ja System.out.print-operaatiot. Tulostus erikoismerkeillä. Edistyneempää tulosteiden muotoilua. 7.2 Tulostusoperaatiot System.out.println-operaatio

Lisätiedot

Pythonin alkeet Syksy 2010 Pythonin perusteet: Ohjelmointi, skriptaus ja Python

Pythonin alkeet Syksy 2010 Pythonin perusteet: Ohjelmointi, skriptaus ja Python Pythonin alkeet Syksy 2010 Pythonin perusteet: Ohjelmointi, skriptaus ja Python 8. marraskuuta 2010 Ohjelmointi Perusteet Peruskäsitteitä Olio-ohjelmointi Pythonin alkeet Esittely Esimerkkejä Muuttujat

Lisätiedot

Ydin-Haskell Tiivismoniste

Ydin-Haskell Tiivismoniste Ydin-Haskell Tiivismoniste Antti-Juhani Kaijanaho 8. joulukuuta 2005 1 Abstrakti syntaksi Päätesymbolit: Muuttujat a, b, c,..., x, y, z,... Tyyppimuuttujat α, β, γ,... Koostimet (data- ja tyyppi-) C, D,...,

Lisätiedot

Geneeriset tyypit. TIES542 Ohjelmointikielten periaatteet, kevät Antti-Juhani Kaijanaho. Jyväskylän yliopisto Tietotekniikan laitos

Geneeriset tyypit. TIES542 Ohjelmointikielten periaatteet, kevät Antti-Juhani Kaijanaho. Jyväskylän yliopisto Tietotekniikan laitos Geneeriset tyypit TIES542 Ohjelmointikielten periaatteet, kevät 2007 Antti-Juhani Kaijanaho Jyväskylän yliopisto Tietotekniikan laitos 6. maaliskuuta 2007 Kysymys Mitä yhteistä on seuraavilla funktioilla?

Lisätiedot

Algoritmit 1. Luento 3 Ti Timo Männikkö

Algoritmit 1. Luento 3 Ti Timo Männikkö Algoritmit 1 Luento 3 Ti 17.1.2017 Timo Männikkö Luento 3 Algoritmin analysointi Rekursio Lomituslajittelu Aikavaativuus Tietorakenteet Pino Algoritmit 1 Kevät 2017 Luento 3 Ti 17.1.2017 2/27 Algoritmien

Lisätiedot

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin peruskurssi Y1 Ohjelmoinnin peruskurssi Y1 CS-A1111 12.9.2018 CS-A1111 Ohjelmoinnin peruskurssi Y1 12.9.2018 1 / 19 Oppimistavoitteet: tämän luennon jälkeen osaat kirjoittaa Python-ohjelman, joka pyytää käyttäjältä lukuja,

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

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

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

815338A Ohjelmointikielten periaatteet

815338A Ohjelmointikielten periaatteet 815338A Ohjelmointikielten periaatteet 2015-2016 VI Funktionaalinen ohjelmointi Sisältö 1. Johdanto ja peruskäsitteitä 2. LISP- ja Scheme-kielet 3. Haskell 4. IO funktionaalisissa kielissä 5. Muita funktionaalisia

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

12. Javan toistorakenteet 12.1

12. Javan toistorakenteet 12.1 12. Javan toistorakenteet 12.1 Sisällys Yleistä toistorakenteista. Laskurimuuttujat. While-, do-while- ja for-lauseet. Laskuri- ja lippumuuttujat. Tyypillisiä ohjelmointivirheitä. Silmukan rajat asetettu

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

Esimerkki: Laskin (alkua) TIEA341 Funktio ohjelmointi 1 Syksy 2005

Esimerkki: Laskin (alkua) TIEA341 Funktio ohjelmointi 1 Syksy 2005 Esimerkki: Laskin (alkua) TIEA341 Funktio ohjelmointi 1 Syksy 2005 Esimerkki: Laskin Liukulukulaskentaa Yhteen, vähennys, kerto ja jakolaskut Syötteenä laskutehtävä, tulosteena tulos tai virheilmoitus

Lisätiedot

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin peruskurssi Y1 Ohjelmoinnin peruskurssi Y1 CS-A1111 14.9.2016 CS-A1111 Ohjelmoinnin peruskurssi Y1 14.9.2016 1 / 19 Oppimistavoitteet: tämän luennon jälkeen osaat kirjoittaa Python-ohjelman, joka pyytää käyttäjältä lukuja,

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

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin peruskurssi Y1 Ohjelmoinnin peruskurssi Y1 CS-A1111 11.9.2019 CS-A1111 Ohjelmoinnin peruskurssi Y1 11.9.2019 1 / 19 Oppimistavoitteet: tämän luennon jälkeen osaat kirjoittaa Python-ohjelman, joka pyytää käyttäjältä lukuja,

Lisätiedot

Ohjelmointi 1 Taulukot ja merkkijonot

Ohjelmointi 1 Taulukot ja merkkijonot Ohjelmointi 1 Taulukot ja merkkijonot Jussi Pohjolainen TAMK Tieto- ja viestintäteknologia Johdanto taulukkoon Jos ohjelmassa käytössä ainoastaan perinteisiä (yksinkertaisia) muuttujia, ohjelmien teko

Lisätiedot

5/20: Algoritmirakenteita III

5/20: Algoritmirakenteita III Ohjelmointi 1 / syksy 2007 5/20: Algoritmirakenteita III Paavo Nieminen nieminen@jyu.fi Tietotekniikan laitos Informaatioteknologian tiedekunta Jyväskylän yliopisto Ohjelmointi 1 / syksy 2007 p.1/17 Tämän

Lisätiedot

Tähtitieteen käytännön menetelmiä Kevät 2009 Luento 4: Ohjelmointi, skriptaus ja Python

Tähtitieteen käytännön menetelmiä Kevät 2009 Luento 4: Ohjelmointi, skriptaus ja Python Tähtitieteen käytännön menetelmiä Kevät 2009 Luento 4: Ohjelmointi, skriptaus ja Python 31. tammikuuta 2009 Ohjelmointi Perusteet Pythonin alkeet Esittely Esimerkkejä Muuttujat Peruskäsitteitä Käsittely

Lisätiedot

ITKP102 Ohjelmointi 1 (6 op)

ITKP102 Ohjelmointi 1 (6 op) ITKP102 Ohjelmointi 1 (6 op) Tentaattori: Antti-Jussi Lakanen 12. huhtikuuta 2019 Tee kukin tehtävä omalle konseptiarkille. Noudata ohjelmointitehtävissä kurssin koodauskäytänteitä. Yksi A4-kokoinen lunttilappu

Lisätiedot

Ohjelmassa henkilön etunimi ja sukunimi luetaan kahteen muuttujaan seuraavasti:

Ohjelmassa henkilön etunimi ja sukunimi luetaan kahteen muuttujaan seuraavasti: 1 (7) Tiedon lukeminen näppäimistöltä Scanner-luokan avulla Miten ohjelma saa käyttöönsä käyttäjän kirjoittamaa tekstiä? Järjestelmässä on olemassa ns. syöttöpuskuri näppäimistöä varten. Syöttöpuskuri

Lisätiedot

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python Ohjelmoinnin perusteet Y Python T-106.1208 19.1.2011 T-106.1208 Ohjelmoinnin perusteet Y 19.1.2011 1 / 39 Haluatko antaa palautetta luennoista? Ilmoittaudu mukaan lähettämällä ilmainen tekstiviesti Vast

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

Harjoitus 2 (viikko 45)

Harjoitus 2 (viikko 45) Mikäli tehtävissä on jotain epäselvää, laita sähköpostia vastuuopettajalle (jorma.laurikkala@uta.fi). Muista lisätä static-määre operaatioidesi otsikoihin, jotta ohjelmasi kääntyvät. Muista noudattaa hyvän

Lisätiedot

Lisää pysähtymisaiheisia ongelmia

Lisää pysähtymisaiheisia ongelmia Lisää pysähtymisaiheisia ongelmia Lause: Pysähtymättömyysongelma H missä H = { w111x w validi koodi, M w ei pysähdy syötteellä x } ei ole rekursiivisesti lueteltava. Todistus: Pysähtymisongelman komplementti

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

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä Ohjelmoinnin peruskurssien laaja oppimäärä Luento 8: Pienen ohjelmointikielen tulkki (ohjelmoitava laskin) (mm. SICP 4-4.1.5 osin) Riku Saikkonen 15. 11. 2012 Sisältö 1 Nelilaskintulkki, globaalit muuttujat

Lisätiedot

System.out.printf("%d / %d = %.2f%n", ekaluku, tokaluku, osamaara);

System.out.printf(%d / %d = %.2f%n, ekaluku, tokaluku, osamaara); Kysy Karilta tai Kimmolta, jos tehtävissä on jotain epäselvää. Kerro WETOon liittyvät ongelmat suoraan Jormalle sähköpostitse (jorma.laurikkala@uta.fi). Muista nimetä muuttujat hyvin sekä kommentoida ja

Lisätiedot

Ohjelmoinnin peruskurssi Y1

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

Lisätiedot

11.4. Context-free kielet 1 / 17

11.4. Context-free kielet 1 / 17 11.4. Context-free kielet 1 / 17 Määritelmä Tyypin 2 kielioppi (lauseyhteysvapaa, context free): jos jokainenp :n sääntö on muotoa A w, missäa V \V T jaw V. Context-free kielet ja kieliopit ovat tärkeitä

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

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

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

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

1. Universaaleja laskennan malleja

1. Universaaleja laskennan malleja 1. Universaaleja laskennan malleja Laskenta datan käsittely annettuja sääntöjä täsmällisesti seuraamalla kahden kokonaisluvun kertolasku tietokoneella, tai kynällä ja paperilla: selvästi laskentaa entä

Lisätiedot

Harjoitus 5 (viikko 48)

Harjoitus 5 (viikko 48) Moni tämän harjoituksen tehtävistä liittyy joko suoraan tai epäsuorasti kurssin toiseen harjoitustyöhön. Harjoitustyö edistyy sitä paremmin, mitä enemmän tehtäviä ratkaiset. Mikäli tehtävissä on jotain

Lisätiedot

Koka. Ryhmä 11. Juuso Tapaninen, Akseli Karvinen. 1. Taustoja 2. Kielen filosofia ja paradigmat 3. Kielen syntaksia ja vertailua JavaScriptiin Lähteet

Koka. Ryhmä 11. Juuso Tapaninen, Akseli Karvinen. 1. Taustoja 2. Kielen filosofia ja paradigmat 3. Kielen syntaksia ja vertailua JavaScriptiin Lähteet Koka Ryhmä 11 Juuso Tapaninen, Akseli Karvinen 1. Taustoja 2. Kielen filosofia ja paradigmat 3. Kielen syntaksia ja vertailua JavaScriptiin Lähteet 1 1. Taustoja Koka on Daan Leijenin ja Microsoft:n kehittämä

Lisätiedot

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä Ohjelmoinnin peruskurssien laaja oppimäärä Luento 5: Sijoituslause, SICP-oliot, tietorakenteen muuttaminen (mm. SICP 33.1.3, 3.33.3.2) Riku Saikkonen 6. 11. 2012 Sisältö 1 Muuttujan arvon muuttaminen:

Lisätiedot

Ohjelmoinnin peruskurssi Y1

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

Lisätiedot

12. Javan toistorakenteet 12.1

12. Javan toistorakenteet 12.1 12. Javan toistorakenteet 12.1 Sisällys Yleistä toistorakenteista. Laskurimuuttujat. While-, do-while- ja for-lauseet. Laskuri- ja lippumuuttujat. Tyypillisiä ohjelmointivirheitä. Silmukan rajat asetettu

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

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

Harjoitus 3 (viikko 39)

Harjoitus 3 (viikko 39) Mikäli tehtävissä on jotain epäselvää, laita sähköpostia vastuuopettajalle (jorma.laurikkala@uta.fi). Muista nimetä muuttujat hyvin sekä kommentoida ja sisentää koodisi. Vältä liian pitkiä rivejä. Ohjelmointitehtävien

Lisätiedot

Luento 5. Timo Savola. 28. huhtikuuta 2006

Luento 5. Timo Savola. 28. huhtikuuta 2006 UNIX-käyttöjärjestelmä Luento 5 Timo Savola 28. huhtikuuta 2006 Osa I Shell-ohjelmointi Ehtolause Lausekkeet suoritetaan jos ehtolausekkeen paluuarvo on 0 if ehtolauseke then lauseke

Lisätiedot

System.out.printf("%d / %d = %.2f%n", ekaluku, tokaluku, osamaara);

System.out.printf(%d / %d = %.2f%n, ekaluku, tokaluku, osamaara); Mikäli tehtävissä on jotain epäselvää, laita sähköpostia vastuuopettajalle (jorma.laurikkala@uta.fi). Muista nimetä muuttujat hyvin sekä kommentoida ja sisentää koodisi. Ohjelmointitehtävien osalta palautetaan

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

11. Javan toistorakenteet 11.1

11. Javan toistorakenteet 11.1 11. Javan toistorakenteet 11.1 Sisällys Laskuri- ja lippumuuttujat. Sisäkkäiset silmukat. Tyypillisiä ohjelmointivirheitä: Silmukan rajat asetettu kierroksen verran väärin. Ikuinen silmukka. Silmukoinnin

Lisätiedot