main :: IO () main = interact (concatmap ((++"\n"). reverse). lines)

Koko: px
Aloita esitys sivulta:

Download "main :: IO () main = interact (concatmap ((++"\n"). reverse). lines)"

Transkriptio

1 saa syötteenään oletussyötevirran stdin koko (jäljellä olevan) sisällön laiskasti luettavana merkkijonona antaa tulosteensa toisena merkkijonona jota se voi rytmittää rivinvaihdoilla. Esimerkiksi: module Main(main) where main :: IO () main = interact (concatmap ((++"\n"). reverse). lines) Mutkikkaammat I/O-operaatiot kuten esimerkiksi tiedostojen käsittely löytyvät vakiokirjastosta System.IO. Esimerkiksi usein halutaan oletustulosvirta stdout sellaiseksi, ettei sitä puskuroidakaan. Siihen tämä kirjasto tarjoaa kutsun hsetbuffering stdout NoBuffering jonka voi sijoittaa sellaisen ohjelman mainin alkuun. Poikkeuksista Poikkeuksia (eception) on hankala sovittaa yhteen puhtaan funktionaalisen ohjelmoinnin kanssa: Se milloin poikkeus käsitellään olettaa, että ohjelmoija tietäisi milloin jotakin tapahtuu laskennan kuluessa mutta puhtaassa funktionaalisessa ohjelmoinnissahan ohjelmoija tietää korkeintaan että se joskus tapahtuu... Haskellin vakiokirjasto System.IO.Error tarjoaakin yksinkertaisen poikkeusmekanismin erilaisten I/O-virheiden käsittelyyn koska Monadissa IO on tällainen järjestys ensin lasketaan tämä, ja sitten vasta tuo... Toteutuksen ghc mukana tulee myös sen oma toinenkin kirjasto Control.Eception jolla poikkeuksia voi nostaa muuallakin kuin Monadissa IO mutta nekin voi käsitellä vain siellä tämän järjestyksen vuoksi. Vakiokirjaston I/O-poikkeusmekanismi koostuu tyypistä IOError eli jokin I/Ovirhe sekä funktioista ioerror :: IOError -> IO a joka nostaa parametrina ilmoitetun I/O-poikkeuksen catch :: IO a -> (IOError -> IO a) -> IO a jonka ensimmäinen parametri on I/O-tyyppinen lauseke (kuten esimerkiksi jokin do-lauseke) jonka laskenta voi aiheuttaa I/O-poikkeuksia. Jos niitä ei aiheudu, niin catchin arvoksi tulee tämän laskennan antama arvo. 104

2 jälkimmäinen parametri on funktio, jota kutsutaan, jos näin käy. Se saa parametrinaan sen aiheutuneen poikkeuksen. Se voi käsitellä kyseisen poikkeustilanteen palauttamalla jonkin arvon, josta tulee tämän catchin arvo. Jos se ei osaakaan käsitellä tilannetta, niin sen pitääkin nostaa sama poikkeus uudelleen, jolloin tilanteen käsittelyvastuu siirtyykin seuraavalle ulommalle catchille. Jos mikään catch ei osaakaan sitä käsitellä, niin silloin koko mainin laskenta keskeytyy suoritusaikaiseen virheeseen. try :: IO a -> IO (Either IOError a) joka koettaa suorittaa parametrinaan saamansa laskennan. Jos sen arvo on Right niin tämä laskenta onnistui virheettä ja on sen lopputulos Left e niin silloin tämä laskenta johtikin poikkeukseen e. Otetaan sitten esimerkiksi I/O-ohjelmoinnista nelilaskin, jossa pidetään muistissa yhtä liukulukua käyttäjä voi antaa komentonaan lisää/vähennä/kerro/jaa se luvulla... tämän komentorivin mahdolliset virheet käsitellään tyhjä komentorivi lopettaa ohjelman suorituksen. module Main(main) where import System.IO import System.IO.Error main :: IO () main = do hsetbuffering stdout NoBuffering laskin 0.0 laskin :: Double -> IO () laskin muisti = do putstr $ "Muistissani on: " ++ show muisti ++ "\nkomentosi? " komentorivi <- getline case komentorivi of "" -> do putstrln "Kiitos!" return () (komento:rivi) -> case lookup komento komennot of Nothing -> do putstrln $ "Tunnen vain seuraavat laskutoimitukset: " ++ map fst komennot ++ "!" laskin muisti 105

3 Just operaattori -> do arvo <- try $ readio rivi case arvo of Right luku -> laskin $ muisti operaattori luku Left _ -> do putstrln "Tajuan vain liukulukuja!" laskin muisti komennot :: [(Char,Double->Double->Double)] komennot = [( +,(+)),( -,(-)),( *,(*)),( /,(/)) ] 7.3 Maybe monadina Aiemmin näimme, miten Maybe on Monadi: instance Monad Maybe where (Just ) >>= k = k Nothing >>= k = Nothing return = Just fail s = Nothing Tarkastellaan sitä tässä valossa, että lausekkeen p >>= k voi lukea myös suorita ensin laskenta p ja sovella sitten sen tulokseen funktiota k. Silloin näemme uuden tulkinnan Maybelle: Jos laskenta p sai jonkin tuloksen niin sovella siihen funktiota k, mutta jos se ei saanutkaan mitään tulosta, niin koko loppulaskentakaan ei saa mitään tulosta koska siitä alkaen jokaisen (>>=)-operaattorin vasen parametri on aina Nothing. Silloin siis jokainen Maybe-tyyppisen do-lauseen hahmo <- kutsuttava ohitetaan kokonaan, jos jokin sitä edeltävistä tällaisista lauseista on jo tuottanut arvon Nothing siinä kutsuttava laskenta tuottaakin sellaisen arvon, joka ei olekaan muotoa olekaan muotoa Just hahmo. Silloin siis tästä alkaen kaikki lauseet ohitetaan. Siten tässä valossa Maybe antaakin tyypin sellaiselle laskennalle joka päättyy epäonnistumiseen jos yksikin siinä kutsuttava laskenta epäonnistuu. 106

4 7.4 Lista monadina Olemme nähneet jo aiemmin, miten listat ovat Monadi: instance Monad [] where m >>= k = concat (map k m) return = [] fail s = [] Tarkastellaan sitäkin tässä valossa, että lausekkeen p >>= k voi lukea myös suorita ensin laskenta p ja sovella sitten sen tulokseen funktiota k. Nyt sen koko laskenta etenee seuraavasti: 1. Laskenta p tuottaa tuloksenaan listan m eli [ 1, 2, 3,...]. 2. Sen jokaiseen alkioon i sovelletaan (map) funktiota k. 3. Jokainen sovellus k i tuottaa tuloksenaan jonkin listan [y 1 i, y 2 i, y 3 i,...]. 4. Yhdistetään (concat) nämä listat yhdeksi listaksi k 1 ++ k 2 ++ k Sitten ympäröivässä listamonadilausekkeessa >>=k sovelletaan seuraavaa funktiota k jokaiseen tämän listan alkioon y j i, jne. Vaihdetaan näkökulmaa kokonaisista listoista niiden yksittäisiin alkioihin: Ajatellaan, että alkio i edustaisi jotakin tilaa, jossa koko laskenta voisi olla tällä hetkellä. Silloin k i tuottaa sille monta eri mahdollista seuraavaa tilaa y j i. Tässtä näkökulmasta k on siis epädeterministinen seuraava laskenta-askel. Tässä valossa listamonadi ja sen do-syntaksi kuvaavat epädeterministisen laskennan kaikkien eri vaihtoehtojen seuraamiseen. Deklaratiivisesti yksi tällainen epädeterministinen askel hahmo <- kutsuttava voidaan lukea valitse mikä tahansa hahmo on sopiva vaihtoehto kutsuttava n laskennan antamista mahdollisuuksista. Tässä luennassa <- on. 107

5 Proseduraalisesti se luetaan kokeile jokaista näistä vaihtoehdoista siinä järjestyksessä jossa kutsuttava ne tuottaa. Tässä luennassa tuo deklaratiivisuus toteutetaan syvyyshakuna (depth-first search). Se on epätäydellistä koska se juuttuu ikuiseen silmukkaan, jos sellaiseen johtava väärä vaihtoehto tulee tässä kokeilujärjestyksessä ennen oikeaa vaihtoehtoa. tehokkaasti toteutettavissa erityisesti muistinkäytöltään. Haskellin laiskat listat hoitavat sen automaattisesti ohjelmoijatta. Aiemmassa esimerkissämme säännöllisistä lausekkeista käytimme juuri tätä samaa ideaa ja näimme erikseen vaivaa sen pysähtymisen takaamiseksi. Olemme nähneet aiemmin myös listakoosteet, joiden syntaksi oli hyvin lähellä dosyntaksia: 1. Listakoosteissa sallittiin vaihe ena Bool-tyyppinen lauseke, jota do-syntaksissa ei sallita. 2. Toisaalta do-syntaksissa sallittiin lause ena mielivaltainen kyseisen Monadityypin lauseke, kun taas listakoosteissa ei sallittu vaihe ena pelkkää listalauseketta ilman edeltävää osaa hahmo <-. Tämä ei tietenkään ole sattumaa vaan suunniteltua: Listakoosteet ovatkin yleisen Monadisen do-syntaksin erikoistapaus listamonadille. Eron 1 voi ymmärtää tästä näkökulmasta: Hylkää tämä nykyinen epädeterministinen laskentahaara ellei tuo ehto q ole totta on luonteva operaatio juuri listamonadissa mutta ei muissa. Tällaisen ehdontestausvaiheen q voi ilmaista listamonadin do-syntaksissa vaikkapa () <- if q then return () else fail Jos listakoosteen ehdontestausvaihe eet q on näin muunnettu tuottaviksi vaihe iksi, niin silloin se voidaan muuntaa suoraan do-syntaksiin: listakoosteesta [lauseke osa 1, osa 2, osa 3,. osa r ] do-syntaksiin do osa 1 osa 2 osa 3. osa r return lauseke 7.5 Tilaperustaisesta ohjelmoinnista monadina Lähdimme kurssin alussa siitä, että matemaattinen funktio on mahdollisimman tiukka rajapintakäsite ohjelmointiin: sisään menee informaatiota vain parametreissa 108

6 ulos ulos tulee informaatiota vain tuloksessa. Voidaan ajatella ja ohjelmoida sellaisia funktioita, jotka näiden funktionaalisten rajapintojensa sisällä ovatkin tilaperustaisia. Silloin vain täytyy pitää huoli, että tämä tila pysyy yksityisenä tällaisen funktion jokaisella käyttökerralla: Kun tällaisen funktion arvon laskenta alkaa, niin myös sen sisäinen tila alustetaan eikä jatketakaan siitä tilasta johon edellinen laskenta päättyi. Jos tällaisen funktion kahta eri arvoa laskettaisiin rinnakkain, niin kumpikin muokkaisi omaa yksityistä tilaansa. ghc tarjoaa tähän tarkoitukseen oman kirjastonsa Control.Monad.ST joka ei siis ole Haskell-standardikirjasto edes Haskell-kielistandardin mukainen, vaan käyttää ghc:n omia laajennuksia tyyppijärjestelmään. Näillä laajennuksilla Haskellin tyypitys pystyy takaamaan, että rajapinnat säilyvät funktionaalisina, vaikka sisäisesti laskenta onkin tilallista. Jos ohjelmoija yrittää vahingossa tai tahallaan rikkoa koodissaan näitä rajapintoja, niin hän siis saakin käännösaikaisen tyyppivirheilmoituksen. Valitettavasti nämä ilmoitukset voivat olla vaikeaselkoisia... Tämän Monadin nimenä onkin STate eli tila. Otetaan esimerkiksemme seuraava ohjelmointiongelmaa: Saamme listan pareja (,y) jotka tarkoittavat että alkioiden ja y pitää kuulua samaan joukkoon. Mitkä nämä joukot ovat, kun alkiot pidetään erillään, ellei mikään tällainen pari vaadi niiden kuuluvan yhteen? Se vaatii tietorakenteen, jossa on seuraavat operaatiot: initial joka alustaa sen siten, että jokainen alkio on aluksi yksin omassa joukossaan. union joka yhdistää ne joukot, joissa annetut alkiot ja y nyt ovat. Siitä käytetään myös nimeä merge. find palauttaa sen joukon edustajan, johon alkio z nyt kuuluu. Joukon edustaja on jokin sen alkioista. Sitä käytetään koko joukon nimenä. Kun esimerkiksi kysytään ovatko alkiot ja y jo nyt samassa joukossa niin re ratkaistaan kysymällä, onko alkion joukon edustaja sama kuin alkion y joukon edustaja. Tämä tietorakenne tunnetaankin nimellä union-find tai merge-find. 109

7 Tämä vaikuttaa sellaiselta ohjelmointiongelmalta, jonka imperatiivinen ratkaisu on funktionaalista nopeampi: Koska imperatiivisessa ratkaisussa voidaan käyttää uudelleensijoitusta, niin siellä voidaan tiivistää hakupolku alkiosta sen edustajaan, jotta seuraavat kyselyt sujuvat nopeammin. Tällöin saadaan ratkaisu, joka toimii askeleessa, jossa O((m + n) α(m + n)) m on alkioiden lukumäärä n on operaatioiden union ja find lukumäärä α on erittäin hitaasti kasvava funktio. Se on aiemmin näkemämme Ackermannin funktion (joka siis kasvoi erittäin nopeasti) käänteisfunktion sukulainen. Käytännössä α(m + n) > 5 vasta kun m + n > alkeishiukkasten arvioitu lukumäärä koko maailmankaikkeudessamme... Funktionaalisessa onjelmoinnissa tämä polun tiivistäminen ei ole mahdollista, ja ainakin yksinkertaiset tietorakenneratkaisut tarvitsevat funtion α tilalla logaritmin. Imperatiivisessa ratkaisussa on oleellisesti taulukko mem, jossa alkiosta z 0 alkava polku mem[z 0 ] mem[z 1 ] mem[z 2 ] z 0 z 1 z 2 mem[zp] z p+1 johtaa alkion joukon edustajaan z p+1. Kun kysytään operaatiolla find alkion joukon edustajaa, niin samalla tämä polku tiivistetään muotoon mem[z 0 ] = mem[z 1 ] = mem[z 2 ] = = mem[z p ] = z p+1 jolloin kaikkien näiden muidenkin alkioiden z 1, z 2, z 3,...,z p 1 operaatiolla find nopeutuvat. Operaatiota union voidaan taas tehostaa seuraavasti: Pidetään yllä jokaisessa edustajassa tietoa rank joka olisi näistä mem-linkeistä koostuvan puun korkeus ilman polkujen tiivistämistä. Tämän tiedon avulla yhdistetään aina matalamman puun juuri korkeamman puun juuren alipuuksi. Nämä juuret eli edustajat antaa siis operaatio find. Monadissa ST voimme luoda tällaisen taulukon mem ja käyttää sitä: Operaatio newarray_ :: (MArray a e m, I i) => (i, i) -> m (a i e) luo taulukon tälle indeksivälille sellaisessa monadissa m jossa sellaiset sallitaan. 110

8 ST on siis yksi sellainen m. IO on toinen sellainen m. Tyyppiluokka I on ne tyypit, joita voi käyttää taulukkoindekseinä. Operaatio readarray :: (MArray a e m, I i) => a i e -> i -> m e lukee tällaisen taulukon arvon annetusta indeksistä. Operaatio writearray :: (MArray a e m, I i) => a i e -> i -> e -> m () kirjoittaa tällaisen taulukon annnettuun indeksiin annetun arvon. module UnionFind where import Control.Monad import Control.Monad.ST import Data.Array.ST import Data.Word unions :: (I t) => [(t,t)] -> [[t]] unions ys = let lo = minimum sys hi = maimum sys sys = s ++ ys (s,ys) = unzip ys in runst $ do mem <- initial lo hi sequence_ $ map (uncurry $ union mem) ys sequence_ $ map (find mem) $ range (lo,hi) memz <- getassocs mem parties <- parts lo hi sequence $ map ( \ (i,it) -> let j = case it of Rank _ data Item t = Rank Word Ranked t memz groupies <- getelems parties return $ map reverse $ filter (not. null) groupies -> i Ranked k -> k in do jt <- readarray parties j writearray parties j $ i:jt) 111

9 deriving (Show) type UF s t = STArray s t (Item t) parts :: (I t) => t -> t -> ST s (STArray s t [t]) parts lo hi = newarray (lo,hi) [] initial :: (I t) => t -> t -> ST s (UF s t) initial lo hi = do mem <- newarray_ (lo,hi) sequence_ $ map (flip (writearray mem) (Rank 0)) $ range (lo,hi) return mem find :: (I t) => UF s t -> t -> ST s t find mem = let finder i = do here <- readarray mem i case here of Rank r -> return i Ranked j -> do k <- finder j writearray mem i $ Ranked k return k in finder union :: (I t) => UF s t -> t -> t -> ST s () union mem y = do i <- find mem j <- find mem y when (i/=j) $ do Rank p <- readarray mem i Rank q <- readarray mem j if p<q then writearray mem i (Ranked j) else do writearray mem j (Ranked i) when (p==q) $ writearray mem i (Rank (p+1)) Funktionaalinen Haskell-ohjelma voi laskea tilaperustaisena määritellyn funktion tuloksen käyttämällä funktiota runst :: (forall s. ST s a) -> a joka suorittaa parametrinsa saamansa ST-laskennan alkusta loppuun saakka 112

10 palauttaa arvonaan sen lopputuloksen, jonka tyyppi on a. Siten tyyppi ST s a on tilaperustainen laskenta, jonka lopputulos on tyyppiä a. Siten ST on sellainen kaksiparametrinen tyyppikonstruktori, joka saadessaan ensimmäisen parametrinsa s tuottaa Monadin ST s. Useimpiin Monadeihin liittyy tällainen suorita -funktio, jolla funktionaalisesta koodista käsin voi ajaa Monadisen laskennan. Kääntäen, Monadissa IO ei ole tällaista funktiota runio koska sehän juuri mahdollistaisi I/O-toiminnat keskellä funktionaalista koodia. Entä tuo tyyppiparametri s? Siinä on käytetty Haskellin laajennusta forall jota emme ole käsitelleet tarkemmin emmäekä tässäkään tutustu siihen syvällisesti. Sen intuitio on että s voi olla mikä tahansa tyyppi joten kääntäen siitä ei voi olettaa yhtään mitään, eli se on erittäin abstrakti. Tässä yhteydessä tämän tyypin voi lukea hiekkalaatikko (sandbo) jonka sisällä tämä tilaperustainen laskenta toimii. Haskellin laajennettu tyyppijärjestelmä takaa, ettei tilaperustainen laskenta voi palauttaa mitään sellaista vastausta, jonka tyypissä esiintyisi tämä s. Siten se ei voi palauttaa esimerkiksi taulukkoa mem koska sen tyyppi on UF s t. Näin se turvaa tilan säilymisen yksityisenä jokaisessa funktion runst kutsussa. 7.6 Monadisen ohjelmoinnin periaatteista Jos haluaa kirjoittaa funktion f, joka käyttää monadin M palveluita (kuten monadin IO syötteenluku- ja tulostuspalveluita) ja palauttaa arvon tyyppiä τ, niin sen tulostyyppinä on M τ viimeinen lauseke do-notaatiossa on return e jossa lausekkeen e tyyppi on τ. Tälläisen funktion arvon a voi sitten laskea do-notaatiossa <- f parametrit jossa myös hahmon tyyppi on τ ja se nimeää arvon a. Funktion f parametri en tyypit kirjoitetaan funktion f tyyppiin tavalliseen tapaan. Jos jonkin parametri n tyyppi on M µ niin se on monadinen vastine korkeamman kertaluvun parametrille: Esimerkiksi funktion when :: (Monad m) => Bool -> m () -> m () 1. parametri on tavallinen totuusarvotyyppinen testi 113

11 2. parametri on laskenta, joka suoritetaan jos tämä testi on tosi muuten ei tehdä mitään, siksi tulostyyppi on (). Vakiokirjastot Prelude ja Control.Monad käyttävät tällaisia korkeamman kertaluvun monadisia parametreja määritelläkseen tällaisia uusia kontrollirakenteita kuten tämä when. Näissä kontrollirakenteissa voidaan yhdistellä esimerkiksi funktionaalista listankäsittelyä ja monadisia operaatioita: Esimerkiksi sequence_ :: Monad m => [m a] -> m () sequence_ = foldr (>>) (return ()) tekee kokonaisen listan esimerkiksi tulostuosoperaatioita (joiden tyyppi on IO ()) alusta loppuun saakka, koska sequence_ [p 1,p 2,p 3,...,p k ] on suoraan funktion foldr määritelmän nojalla p 1 >> (p 2 >> (p 3 >> (... >> (p k >> return ())...))) joka taas on sokeroimaton muoto lausekkeelle do p 1 p 2 p 3. p k return () Muutkin ohjelmointitehtävät joissa on luonteva käsite ensin tämä ja sitten tuo voidaan mallintaa monadeilla. Sellainen on esimerkiksi jäsentäminen (parsing). Aiempaa säännöllisten lausekkeiden esimerkkiämme voikin kehittää edelleen kirjastoksi monadisia jäsenninkombinaattoreita (monadic parser combinator). Silloin do 1 <- q 1 2 <- q 2 3 <- q 3. k <- q k return $ f k 114

12 on yksi kielioppisääntö ensin tulee jotakin, jonka q 1 jäsentää, sitten jotakin jota q 2 jäsentää, sitten... ja nämä i ovat niitä vastaavat semanttiset semanttiset rakenteet kuten jäsennyspuut. Ne taas on luonteva esittää algebrallisilla tietotyypeillä. Näitä voi sitten yhdistellä (combine) sopivilla operaattoreilla kuten r < > s eli käytä joko jäsennintä r tai jäsennintä s. HackageDB sisältää kirjaston tällaisen Parsec. Yleisemmin monadisen ohjelmoinnin haittavaikutus on, että ne tartuttavat helposti koodia: Jos yksi osa koodista on Monadista, niin myös siinä kutsuttavien koodinosien pitää usein olla Monadisia, ja näin isosta osasta koodia tulee monadisesti monoliittista. Tämä johtuu siitä, että Monadinen tyyppi sanoo että tämä koodi voi tarvita tämän Monadin tarjoamia palveluita. Tästä näkökulmasta esimerkiksi ST s tarkoittaa tämä koodi voi tarvita uudelleensijoituslausetta. Koodin monoliittisuus tarkoittaakin usein sitä, että Monadia pidetään varmuuden vuoksi tarjolla ja sen voisi välttää miettimällä tarkemmin mitä palveluita oikeastaan milloinkin koodissaan tarvitsee. Monadikirjastot pyrkivät usein ehkäisemään tätä monoliittisyyttä tarjoamalla monadimuuntimia (monad transformers) joilla voi lisätä jonkin sisemmän monadin päälle kuorikerrokseksi toisen monadin. Tällöin jokaisessa kerroksessa on vain siinä tarpeelliset palvelut. 115

13 8 Laiskan laskennan teoriaa ja käytäntöä Tarkastellaan lopuksi hieman sitä, mistä Haskellin laiskassa laskennassa tarkemmin sanoen onkaan kyse. Tähän mennessä olemme puhuneet siitä käsiä heilutellen tyyliin Haskell laskee vain sen tiedon jota tarvitsee tms. Yleisesti ohjelmointikielen merkitysopissa eli semantiikassa on kaksi puolta: Tarkoitesemantiikka (denotational semantics) käsittelee sitä mitä kielen ilmaukset oikein laskevat ilmaisulla tarkoitettua tulosta. Kurssilla LAP käytettiin tätä lähestymistapaa silloin kun käsiteltiin sitä formaalikieltä, joka koostui niistä syötteistä, joilla automaatti(a vastaava tietokoneohjelma) vastaisi kyllä. Automaateilla tarkoitesemantiikka onkin formaalikielten joukko-oppia. Ohjelmointikielten tarkoitesemantiikassa käytetään sellaisia matemaattisia työvälineitä kuin kategoriateoriaa ja arvoalueteoriaa (joka on luennoijan oma kömpelö käännösehdotelma termille domain theory...). Ohjelmointikielillä tarkoitesemantiikka kuvaileekin niitä funktioita joita ohjelmat esittävät. Yksi osa tarkoitesemantiikkaa on ohjelmointikielen tyyppiteoria (type theory) jolla suljetaan pois sellaisia ilmauksia, jotka kyllä ovat syntaktisesti oikein, muitta joille ei voi antaa järkevää tarkoitettua tulosta. Esimerkiksi ohjelmalla, joka laskisi yhteen totuusarvon ja merkkiijonon, ei ole järkevää tulosta, joten tyypitys sulkeen sen pois. Haskellin tyyppiteoria lähtee siitä, että tyypitys tehdään kokonaan ennen laskentaa, jolloin laskennan aikana ei enää ilmene tyyppivirheitä vaan pelkästään sellaisia suoritusvirheitä kuten vaikkapa yritys jakaa nollalla tms. Emme kuitenkaan uppoudu tällä kurssilla tarkoitesemantiikkaan koska se vaatisi matemaattisen kalustonsa esittelyä ja kehittelyä. Suoritussemantiikka (operational semantics) taas käsittelee sitä miten kielen ilmausten tarkoittamat tulokset lasketaan. Tutustumme siis laiskan laskennan suoritussemantiikan pääpiirteisiin samoin kuin sen tavallisemman eli ahkerankin laskennan, jotta näemme missä niiden ero on. Lisäksi tutustumme siihen, miten Haskell-ohjelmoija voi koodissaan ilmoittaa että tämä koodinpätkä olisikin syytä suorittaa ahkerasti ja näin parantaa sen tehokkuutta. 8.1 Lambda-laskennen perusideat Alonzo Churchin 1936 jukaisema lambda- eli λ-laskenta on vakiintunut keskeiseksi formalismiksi ohjelmointikielten teoriassa, joten tutustutaan nyt lyhyesti sen perusideoihin. Church kehitti sen tarkastellakseen sellaista laskentaa, joka etenee sieventämällä monimutkaisempia lausekkeita yksinkertaisemmiksi. 116

14 Se onkin luonteva lähestymistapa erityisesti funktionaalisissa kielissä, joissa ohjelman suoritusta voidaan ajatella sen yksinkertaistamisena kohden tulostaan. Tilaperustaisissa kielissä oletetaan sievennyksen ohella myös jokin matemaattinen abstraktio muokattavan muistin käsitteelle, jota siis λ-laskennassa ei ole. Erityisesti λ-laskenta on otettu malliksi parametrinvälitykselle ohjelmointikielissä. Määritellään λ-lausekkeet seuraavasti: Muuttujan esiintymä on λ-lauseke. Sellaisenaan se on vapaa (free) esiintymä, koska sitä ei sido (bind) mikään λ. λ-termi λ.e on λ-lauseke, jossa on muuttuja ja e λ-lauseke. Tämä λ sitoo kaikki lausekkeessa e olevat tämän muuttujan vapaat esiintymät. Näin syntyy nykyaikaisista ohjelmointikielistä tuttu muuttujanesittelyiden näkyvyyssääntö: Tämä λ esittelee muuttujan ja siihen sidotut muuttujan esiintymät lausekkeessa e viittaavat tässä esiteltyyn muuttujaan. Jos lausekkeen s sisällä esiintyy jokin toinen (λ.f) niin se esittelee samannimisen mutta eri muuttujan, ja lausekkeen f sisällä muuttujan esiintymät viittaavatkin tähän sisempään esittelyyn. Tällainen λ-termi tarkoittaa ohjelmoijan näkökulmasta sellaista yksiparametrista funktiota, jonka parametrin nimi on tämä ja runko tämä e. Siis sitä, jonka Haskellissa ilmaisemme \ -> e joka onkin yritetty valita muistuttamaan merkkiä λ niin hyvin kuin se on ASCIIlla mahdollista... Kutsutermi muotoa (p q) on λ-lauseke jossa p ja q ovat λ-lausekkeita. Se tarkoittaa tämän funktion p kutsua tällä parametrilla q. Ennen suoritusta tehty tyypintarkastus takaa, että p voidaan sieventää muotoon (ellei se jo ole valmiiksi siinä muodossa) (λ.e). Ideana on että laskenta jatkuu lausekkeella e siten, että tämän vapaat esiintymät on siinä korvattu tällä q. Sovitaan sulkujen vähentämiseksi, että tarkoittaa samaa kuin (p q 1 q 2 q 3... q k ) (...(((p q 1 ) q 2 ) q 3 )... q k ) kuten Haskellissakin eli täälläkin käytämme kuritusta moniparametrisille funktioille, jotka ovat nyt muotoa λ 1.λ 2.λ 3....λ k.f. Muita λ-lausekkeita ei λ-laskennan perusmuodossa ole. 117

15 Nämä intuitiot parametrien nimien ja funktionkutsujen merkityksestä voidaan lausua seuraavina kahtena periaatteena: α-ekvivalenssi sanoo, että funktiot ovat samat, jossa λ.e ja λy.e[/y] muuttuja y ei esiinny vapaana lausekkeessa e ja e[/y] tarkoittaa sitä λ-lauseketta, joka saadaan korvaamalla jokainen muuttujan vapaa esiintymä lausekkeessa e λ-lausekkeella y. Siis paikallisen muuttujan määrittelyssä voi vaihtaa sen nimeä. Ohjelmointikielissä ajonaikainen järjestelmä huolehtii tästä automaattisesti, se täytyy sanoa ääneen vain λ-laskennan teoriaa esitellessä. β-reduktio taas sanoo, että kutsulauseke (λ.e) f sievenee muotoon e[/f] kunhan ei esiinny vapaana λ-lausekkeessa f mutta senhän voimme aina varmistaa käyttämällä ensin α-ekvivalenssia kutsulausekkeessa. Tämä on se keskeinen sääntö kun λ-laskentaa käytetään ohjelmointikielten ja niillä määritellyn laskennan kuvailussa......koska se ilmaisee mitä funktionkutsun suorittaminen merkitsee. Sen perusintuitio on, että kutsu suoritetaan suorittamalla funktion arvon määrittelevä lauseke e siten, että sen parametrin tilalla onkin sen argumentti f. Eri laskentamallien väliset erot palautuvat oleellisesti siihen, missä järjestyksessä näitä β-reduktioita sovelletaan, kun ohjelman suoritusta ajatellaan tähän tapaan sievennysaskeleina. Kun merkitsemme yhtä tällaista β-reduktioaskelta = β niin voimme esimerkiksi sieventää (λ.λy. y ) (λz.z z) = β λy.(λz.z z) y (λz.z z) = β λy.y y (λz.z z) jossa on alleviivattu se λ johon β-reduktiota nyt sovelletaan. Merkitään vastaavasti = β kokonaista ketjua tällaisia β-reduktioaskeleita. Siis (λ.λy. y ) (λz.z z) = β λy.y y (λz.z z) (14) edellisen kaksiaskelisen ketjun perusteella. Ohjelmointikieliä tarkasteltaessa tätä λ-laskennan perusmuotoa laajennetaan (tarpeen mukaan) esimerkiksi seuraavilla lisäpiirteillä: Perustyypeillä kuten Haskellin Bool, Integer,... Perusoperaatioilla jotka käsittelevät näitä perustyyppisiä arvoja, kuten vaikkapa (+) Integereille. 118

16 Algebrallisilla tietotyypeillä sekä vastaavilla case-lausekkeilla sentyyppisten arvojen käsittelyyn. Ne voidaan liittää mukaan määrittelemällä niillekin omat β-reduktiosääntönsä. Esimerkiksi Integereiden yhteenlasku (+) voidaan ajatella määritellyn äärettömän monena sääntönä tyyliin = β 4615 jne. Nämä perustyyppien perusoperaatiot käsittelevät sentyyppisiä arvoja (value) eli intuitiivisesti loppuun saakka laskettuja välituloksia formaalimmin sellaisia λ-lausekkeita, joihin ei enää voi soveltaa β-reduktioita. Siis esimerkiksi ((λ.(456 + )) 789) = β ( ) = β = β 1368 koska ulomman yhteenlaskun voi tehdä vain arvoilla, joten sen toinen operandi pitää ensin laskea omaan arvoonsa. 8.2 Normaalimuodoista Normaalimuodon (normal form, NF) käsite tarkoittaa yleisesti lausekkeen tms. sellaista muotoa, johon ei enää voi soveltaa mitään käytettävissä olevista muunnossäännöistä. Nyt λ-laskennan tapauksessa tämä ainoa sovellettava muunnossääntö on β-reduktio, ja siten λ-lausekkeen normaalimuoto tarkoittaa sen arvoa. Tämä normaalimuoto eli arvo voi toki olla funktiotyyppinenkin, kuten yhtälössä (14). Tyypittämätön λ-laskenta sisältää toki termejä joilla ei ole normaalimuotoa onhan päättymättömiä ohjelmiakin! Esimerkiksi jos termiin (λ.( )) (λ.( )) soveltaa β-reduktiota, niin saa vastauksenaan sen itsensä eli siihen voidaan loputtomiin soveltaa β-reduktiota. Mutta jos λ-laskennan termillä on normaalimuoto, niin se on oleellisesti yksikäsitteinen: Jos samalla termillä t on kaksi eri normaalimuotoa u ja v, niin ne ovat keskenään α-ekvivalentit, eli ne eroavat toisistaan vain paikallisten muuttujiensa nimissä. Tästä seuraa että kaikki termistä t alkavat ja loppuun asti lasketut β-reduktioketjut päätyvät oleellisesti samaan tulokseen. Siis tämä normaalimuoto eli arvo eli laskennan lopputulos on hyvin määritelty käsite joka ei riipu laskujärjestyksestä. 119

17 Tämä ei kuitenkaan tarkoita, että kaikki järjestykset olisivat yhtä hyviä: jotkut järjestykset päättyvät, ja saavuttavat lopputuloksen toiset taas jatkuvat ikuisesti, eivätkä saavuta sitä koskaan. Esimerkiksi λ-lausekkessa (λy.λz.z) ((λ.( )) (λ.( ))) = β λz.z (15) jos sovelletaan β-reduktiota alleviivatussa kohdassa, mutta muuten jäädään samaan ikuiseen silmukkaan kuin edellä. Onko olemassa jokin sellainen periaate valita aina oikea kohta λ-lausekkeessa, että kun juuri siihen sovelletaan β-reduktiota, niin aina lopulta päästään normaalimuotoon, jos sellainen lausekkeella on? Kyllä on, ja jopa yksinkertainen: Kohdista aina β-reduktio ensimmäiseen eli vasemmanpuoleisimpaan mahdolliseen kohtaan lausekkeessa. Tällaista kohtaa, johon voisi soveltaa β-reduktiota, kutsutaan nimellä rede (reducible epression eli redusoituva lauseke). Tämä vuoksi tätä periaatetta valitse aina vasemmanpuoleisin rede kutsutaankin normaaliksi sievennysjärjestykseksi (normal order reduction). Muista kuitenkin seuraava: Tällainen ohjelmointikielen formaali kuvaus ilmoittaa, että sen laskennan pitää näyttää ulkopuolisen tarkkailijan silmissä samalta kuin jos se oikeasti suoritettaisiinkin juuri näin. Kielen toteutus voi sisäisesti toimia miten tahansa, kunhan se säilyttää tämän illuusion. Suorituskelpoinen Haskell-ohjelmakaan ei manipuloi enää lausekkeita, vaan se suorittaakin niistä käännettyä konekoodia, jonka suoritus etenee sitä vastaavasti. Tätä periaatetta pitää tosin täsmentää silloin kun tämä vasemmanpuoleisin lauseke on case valinta of hahmo 1 -> tuloslauseke 1 hahmo 2 -> tuloslauseke 2 hahmo 3 -> tuloslauseke 3. hahmo k -> tuloslauseke k seuraavasti: 1. Valitse samalla periaatteella valinta lausekkeesta kohta, johon sovellat β-reduktiota. 120

18 2. Jos valinta lauseke muuttui sen tuloksena sellaiseen muotoon, johon jokin näistä hahmo ista sopii, niin korvaa koko tämä case-lauseke ensimmäisen sellaisen hahmon tuloslausekkeella johon olet tehnyt vastaavat nimennät. 3. Muuten palaa takaisin kohtaan 1 sieventämään valinta a edelleen; tai jos se onkin jo normaalimuodossaan, eikä se siltikään sopinut yhteenkään näistä hahmoista, niin lopeta koko laskenta suoritusaikaiseen virheeseen. Nyt voimme lausua ensimmäisen eron ohjelmointikielten erilaisten suoritusmekanismien välillä: Ahkera suoritusjärjestys (call-by-value/cbv, strict, eager) määritellään seuraavasti: Suorita kutsulauseke ((λ.e) f) siten, että 1. ensin sievennät sen parametrilausekkeen f arvoonsa a 2. sitten jatkat sieventämällä lauseketta e[/a]. Se ei siis noudatakaan normaalia sievennysjärjestystä......jolloin se voikin jäädä ikuiseen silmukkaan, kuten yhtälössä (15)... mutta silti useimmat ohjelmointikielet määrittelevät aliohjelmakutsunsa juuri näin... koska silloin ohjelmoija tietää suoritusjärjestyksestä ainakin sen, milloin arvon a laskenta on valmis... joten hän voi käyttää tilaperustaisia piirteitä. Laiska suoritusjärjestys (call-by-need, lazy, non-strict) taas noudattaakin normaalia sievennysjärjestystä. Silloin lauseke e pystyykin valitsemaan itse, mitä osia lausekkeen f arvosta a sen tarvitseekaan oikeasti laskea omaa vastaustaan varten eli silloin tietoriippuvuudet määräävät laskentajärjestyksen. Edellisen mukaan siis laiska suoritusjärjestys pystyy saavuttamaan lopputuloksen aina kun sellainen suinkin on olemassa eli se keksii itse aina oikean sievennystavan...vaikkei siinä ollutkaan paljon keksimistä: Riittää valita aina vasemmanpuoleisin rede. Huomaa kuitenkin, että case-lausekkeissa on kiinteä kokeilujärjestys... jos tämä hahmo sopii mutta mikään sitä edeltävistä ei sopinut. Siten myös laiskassa suoritusjärjestyksessä infinite = case of y -> infinite y [] -> 0 on ikuinen silmukka: sekään ei osaa itse valita jälkimmäistä haaraa, koska edellinenhän sopii aina. Haskell käyttää siis tätä laiskaa suoritusjärjestystä. Normaalilla suoritusjärjestyksellä on myös se etu, että koodia voi manipuloida algebrallisesti miettimättä mitä lisärajoituksia ohjelmointikielen laskentajärjestys aiheuttaa. Toisin sanoen, voi käyttää vapaasti lauseketta, joka määrittelee halutun tuloksen, miettimättä erikseen osaako tämä ohjelmointikieli laskea sen tuloksen kyllä se osaa! 121

19 Haskell ei myöskään laske vastauksiaan siihen oikeaan normaalimuotoon saakka, jossa kaikki mahdolliset β-reduktiot olisi tehty. Sen sijaan Haskell tyytyykin ns. heikkoon päänormaalimuotoon (weak head normal form, WHNF) jossa lopetetaankin heti, kun normaali sievennysjärjestys ehdottaisi soveltamaan β-reduktiota seuraavaksi sellaiseen kohtaan, joka on... jonkin λ:n sisällä, eli kun lauseke on sieventynyt muotoon λ.((λy.e) f) eli funktioksi, jonka laskenta etenee vasta kun se saa argumentin, koska vasta tämän argumenttinsa saatuaan tämä funktio tietäisi, mitä osia se siitä oikein tarvitseekaan, ja Haskell-laskennanhan määräävät tietoriippuvuudet. jonkin perusoperaation kutsu, mutta sillä on liian vähän argumentteja, joten sitä ei voi suorittaa tätä pidemmälle, kuten vaikkapa sektiota (5 +). jonkin datatyyppinä määritellyn algebrallisen tietotyypin konstruktori, jolla myös on liian vähän argumentteja, joten sitäkään ei voi suorittaa tätä pidemmälle. Muuten jatketaan tekemällä se ehdotettu β-reduktio, jne. Kun sievennettävä Haskell-lauseke h ei olekaan funktiotyyppiä vaan perustyyppiä kuten Integer niin silloin sen WHNF on vastaava arvo. algebrallista tyyppiä niin silloin sen WHNF saadaan sieventämällä sitä kunnes selviää, mikä tämän tyypin konstruktoreista on lausekkeen h alussa. Esimerkiksi jos h :: Maybe Integer niin silloin sen WHNF saadaan sieventämällä, kunnes selviää onko se Nothing vaiko jotakin muotoa Just n. Jos jälkimmäistä, niin sen kentän sisältö n on yhä sieventämättä ellei sisällön n sieventäminen ollut välttämätöntä koko lausekkeen h konstruktorin selvittämiseksi. Vastaavasti case-lausekkeen hahmo t ovatkin muotoa Konstruktori... koska ne kysyvät onko lausekkeen h Konstruktorina tämä? Myös tulkissa ghci käyttäjän kirjoittamaa lauseketta h sievennetään vain sen heikkoon päänormaalimuotoon mutta jos tämä h onkin sellaista tyyppiä, joka kuuluukin tyyppiluokkaan Show, niin silloin ghci alkaakin vielä muuntamaan sieventämäänsä tulosta lausekkeelle h vielä merkkijonoksi, jonka se tulostaa käyttäjälle. Tämä muunnos merkkijonoksi taas aiheuttaa sen, että lausekkeen h tulos sievennetäänkin loppuun saakka koska tämän tulostettavan merkkijonon WHNF puolestaan tarvitsee kaikki merkit siitä merkkijonosta, jonka tuottaa kutsu show h. 8.3 Ahkeruuden osoittaminen Haskell-ohjelmassa Haskell tarjoaa primitiivin, jolla ohjelmoija voi ilmoittaa haluavansa, että jokin ohjelman osa suoritetaankin ahkerasti. Kaikkein matalimman abstraktiotason primitiivi on seq :: a -> t -> t 122

20 jonka tulkinta on sievennä ensimmäinen argumentti tyyppiä a heikkoon päänormaalimuotoonsa w ja palauta tuloksena toinen argumentti tyyppiä b sellaisenaan. Siis Haskell suorittaa ensimmäisen argumenttinsa sivuvaikutuksenaan vaikkei se ole tarpeen tuloksen tekemiseksi. Onneksi Haskell tarjoaa myös tämän primitiivin päälle rakennettuja korkeamman abstraktiotason tapoja ilmaista ahkeruutta. Yksi tällainen tapa ovat Preluden operaattorit ($), ($!) :: (a -> b) -> a -> b f $ = f f $! = seq f joista $ onkin jo tuttu sehän vain kutsuu funktiota f parametrilla normaalisti eli laiskasti $! siis 1. ensin normalisoi parametrin heikkoon päänormaalimuotoonsa w 2. sitten kutsuu funktiota f tällä w. Näillä operaattoreilla on sitten lisätty datatyyppimäärittelyihin mahdollisuus sanoa, että käsittelekin tämä kenttä ahkerasti : Kentän tyypin voi aloittaa huutomerkillä!. Silloin lausekkeessa Konstruktori kenttään 1 kenttään 2 kenttään 3... kenttään k kunkin kentän eteen tulee operaattori ($!) jos sen tyyppi alkaa! ja muuten ($). Silloin esimerkiksi seuraava datatyyppimäärittely on sellain hakupuutyyppi, joka rakennetaankin ahkerasti eikä laiskasti: Funktiossa lisaa konstruktori Solmu normalisoi huutomerkkiensä! vuoksi rekursiokutsunsa lisaa y vasen (ja oikea) tuloksen. Siten se normalisoi jokaisen alipuunsa juuren. Siten rekursio tuottaa puun, jonka jokainen alipuu on kokonaan normalisoitu. data Puu k t = Tyhja Solmu!(Puu k t) k t!(puu k t) deriving (Show) lisaa :: (Ord k) => k -> t -> Puu k t -> Puu k t lisaa y Tyhja = Solmu Tyhja y Tyhja lisaa y haara@(solmu vasen avain tieto oikea) < avain = Solmu (lisaa y vasen) avain tieto oikea > avain = Solmu vasen avain tieto (lisaa y oikea) otherwise = haara 123

21 Nämä huutomerkit! datatyyppimäärittelyissä ovat jo nyt Haskell-standardissa. Seuraavaan Haskell-standardiin on ehdotettu tällaisten huutomerkkien! sallimista myös hahmoissa (bang patterns) ja ghc toteuttaakin sen yhtenä laajennuksistaan. Silloin voisi kirjoittaa hahmon muotoa!muuttuja tai!_ tarkoittamaan vaivatta, että normalisoi tämä osa heikkoon päänormaalimuotoonsa, vaikka se ei olekaan tarpeen. Haskell-kääntäjän kuten ghc koodin optimoinnin yhtenä työvaiheena on ahkeruusanalyysi (strictness analysis). Se lähtee liikkeelle näistä ohjelmoijan ilmoittamista huutomerkeistä! ja analysoi niiden perusteella, mitkä kaikki muutkin ohjelman osat pitää niiden seurauksena suorittaa ahkerasti Se siis sirottelee ohjelmaan omin päin lisää seq-kutsuja tehostaakseen sitä. Ahkerasta ohjelmakoodista voi nimittäin tuottaa tehokkaampaa konekoodia kuin laiskasta, koska siitä voi jättää pois laiskuuden vaatiman lisäkirjanpidon. Tämä on yksi sellainen optimointivaihe, jota ahkeran kielen kääntäjässä ei ole. Tätä huutomerkkiä! ei kuitenkaan voi käyttää tyyppimäärittelyssä newtype Nimi = Konstruktori Tyyppi vaan tämän uudennimi sen tyypin ahkeruuden tai laiskuuden määrää se olemassa oleva Tyyppi jonka se sisältää. Siten newtype tekee uudennimi sen tyypin joka käyttäytyy laskennassa samoin kuin tämä Tyyppi. Tämä pätee myös silloin kun tällä uudennimisellä tyypillä on tyyppiparametreja. Vastaavanlainen datatyypinmäärittely tekisikin uuden tyypin, joka olisikin laiska, ellei huutomerkillä! muuta ilmaista. Siis sen käyttäytyminen laskennassa määräytyykin datatyyppimäärittelyn perusteella eikä noudattamalla Tyyppiä. Tämä onkin newtype- ja datatyyppimäärittelyjen perustava ero. Tarkastellaan lopuksi esimerkkinä ahkeruuden tehostavasta vaikutuksesta lukulistan yhteenlaskua. Koska (+) on assosiatiivinen, niin voimme valita vapaasti kumpaa foldia käytämme. Valintamme on foldl koska sehän on intuitiivisesti pelkkä silmukka kun taas foldr olisi aitoa rekursiota : foldl :: (a -> b -> a) -> a -> [b] -> a foldl f z [] = z foldl f z (:s) = foldl f (f z ) s foldr :: (a -> b -> b) -> b -> [a] -> b foldr f z [] = z foldr f z (:s) = f (foldr f z s) 124

22 Lasketaan sitten käsin esimerkkiä normaalissa järjestyksessä: foldl (+) 0 [ 1, 2, 3,..., n ] = βfoldl (+) (0 + 1 ) [ 2, 3,..., n ] = βfoldl (+) ((0 + 1 ) + 2 ) [ 3,..., n ] (16) = βfoldl (+) ((...(((0 + 1 ) + 2 ) + 3 )...) + n ) [] = β((...(((0 + 1 ) + 2 ) + 3 )...) + n ). Eihän tämä laskenta ollutkaan lainkaan tehokasta sehän teki vain vasemmalle vinon kopion oikealle vinosta syötelistastaan! Miksi? Koska näitä välisummia ei tarvittu laskennan kuluessa! se + 2 ne + 3. Tämä summalauseke sievennetään arvoonsa vasta kun sitä kysytään ja silloin tehdään oleellisesti saman verran työtä kuin foldl-sievennyksissä. Kirjasto Data.List sisältää onneksi myös funktion foldl :: (a -> b -> a) -> a -> [b] -> a foldl f z [] = z foldl f z (:s) = let z = z f in seq z $ foldl f z s joka siis sanoo, että sievennä lisäksi joka askeleessa tämänhetkinen välitulos z heikkoon päänormaalimuotoonsa. Koska nyt tämän välituloksen tyyppi on numero, niin sen sievennys laskee kyseisen välituloksen arvon. Sen laskenta eteneekin siis seuraavasti: jossa foldl (+) 0 [ 1, 2, 3,..., n ] = βfoldl (+) (0 + 1 ) [ 2, 3,..., n ] = β foldl (+) z 1 [ 2, 3,..., n ] = βfoldl (+) (z ) [ 3,..., n ] = β foldl (+) z 2 [ 3,..., n ] = βfoldl (+) z n [] = βz n z i = i on tämän välisumman arvo joka on siis nyt yksi luku. Nyt laskentamme etenee kuten haluamme: tehokkaana silmukkana. 125

23 8.4 Muistin käyttö ja välitulosten jakaminen Edellinen foldl -esimerkki osoitti myös, että laiskan laskennen muistinkäyttökin saattaa tuottaa yllätyksiä: foldl synnyttikin muistiin kokonaisen sieventämättömän summalausekkeen. Tutustutaan siksi lyhyesti myös siihen, miten laiska laskenta käsittelee muistia. Otetaan yksinkertaiseksi esimerkiksemme kahdennusfunktio double :: Int -> Int double = + ja lausekkeen double (double (double 1)) arvon laskenta. Normaalissa järjestyksessä β-reduktio kohdistuu aina vasemmanpuoleisimpaan mahdolliseen paikkaa eli uloimpaan doubleen: double (double (double 1)) = β (double (double 1)) +(double (double 1)). Mutta laskeeko Haskell tämän välituloslausekkeen (double (double 1))... kerran koska se on paikallisen muuttujan arvona vai kahdesti koska tämä esiintyykin kahdesti doublessa? Vain kerran koska tämän esiintymät jakavat saman kopion välituloslausekkeesta muistissa: + double (double 1) Itse asiassa laiskat ohjelmointikielet käyttävätkin toteutuksissaan verkkoreduktiota (graph reduction) joka on λ-laskentaa verkoilla eli niille määriteltyä β-reduktiota, jotta voidaan esittää rakenteiden jako muistissa, vaikka tekstimuotoisille lausekkeille ilman rakenteiden jakoa se onkin alun perin määritelty. Nyt seuraavaa β-reduktiota sovelletaan normaalin järjestyksen mukaan tämän verkon juureen. Siellä on (+) jolla on molemmat operandit, joten aletaan sieventää sitä heikkoon päänormaalimuotoonsa. 126

24 Mutta sen sievennys tarvitseekin molempien operandiensa arvot, joten ne pitää sieventää ensin omiin päänormaalimuotoihinsa. Sievennetään ensin vasemmanpuoleista operandia. Sieveneekö myös oikea operandi samalla nehän jakavat saman lausekkeen eli aliverkon? Kyllä sievenee, koska vasemman operandin sievennys kirjoittaa tuloksensa siihen samaan muistipaikkaan, jossa lauseke oli ja jonka myös oikea operandi jakaa: + + double 1 Siis vaikka Haskell-kielessä ei olekaan uudelleensijoituslausetta (Monadien ST ja IO ulkopuolella) niin sen ajonaikainen järjestelmä (run-time system, RTS) perustuu uudelleensijoitukseen konekooditasolla. Jatketaan samaan tapaan:

25 Nyt alimman solmun (+) molemmat operandit ovat lukuja 1 eli heikossa päänormaalimuodossaan, joten sekin voidaan vihdoin sieventää omaan heikkoon päänormaalimuotoonsa ja jälleen kirjoittaa tämä tulos siihen muistipaikkaan jossa solmu oli: Nyt voidaan laskea seuraava solmu (+) vastaavasti:

26 Ja lopuksi vielä juurisolmu (+): Kuviin on katkoviivoilla merkitty se, milloin muistin eri osia ei enää tarvita. Silloin ne palautuvat toteutuksen roskankerääjälle (garbage collector) uudelleenkäytettäviksi. Näin Haskell sieventää jokaisen lausekkeen vain kerran. Jos samaan lausekkeeseen on useita viittauksia, niin kaikki muutkin viittaukset hyötyvät yhden kautta tehdystä sievennystyöstä. Koska double-esimerkissämme oli solmun (+) sekä vasempana että oikeana operandina, ja siten niillä yhteinen lauseke, niin vasemman operandin sievennys tuotti samalla myös oikealle operandille arvon. Jos joutuu tarkastelemaan Haskell-ohjelman ajan- tai tilankäytön yksityiskohtia, niin silloin joutuu miettimään näitä jaettuja esityksiä muistissa. Toisaalta silloin Haskell joutuu käyttämään muistia kirjanpitoon siitä, mitkä rakenteet ovat vielä sieventämättä ja mitkä ovat jo valmiit. Lisäksi jokaiseen muistiviittaukseen liittyy lisätyönä kysymys onko sen kohde tämän kirjanpidon mukaan vielä kesken tai jo valmis? Tämän kirjanpidon sekä monimuotoisuuden vuoksi Haskell ylläpitää tietoalkioitaan muistissa laatikoituina (boed). Tällaisessa laatikossa on tilaa sekä kirjanpidolle että tulokselle. Tämä laatikointi on saman kaltaista kuin Javan kaksi kokonaislukulajia: raaka int joka ei ole olio vs. Integer joka on olio joka on laatikko jossa on int sisällä. Kääntäjälle ghci voi antaa valitsimen unbo-strict-fields jolloin se eliminoi tämän laatikoinnin niistä datatyyppien kentistä, joiden alussa on huutomerkki! niitä ei tarvitse laatikoida, koska nehän lasketaan ahkerasti. 129

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

6 Algebralliset tietotyypit

6 Algebralliset tietotyypit Nyt voitaisiin kirjoittaa instance Functor Set where type Inv Set e = (Ord e) fmap = map jossa metodin tyyppi onkin nyt fmap :: (Ord a,ord b) => (a -> b) -> Set a -> Set b joka onkin nyt samaa tyyppiä

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

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

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

5.2.5 Konstruktoriluokat Edellisessä esimerkissä määrittelimme oman tyyppiluokan Isqrt jonka jäsenet olivat tyyppejä (kuten Int, Integer, Word,...).

5.2.5 Konstruktoriluokat Edellisessä esimerkissä määrittelimme oman tyyppiluokan Isqrt jonka jäsenet olivat tyyppejä (kuten Int, Integer, Word,...). 5.2.5 Konstruktoriluokat Edellisessä esimerkissä määrittelimme oman tyyppiluokan Isqrt jonka jäsenet olivat tyyppejä (kuten Int, Integer, Word,...). Voimme määritellä tyyppiluokkia myös tyyppikonstruktoreille

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

Monadeja siellä, monadeja täällä... monadeja kaikkialla? TIES341 Funktio ohjelmointi 2 Kevät 2006

Monadeja siellä, monadeja täällä... monadeja kaikkialla? TIES341 Funktio ohjelmointi 2 Kevät 2006 Monadeja siellä, monadeja täällä... monadeja kaikkialla? TIES341 Funktio ohjelmointi 2 Kevät 2006 Materiaalia Paras verkkomatsku: http://www.nomaware.com/monads/html/ Komentoanalogiasta vielä Monadityypin

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

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

5.5 Jäsenninkombinaattoreista

5.5 Jäsenninkombinaattoreista 5.5. JÄSENNINKOMBINAATTOREISTA 67 type Env α = FiniteMap String α data EnvT m α = MkE (Env Integer m (Env Integer, α)) instance Transformer EnvT where promote mp = MkE $ λenv mp λr return $(env, r) instance

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

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

Lisää laskentoa. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Lisää laskentoa. TIEA341 Funktio ohjelmointi 1 Syksy 2005 Lisää laskentoa TIEA341 Funktio ohjelmointi 1 Syksy 2005 Kertausta: Laajennettu aritmetiikka Lasketaan rationaaliluvuilla vakiot yhteen, vähennys, kerto ja jakolasku Laajennetaan sitä määrittelyillä: vakio

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

Uusi näkökulma. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Uusi näkökulma. TIEA341 Funktio ohjelmointi 1 Syksy 2005 Uusi näkökulma TIEA341 Funktio ohjelmointi 1 Syksy 2005 Aloitetaan alusta... Otetaan uusi näkökulma Haskelliin ohjelmointi laskentana kertausta toisaalta, uusia käsitteitä toisaalta helpottanee sitten

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

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

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

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

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

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

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

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

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

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

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

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

Algoritmit 2. Luento 2 Ke Timo Männikkö

Algoritmit 2. Luento 2 Ke Timo Männikkö Algoritmit 2 Luento 2 Ke 15.3.2017 Timo Männikkö Luento 2 Tietorakenteet Lineaarinen lista, binääripuu Prioriteettijono Kekorakenne Keko-operaatiot Keon toteutus taulukolla Algoritmit 2 Kevät 2017 Luento

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

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 10 Todistamisesta Antti-Juhani Kaijanaho Jyväskylän yliopisto Tietotekniikan laitos 21. tammikuuta 2008 Samuuden todistaminen usein onnistuu ihan laskemalla

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

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

Vasen johto S AB ab ab esittää jäsennyspuun kasvattamista vasemmalta alkaen:

Vasen johto S AB ab ab esittää jäsennyspuun kasvattamista vasemmalta alkaen: Vasen johto S AB ab ab esittää jäsennyspuun kasvattamista vasemmalta alkaen: S A S B Samaan jäsennyspuuhun päästään myös johdolla S AB Ab ab: S A S B Yhteen jäsennyspuuhun liittyy aina tasan yksi vasen

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

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

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 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

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

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

Luku 5. Monadit. 5.1 Siirrännän ongelma

Luku 5. Monadit. 5.1 Siirrännän ongelma Luku 5 Monadit There are lots of books about functional programming in Haskell. They tend to concentrate on the beautiful core of functional programming: higher order functions, algebraic data types, polymorphic

Lisätiedot

TIEA241 Automaatit ja kieliopit, kesä Antti-Juhani Kaijanaho. 26. kesäkuuta 2013

TIEA241 Automaatit ja kieliopit, kesä Antti-Juhani Kaijanaho. 26. kesäkuuta 2013 ja ja TIEA241 Automaatit ja kieliopit, kesä 2012 Antti-Juhani Kaijanaho TIETOTEKNIIKAN LAITOS 26. kesäkuuta 2013 Sisällys ja ja on yksi vanhimmista tavoista yrittää mallittaa mekaanista laskentaa. Kurt

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

Algoritmit 2. Luento 2 To Timo Männikkö

Algoritmit 2. Luento 2 To Timo Männikkö Algoritmit 2 Luento 2 To 14.3.2019 Timo Männikkö Luento 2 Tietorakenteet Lineaarinen lista, binääripuu Prioriteettijono Kekorakenne Keko-operaatiot Keon toteutus taulukolla Algoritmit 2 Kevät 2019 Luento

Lisätiedot

Luku 2. Ohjelmointi laskentana. 2.1 Laskento

Luku 2. Ohjelmointi laskentana. 2.1 Laskento Luku 2 Ohjelmointi laskentana Funktio-ohjelmoinnin, olio-ohjelmoinnin ja käskyohjelmoinnin ero on löydettävissä niiden pohjalla olevista laskennan mallista. Automaattisen tietojenkäsittelyn yksi historiallinen

Lisätiedot

Algoritmit 2. Luento 7 Ti Timo Männikkö

Algoritmit 2. Luento 7 Ti Timo Männikkö Algoritmit 2 Luento 7 Ti 4.4.2017 Timo Männikkö Luento 7 Joukot Joukko-operaatioita Joukkojen esitystapoja Alkiovieraat osajoukot Toteutus puurakenteena Algoritmit 2 Kevät 2017 Luento 7 Ti 4.4.2017 2/26

Lisätiedot

8.5 Takarekursiosta. Sanoimme luvun 8.3 foldl -esimerkissämme että

8.5 Takarekursiosta. Sanoimme luvun 8.3 foldl -esimerkissämme että 85 Takarekursiosta Sanoimme luvun 83 foldl -esimerkissämme että foldl :: (a -> b -> a) -> a -> [b] -> a foldl f z [] = z foldl f z (x:xs) = foldl f (f z x) xs olisi pelkkä silmukka Tämä johtuu siitä, että

Lisätiedot

14.1 Rekursio tyypitetyssä lambda-kielessä

14.1 Rekursio tyypitetyssä lambda-kielessä Luku 14 Rekursiiviset tyypit Edellisessä luvussa esitetyt tietue- ja varianttityypit eivät yksinään riitä kovin mielenkiintoisten tietorakenteiden toteuttamiseen. Useimmissa ohjelmissa tarvitaan erilaisia

Lisätiedot

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä Ohjelmoinnin peruskurssien laaja oppimäärä Luento 3: Funktionaalinen listankäsittely ja listankäsittelyoperaatiot (mm. SICP 22.2.3) Riku Saikkonen 31. 10. 2011 Sisältö 1 Linkitetyt listat 2 Listarakenteet

Lisätiedot

Hahmon etsiminen syotteesta (johdatteleva esimerkki)

Hahmon etsiminen syotteesta (johdatteleva esimerkki) Hahmon etsiminen syotteesta (johdatteleva esimerkki) Unix-komennolla grep hahmo [ tiedosto ] voidaan etsia hahmon esiintymia tiedostosta (tai syotevirrasta): $ grep Kisaveikot SM-tulokset.txt $ ps aux

Lisätiedot

5.3 Laskimen muunnelmia 5.3. LASKIMEN MUUNNELMIA 57

5.3 Laskimen muunnelmia 5.3. LASKIMEN MUUNNELMIA 57 5.3. LASKIMEN MUUNNELMIA 57 Samaan sarjaan kuuluu seuraavakin funktio, jonka määritelmä esittelee muutenkin hyödyllisen tavan kirjoittaa ohjelmia: getline :: IO String getline = getchar λc case c of \n

Lisätiedot

T Syksy 2004 Logiikka tietotekniikassa: perusteet Laskuharjoitus 7 (opetusmoniste, kappaleet )

T Syksy 2004 Logiikka tietotekniikassa: perusteet Laskuharjoitus 7 (opetusmoniste, kappaleet ) T-79144 Syksy 2004 Logiikka tietotekniikassa: perusteet Laskuharjoitus 7 (opetusmoniste, kappaleet 11-22) 26 29102004 1 Ilmaise seuraavat lauseet predikaattilogiikalla: a) Jokin porteista on viallinen

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 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

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

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 peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä Ohjelmoinnin peruskurssien laaja oppimäärä Luento 6: Rajoite-esimerkki, funktionaalista ohjelmointia (mm. SICP 3.3.5, 3.5) Riku Saikkonen 8. 11. 2012 Sisältö 1 SICP 3.3.5 esimerkki: rajoitteiden vyörytysjärjestelmä

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

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 peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä Ohjelmoinnin peruskurssien laaja oppimäärä Luento 5: Sijoituslause, SICP-oliot, todistamisesta (mm. SICP 33.1.3, 3.33.3.2) Riku Saikkonen 7. 11. 2011 Sisältö 1 Muuttujan arvon muuttaminen: set! 2 SICP-oliot

Lisätiedot

Algoritmit 1. Luento 7 Ti Timo Männikkö

Algoritmit 1. Luento 7 Ti Timo Männikkö Algoritmit 1 Luento 7 Ti 31.1.2017 Timo Männikkö Luento 7 Järjestetty binääripuu Binääripuiden termejä Binääripuiden operaatiot Solmun haku, lisäys, poisto Algoritmit 1 Kevät 2017 Luento 7 Ti 31.1.2017

Lisätiedot

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 3. lokakuuta 2016

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 3. lokakuuta 2016 TIEA241 Automaatit ja kieliopit, syksy 2016 Antti-Juhani Kaijanaho TIETOTEKNIIKAN LAITOS 3. lokakuuta 2016 Sisällys n tunnistin Jay : An Efficient Context-Free Parsing Algorithm. Communications of the

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

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 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 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

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

PERL. TIE Principles of Programming Languages. Ryhmä 4: Joonas Lång & Jasmin Laitamäki

PERL. TIE Principles of Programming Languages. Ryhmä 4: Joonas Lång & Jasmin Laitamäki PERL TIE-20306 Principles of Programming Languages Ryhmä 4: Joonas Lång & Jasmin Laitamäki 1. Johdanto Perl on ohjelmointikielten perhe, johon kuuluu Perl 5 ja Perl 6. Kielet ovat kuitenkin erilliset ohjelmointikielet

Lisätiedot

1 Mitä funktionaalinen ohjelmointi on?

1 Mitä funktionaalinen ohjelmointi on? 1 Mitä funktionaalinen ohjelmointi on? On olemassa useita erilaisia ohjelmointiparadigmoja (programming paradigms) koska on useita erilaisia tapoja mallintaa ohjelmointiongelmia, esimerkiksi: Proseduraalinen

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

11/20: Konepelti auki

11/20: Konepelti auki Ohjelmointi 1 / syksy 2007 11/20: Konepelti auki Paavo Nieminen nieminen@jyu.fi Tietotekniikan laitos Informaatioteknologian tiedekunta Jyväskylän yliopisto Ohjelmointi 1 / syksy 2007 p.1/11 Tämän luennon

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

Jäsennys. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Jäsennys. TIEA341 Funktio ohjelmointi 1 Syksy 2005 Jäsennys TIEA341 Funktio ohjelmointi 1 Syksy 2005 Muistutus: Laskutehtävä ja tulos data Laskutehtava = Luku Double Yhteen Laskutehtava Laskutehtava Vahennys Laskutehtava Laskutehtava Tulo Laskutehtava

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

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

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

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

etunimi, sukunimi ja opiskelijanumero ja näillä

etunimi, sukunimi ja opiskelijanumero ja näillä Sisällys 1. Algoritmi Algoritmin määritelmä. Aiheen pariin johdatteleva esimerkki. ja operaatiot (sijoitus, aritmetiikka ja vertailu). Algoritmista ohjelmaksi. 1.1 1.2 Algoritmin määritelmä Ohjelmointi

Lisätiedot

Harjoitustyön testaus. Juha Taina

Harjoitustyön testaus. Juha Taina Harjoitustyön testaus Juha Taina 1. Johdanto Ohjelman teko on muutakin kuin koodausta. Oleellinen osa on selvittää, että ohjelma toimii oikein. Tätä sanotaan ohjelman validoinniksi. Eräs keino validoida

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

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

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

13. Loogiset operaatiot 13.1

13. Loogiset operaatiot 13.1 13. Loogiset operaatiot 13.1 Sisällys Loogiset operaatiot AND, OR, XOR ja NOT. Operaatioiden ehdollisuus. Bittioperaatiot. Loogiset operaatiot ohjausrakenteissa. Loogiset operaatiot ja laskentajärjestys.

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

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

Ehto- ja toistolauseet

Ehto- ja toistolauseet Ehto- ja toistolauseet 1 Ehto- ja toistolauseet Uutena asiana opetellaan ohjelmointilauseet / rakenteet, jotka mahdollistavat: Päätösten tekemisen ohjelman suorituksen aikana (esim. kyllä/ei) Samoja lauseiden

Lisätiedot

TIEA241 Automaatit ja kieliopit, kevät 2011 (IV) Antti-Juhani Kaijanaho. 19. tammikuuta 2012

TIEA241 Automaatit ja kieliopit, kevät 2011 (IV) Antti-Juhani Kaijanaho. 19. tammikuuta 2012 TIEA241 Automaatit ja kieliopit, kevät 2011 (IV) Antti-Juhani Kaijanaho TIETOTEKNIIKAN LAITOS 19. tammikuuta 2012 Sisällys Sisällys Muistathan A B -konstruktion 0 k 1 i 2 s 3 s 4 a 5 0 k 1 o 2 i 3 r 4

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

Python-ohjelmointi Harjoitus 5

Python-ohjelmointi Harjoitus 5 Python-ohjelmointi Harjoitus 5 TAVOITTEET Kerrataan silmukkarakenteen käyttäminen. Kerrataan jos-ehtorakenteen käyttäminen. Opitaan if else- ja if elif else-ehtorakenteet. Matematiikan sisällöt Tehtävät

Lisätiedot

Datatähti 2019 loppu

Datatähti 2019 loppu Datatähti 2019 loppu task type time limit memory limit A Summa standard 1.00 s 512 MB B Bittijono standard 1.00 s 512 MB C Auringonlasku standard 1.00 s 512 MB D Binääripuu standard 1.00 s 512 MB E Funktio

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

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

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 perusteet Y Python

Ohjelmoinnin perusteet Y Python Ohjelmoinnin perusteet Y Python T-106.1208 11.2.2009 T-106.1208 Ohjelmoinnin perusteet Y 11.2.2009 1 / 33 Kertausta: listat Tyhjä uusi lista luodaan kirjoittamalla esimerkiksi lampotilat = [] (jolloin

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

Imperatiivisen ohjelmoinnin peruskäsitteet. Meidän käyttämän pseudokielen lauseiden syntaksi

Imperatiivisen ohjelmoinnin peruskäsitteet. Meidän käyttämän pseudokielen lauseiden syntaksi Imperatiivisen ohjelmoinnin peruskäsitteet muuttuja muuttujissa oleva data voi olla yksinkertaista eli primitiivistä (esim. luvut ja merkit) tai rakenteista jolloin puhutaan tietorakenteista. puhuttaessa

Lisätiedot

1. Algoritmi 1.1 Sisällys Algoritmin määritelmä. Aiheen pariin johdatteleva esimerkki. Muuttujat ja operaatiot (sijoitus, aritmetiikka ja vertailu). Algoritmista ohjelmaksi. 1.2 Algoritmin määritelmä Ohjelmointi

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

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