7.5 Monadimuuntimet. Vaikka monadinen tyypitus on monoliittista, niin monadit voi suunnitella ja toteuttaa hierarkisesti.

Koko: px
Aloita esitys sivulta:

Download "7.5 Monadimuuntimet. Vaikka monadinen tyypitus on monoliittista, niin monadit voi suunnitella ja toteuttaa hierarkisesti."

Transkriptio

1 7.5 Monadimuuntimet Vaikka monadinen tyypitus on monoliittista, niin monadit voi suunnitella ja toteuttaa hierarkisesti. Sitä varten ghc tarjoaa monadimuuntimet (monadic transformers) (O Sullivan et al., 2008, luku 18). Jos M ja N ovat monadeja, niin N (M a) on sellaisen monadin tyyppi, jossa ulompi monadi N tuottaa vastauksen tyyppiä M a jossa sisempi monadi M esittää sellaisen laskennan, jonka vastaus on a. Silloin tämä ulompi tyyppi N onkin sellainen, joka ottaa sisäänsä toisen monadin M antaa tuloksenaan uuden monadin, jossa sisään otettua monadia M on täydennetty uusilla ominaisuuksilla. Eri monadimuuntimet N voivat siten esittää eri täydennystapoja, ja haluttu monadi koota niitä pinoamalla B (...(O (N (M a)))...). Kun laskennassa halutaan käyttää jotakin sisämonadin operaatiota niin sen käyttö tulos <- operaatio kirjoitetaankin muodossa tulos <- lift $ operaatio jossa tämän monadimuuntimen t metodi lift :: (Monad m, MonadTrans t) => m a -> t m a nostaa tämän operaation sisämonadista m=m ulkomonadin operaatioksi. ulkomonadin operaatiota niin se on käytössä suoraan ilman nostamista. Siten monadimuuntimen t käyttö koostuu sellaisen tyypin kirjoittamisesta, jossa uloimpana on t ja sisällä sisämonadin tyyppi sisämonadista tarvittavien operaatioiden nostamisesta. ghc tarjoaa Control.Monad-kirjastoissaan monia tällaisia muuntimia. Esimerkkinä täydennetään monadia ST virheenkäsittelymekanismilla, jonka tarjoaa monadimuunnin ErrorT kirjastosta Control.Monad.Error. Ulkomonadimme tyyppi on muotoa ErrorT virheilmoitustyyppi sisämonadi vastaustyyppi Me käytämme virheilmoitustyyppinämme Stringiä. Meidän sisämonadimme on ST s jossa s on se eksistentiaalikvantifioitava tyyppiparametri. 122

2 Meidän tyyppimme omat parametrit ovat tämä s ja sama vastaustyyppi. newref1 on esimerkkinä sisämonadimme ST s operaation nostamisesta ulkomonadiimme. throwerror taas on esimerkki uudesta ominaisuudesta jonka tämä muunnin lisäsi sisämonadiimme. import Control.Monad.Error import Control.Monad.ST import Data.STRef type ErrorST s a = ErrorT String (ST s) a newref1 :: a -> ErrorST s (STRef s a) newref1 = lift. newstref suojattu1 :: Double -> Either String Bool suojattu1 x = runst $ runerrort $ do y <- newref1 True if x<0 then throwerror "Ei negatiivisia!" else return $ x>0 Tämän ulkomonadimme suoritusfunktio on runerrorst :: ErrorST s a -> Either String a runerrorst = runst. runerrort kuten suojattu1 osoittaa. Sen tulos on siis joko Left virheilmoitusteksti tai Right vastaus. Tällaisen suoritusfunktion rakenne on vastaava tyyppi toisinpäin: Tyypin N (M a) suoritusfunktio on muotoa runm (runn...) koska N-laskenta tuottaa M-laskennan joka tuottaa vastauksen. Tällaisen suoritusfunktion kirjoittaminen on hyvää ohjelmointityyliä. Valitettavasti runst:n tyypin eksistenssikvantifiointi aiheuttaa sen, ettei Haskell pystykään päättelemään tätä tyyppiä omin voimin. Tämän ongelman voisi kiertää kirjoittamalla operaattorin (.) tälle käyttötilanteelle käsin sen tämänhetkisen tyypin (kvanttoreineen) mutta sivuutamme sen nyt. 123

3 Tämä monadimuunnin ErrorT laajentaakin aiempaa monadia Maybe :: * -> * joka toteutti yksinkertaiset poikkeukset. Mayben virhetilanne Nothing ei sisällä lisäinformaatiota poikkeuksen syystä. Monadi Either e :: * -> * sisältää tämän lisäinformaation tyyppiä e. Sen jäsenyys voisi siis alkaa instance Monad (Either e) where (Right x) >>= k = k x j@(left _) >>= _ = j return = Right Mayben jäsenyyden pohjalta. Voimme vielä parantaa tyyppiturvallisuutta määrittelemällä kokonaan uuden tyypin joka käyttää monadimuunninta vain sisäisesti. Voimme tehdä sen newtypenä, koska tyypillämme on vain yksi kenttä, eli se muuntimella luomamme monadi. Meidän on liitettävä oma tyyppimme tyyppiluokan Monad jäseneksi. Meidän on liitettävä oma tyyppimme myös tyyppiluokan MonadError jäseneksi, jotta sillä olisi ne muuntimen lisäämät ominaisuudet kuten throwerror. ghc ilmoittaa mitkä instancet vielä tarvitaan. Nämä puuttuvat instancet saadaan puolestaan vaivatta deriving-mekanismilla ja kielilaajennuksella GeneralizedNewtypeDeriving joka monipuolisti sitä newtypeille. {-# LANGUAGE GeneralizedNewtypeDeriving #-} import Control.Monad.Error import Control.Monad.ST import Data.STRef newtype ErrST s a = ErrST{ errst :: ErrorT String (ST s) a } deriving(monad,monaderror String) runerrst = runerrort. errst newref2 :: a -> ErrST s (STRef s a) newref2 = ErrST. lift. newstref suojattu2 x = runst $ runerrst $ 124

4 do y <- newref2 True if x<0 then throwerror "Ei negatiivisia!" else return $ x>0 Haskell Platformin kirjasto Control.Monad.State tarjoaa erityisen kätevän monadimuuntimen StateT. Se lisää monadiseen koodiin taustaparametrin joka kulkee automaattisesti monadisen suorituksen rinnalla ilman lisäohjelmointia. Ohjelmoija voi siis käsitellä tätä taustaparametria monadisessa koodissaan silloin kun hän itse haluaa, eikä hänen tarvitse muulloin ottaa sitä erikseen huomioon. Sen monadisia operaatioita ovat esimerkiksi get joka lukee taustaparametrin nykyisen arvon put joka korvaa sen nykyisen arvon uudella Sen run-funktioita ovat esimerkiksi runstatet tämä alkuarvo joka suorittaa tämän laskennan tällä taustaparametrin alkuarvolla ja tuottaa parin (vastaus,loppuarvo) evalstatet tämä alkuarvo jonka tulos onkin pelkkä vastaus execstatet tämä alkuarvo jonka tulos onkin pelkkä loppuarvo. Samassa kirjastossa on myös monadi State joka tarjoaa samat palvelut. Se on määritelty lyhenteenä type State s = StateT s Identity eli tämän monadimuuntimen soveltamisena monadiin... Identity joka on siinä mielessä tarpeeton monadi, että se ei sisällä mitään omaa laskentaa. Identity on kuitenkin monadimuuntimissa hyödyllinen monadi, koska tällä tavalla saadaan myös monadi M monadimuuntimen MT sivutuotteena. 7.6 Monadinen jäsennys Jäsennys (parsing) on syötteenä saadun merkkijonon muuntamista sitä vastaavaksi jäsennyspuuksi (tai muuksi semanttiseksi rakenteeksi ) annetun kieliopin mukaisesti. Se on epädeterminististä laskentaa, koska kielioppi voi olla moniselitteinen eli sallia samalle merkkijonolle monta eri jäsennystä ja jäsennyspuuta jäsennettäessä merkkijonoa alusta eteenpäin voi paikallisesti olla useita eri lupaavia tapoja jatkaa jäsennystä, vaikka yksiselitteinen kielioppi sulkisikin lopulta pois kaikki muut kuin yhden niistä. 125

5 Aiemmin näimme, että tällaisen epädeterministisen laskennan eri vaihtoehdot voi esittää Haskell-listana, jonka jokainen alkio on yhden epädeterminisen laskennan välitilanne. Jäsennyksessä tällainen välitilanne on pari (taimi,loppuosa) jossa taimi on se jäsennyspuun osa, joka on koottu jo käsitellystä merkkijonon alkuosasta loppuosa merkkijonosta, joka on vielä jäsentämättä. Lopputilanne on silloin pari (jäsennyspuu,""). Dr. Seussin the Cat in the Hat sanoisi tämän: A parser for Things is a function from Strings to lists of pairs of Things and Strings. Haskellilla sama tyyppi ilmaistaan type Parser t = String -> [(t,string)]. Epädeterminisyyden lisäksi jäsennys on monadista toisestakin syystä: Jäsennyksessä on luonteva peräkkäisjärjestys jäsennä ensin merkkijonon alkuosa tällä tavalla ja jatka sitten jäljelle jääneen loppuosan jäsentämistä tuolla tavalla. Tätä lähestymistapaa jäsennykseen kutsutaan monadisiksi jäsenninkombinaattoreiksi (monadic parser combinators) koska jokainen yksittäinen jäsennin on monadinen mutkikkaammat jäsentimet kootaan yhdistelemällä yksinkertaisempia jäsentimiä toisiinsa. Voisimmekin ryhtyä itse kehittämään tätä jäsennystapaa kirjoittamalla määritelmät newtype Parser t =... instance Monad Parser where... mutta kun mukaan lisätään vielä jäsennysvirheiden käsittely Eitherilla kuten edellä, niin on vaivattomampaa ryhtyä käyttämään valmista työkalua. Haskell Platform sisältää raskaan sarjan jäsennystehtäviin erilliset työkalut Happy joka on Haskell-vastine UNIXin yacc- ja GNUn bison-työkalulle. Ne ovat metakääntäjiä (metacompiler) jotka tekevät annetulle kontekstittomalle (LA)LR-kieliopille kokoavan (bottom-up) jäsentäjän. Esimerkiksi ghc itse on toteutettu sen avulla. Alex joka on Haskell-vastine UNIXin lex- ja GNUn flex-työkalulle. Raskaan sarjan jäsentäminen jaetaan kahteen vaiheeseen: 126

6 selaukseen jossa syötemerkkijono kootaan suuremmiksi yksiköiksi, kuten ohjelmointikielissä varatuiksi sanoiksi, muuttujannimiksi,... Tässä vaiheessa poistetaan myös sellaiset osat joiden ei haluta näkyvän enää jäsennysvaiheessa, eli välilyönnit, rivinvaihdot, kommentit,... jäsennykseen joka jäsentää näin saadun suurempien yksikköjen listan. Nämä työkalut tuottavat selaajan, kun annetaan jäsennettävän kielen perusalkioiden kuvaus säännöllisinä lausekkeina. Niiden sijaan tutustummme keskiraskaan sarjan jäsennystehtäville sopivaan Haskell Platformin jäsenninkombinaattorikirjastoon Text.Parsec. (O Sullivan et al., 2008, luku 16) Jäsenninkombinaattorit ovat rekursiivisesti etenevää (recursive descent) jäsennystä. Rekursiivisesti etenevä jäsennys on osittavaa (top-down) ja se soveltuu LLkieliopeille. Emme kytke Parseciin erillistä selaajaa, vaan varaudumme itse kieliopissamme välilyönteihin yms. Haskell Platfrom sisältää myös kirjaston Data.Attoparsec joka käyttää samaa lähestymistapaa jäsennykseen tuottaa tehokkaampia jäsentäjiä vaatii enemmän ohjelmointia kuin Parsec. Muistutetaan mieliin kontekstittoman kieliopin idea: Se koostuu säännöistä muotoa välikesymboli vaihtoehto vaihtoehto vaihtoehto. vaihtoehto joka sanoo, että tällä välikesymbolilla on (vain) nämä vaihtoehdot. Jokainen vaihtoehto on puolestaan (äärellinen) jono muotoa symboli symboli symboli... symboli jonka jokainen symboli on joko välike- tai päätesymboli. Jokin näistä välikesymboleista on erityinen alkusymboli. Sitä on tapana merkitä S. Tällaisen kieliopin välikesymbolin A tuottamat johdokset määritellään induktiivisesti (eli kielioppisääntöjen pienimpänä kiintopisteenä): A itse on johdos. 127

7 Jos symbolijono muotoa αbγ on välikesymbolin A tuottama johdos, ja kieliopissa on sääntö muotoa B... β... niin myös symbolijono αβγ on välikesymbolin A tuottama johdos. Välikesymbolin A tuottama kieli koostuu niistä päätesymbolijonoista jotka ovat välikesymbolin A tuottamia johdoksia. Tällaisen kieliopin tuottama kieli on sen alkusymbolin S tuottama kieli. Tällaisen kieliopin tunnistusongelma on Tässä on päätesymbolijono δ. Kuuluuko se kielioppisi tuottamaan kieleen? jäsennysongelma on Tässä on päätesymbolijono δ. Voitko jäljittää sen tavan, miten alkusymbolisi S tuotti tämän johdoksen δ? Tämä tapa voidaan esittää jäsennyspuuna. Nämä jäsennyspuut voidaan esittää luontevasti algebrallisilla tietotyypeillä. Useimmiten haluammekin muuntaa syötemerkkijonon δ sitä vastaavaksi algebrallisen tietotyypin arvoksi. Toisin sanoen, haluammekin toteuttaa saman, jonka metodi read :: (Read a) => String -> a tekee, mutta omalla (eikä Haskellin) kieliopilla algebrallisen tietotyypin a arvojen tekstiesitykselle. Rekursiivisesti etenevän jäsentämisen perusidea on: Jokaiselle välike- ja päätesymbolille ohjelmoidaan sen oma rekursiivinen aliohjelma. Välikesymbolin A aliohjelman tehtävänä on lukea jäljellä olevan syötteen alusta jokin sen tuottama päätesymboleista koostuva johdos. Päätesymbolin aliohjelman tehtävänä on lukea jäljellä olevan syötteen alusta sen tekstiesitys. Nämä aliohjelmat kutsuvat rekursiivisesti toisiaan siten kuin kielioppi esittää. Tavallisesti sen ohjelmointi ennustavana (predictive) vaatii, että kielioppi täyttää LL(k)-ehdon, jonka mukaan tällainen välikesymbolin A aliohjelma voi valita sen säännössä muotoa A α 1 α 2 α 3... α p juuri oikean vaihtoehdon α i tutkimalla vain seuraavaa k syötemerkkiä tavallisesti tämä kurkistus (lookahead) k = 1. Haskellin epädeterminismi- eli listamonadi syötemerkkijonon käsittely laiskana merkkilistana kuten getcontents do-syntaksi 128

8 osoittavat toisen tavan valita vaihtoehto α i kuin LL(k): Seurataan epädeterministisesti eri vaihtoehtoja α 1, α 2, α 3,...,α p kunnes joku niistä onnistuu. Tämä epädeterminismi ja siihen liittyvä syötemerkkijono käsittely piilotetaan jäsennysmonadin sisälle. Silloin jokainen vaihtoehto α j voidaan kirjoittaa jäsennysmonadisena do-lausekkeena ja koko välikesymbolin A aliohjelma voidaan kirjoittaa yhdistämällä ne toisiinsa sopivalla jäsenninkombinaattorilla joka toteuttaa pystyviivalla esitetyn epädeterministisen valintaoperaation tai. Esimerkkinä olkoon tavalliset aritmeettiset lausekkeet S SAB B B BCD D D (S) e x A + - C * / jossa e on liukulukuvakio x on muuttujannimi. Niiden rakennetta ei tavallisesti kuvata kieliopissa, koska säännölliset lausekkeet riittäisivät siihen ne käsitellään tavallisesti selaajassa eikä jäsentäjässä jäsennetään ne Haskellin selaajalla, jonka Parsec tarjoaa valmiina. Kirjoitamme systemaattisesti jokaiselle välikesymbolille X jäsennysfunktion nimeltä parsex. sellaisen kutsut muodossa x <- parsex jossa x on sen palauttama semanttinen tulos. välikesymbolin X vaihtoehdot muodossa parsex = do a <- parsea b <- parseb c <- parsec return $ sem a b c... X ABC... semantiikkafunktiot jotka kokoavat jäsennyspuun rekursiokutsujen antamista alipuista. Emme vielä tässä vaiheessa rakenna jäsennyspuita, vaan palautamme aina arvon (). 129

9 import Text.Parsec -- Tässä otetaan käyttöön Parsecin Haskell-selaaja. import qualified Text.Parsec.Token as Token import Text.Parsec.Language(haskellDef) lexer = Token.makeTokenParser haskelldef -- "A parser for things..." type Parser thing = Parsec String () thing -- Tässä on jäsennyksen pääohjelma. Se kutsuu alkusymbolin -- jäsennysfunktiota. (Tyhjää) merkkijonoparametria -- käytetään virheilmoituksiin. jasenna = parse (do s <- parses eof -- Jäsentää syötteen lopun. return s) "" parses :: Parser () parses = do s <- parses a <- parsea b <- parseb return () do b <- parseb return () parsea = do char + return () do char - return () parseb = do b <- parseb c <- parsec d <- parsed return () do d <- parsed return () parsec = do char * return () do char / 130

10 return () parsed = do char ( s <- parses char ) return () do e <- Token.float lexer return () do x <- Token.identifier lexer return () Kielioppeihin liitetään kolmenlaisia attribuutteja (attribute) ja niiden muodostussääntöjä. Syntesoidut (synthesized) attribuutit muodostetaan jäsennyspuussa alhaalta ylöspäin lehdistä juureen S päin. Monadisessa jäsennyksessä nämä ovat niitä, jotka palautetaan jäsennysfunktioista parsex returnilla rekursiokutsuista. Vielä nyt ne ovat esimerkissämme() mutta täydennämme ne myöhemmin. Perityt (inherited) attribuutit muodostetaan jäsennyspuussa ylhäältä alaspäin juuresta S lehtiin päin. Monadisessa jäsennyksessä nämä esitetään jäsennysfunktioiden parsex parametreina. Emme tarvitse niitä esimerkissämme. Muut attribuutit ovat taustainformaatiota. Parsecissa ne voidaan esittää kuten monadissa Control.Monad.State. Emme tarvitse niitä esimerkissämme, joten määrittelemme niille tyypin () omassa Parserissamme. Tämä koodi kääntyy mutta jumittuu ikuiseen silmukkaan: parses (ja parseb) kutsuu itseään rekursiivisesti lukematta syötettä. Tämä vasen (left) rekursio on ongelmallista rekursiivisesti enenevälle jäsennykselle. Sitä tarvitaan vasemmalle assosioiville operaattoreille kuten - (ja / ) jolla x y z on (x y) z eikä x (y z). Funktion parses pitäisi arvata sokkona epädeterministisesti oikein, montako vähennyslaskua - syötteessä on tulossa eikä sen listatoteutus siihen pysty, koska se on syvyyssuuntaista etsintää. Tämä ongelma ratkaistaan tavallisesti muuttamalla kielioppia niin, että vasen rekursio poistuu. Parsecissa tämä kieliopin muuttaminen on ohjelmoitu monadisena kontrollirakenteena 131

11 chainl1 :: Parser a -> Parser (a -> a -> a) -> Parser a jolla ketju BABABA... B voidaan kirjoittaa chainl1 parseb parsea joka välttää jumittumisen. import Text.Parsec import Text.Parsec.Combinator -- Tässä otetaan käyttöön Parsecin Haskell-selaaja. import qualified Text.Parsec.Token as Token import Text.Parsec.Language(haskellDef) lexer = Token.makeTokenParser haskelldef -- "A parser for things..." type Parser thing = Parsec String () thing -- Tässä on jäsennyksen pääohjelma. Se kutsuu alkusymbolin -- jäsennysfunktiota. (Tyhjää) merkkijonoparametria -- käytetään virheilmoituksissa. jasenna = parse (do s <- parses eof return s) "" parses :: Parser () parses = chainl1 parseb parsea parsea = do char + return $ \ () () -> () do char - return $ \ () () -> () parseb = chainl1 parsed parsec parsec = do char * return $ \ () () -> () do char / return $ \ () () -> () parsed = Token.whiteSpace lexer >> 132

12 (do s <- Token.parens lexer parses return () (try $ do e <- Token.float lexer return ()) do e <- Token.natural lexer return () do x <- Token.identifier lexer return ()) Lisätään samalla välilyöntien käsittely: Poistetaan välilyönnit yms. Token.whiteSpace ennen välikesymbolia D sen jäsennysfunktiossa parsed. Sen Token-funktiot poistavat ne sen jälkeen. Tämän vuoksi siirrytään käsittelemään myös (S) Token-funktiolla. Token.float jäsentää Haskell-liukulukuvakion, jossa siis pitää olla desimaalipiste. Sallitaan myös (etumerkitön) kokonaislukuvakio Token.natural jotta sitä ei tarvita. Parsecin ei olekaan sama kuin kielioppien. Sen sijaan eka toka tarkoittaakin, että tokaa kokeillaan vain jos eka epäonnistui lukematta yhtään syötettä. Tässä siis yritetään ensin lukea aito liukulukuvakio, mutta jos se epäonnistuu (desimaalipisteen puuttumisen vuoksi) niin sitten yritetään jäsentää samat numeromerkit kokonaislukuvakiona. Jos tarvitaan oikeaa (kuten nyt) niin (try eka) toka muuntaa ekan sellaiseksi jäsentimeksi, joka epäonnistuessaan palauttaa lukemansa syötteen takaisin tokan luettavaksi. Näin tämä Parsecin try sallii LL( )-jäsennyksen, eli sellaisen rekursiivisen jäsennyksen, jossa ei olekaan kiinteää kurkistusylärajaa k. Tämä ero johtuu siitä, että luonnollinen kieli on moniselitteistä (eli saman syötteen voi jäsentää monella eri tavalla) ja mallintaa sitä formaalisti määritellyt kielet (kuten ohjelmointikielet) suunnitellaan yksiselitteisiksi. Tämä ero heijastuu jäsennysvirheiden käsittelyyn: luonnollisessa kielessä pitää silloin kokeilla jotakin toista jäsennystapaa ja tekee niin formaalisti määritellyssä kielessä pitääkin pysähtyä virheilmoitukseen ja tekee niin ohittamalla ne toiset jäsennystavat, kuten monadit Maybe ja Either tekivät. 133

13 Näin välttää turhan ja pahimmassa tapauksessa eksponentiaalisen (!) toisten jäsennystapojen kokeilun. Siis (try eka) toka sanoo, että jos ekassa tulee jäsennysvirhe, niin yritä tokaa vaikka tavallinen reaktio olisikin pysäyttää jäsennys siihen virheeseen. Nyt kun syntaksi on kunnossa siirrymme semantiikkaan. Jäsennyspuun tyyppi voidaan määritellä systemaattisesti määrittelemällä jokaiselle välikesymbolille X oma datatyyppinsä PuuX välikesymbolin X vaihtoehdot muodossa eli X ABC DEF... PuuX = KonstruktoriX1 PuuA PuuB PuuC KonstruktoriX2 PuuD PuuE PuuF... jokaiselle sen vaihtoehdolle oma konstruktori jokaisen konstruktorin kentät samassa järjestyksessä kuin sen vaihtoehdossa symbolit. Tämän taustalla on tietenkin se, että sekä kieliopin että data-määrittelyn on tai vaihdoehdon symboleilla että konstruktorin kentillä on keskinäinen järjestys. Näin sammme systemaattisesti tarkan data-määrittelyn alkuperäisen kielioppimme jäsennyspuille. Koska poistimme siitä vasemman rekursion monadisella kontrollirakenteella chainl1, jäsentimemme käyttääkin implisiittisesti siten muutettua kielioppia, vaikka emme konstruoineetkaan sitä eksplisiittisesti. Siten meidän on muokattava kontrollirakenteen chainl1 käyttöparametreja siten, että ne luovat alkuperäisen kielioppimme mukaisen jäsennyspuun. Se ei kuitenkaan ole työlästä algbrallisilla tietotyypeillä. Tämä on kuitenkin vähemmän mutkikasta kuin muodostaa muutettu kielioppi eksplisiittisesti ja tuottaa sen mukaisia jäsennyspuita, koska haluttu semantiikka on tavallisesti suunniteltu alkuperäisen kieliopin mukaisesti. Tietojenkäsittely- ja formaalissa kielitieteessä erotellaan konkreettinen syntaksi joka kuvaa merkkijonojen rakenteen. abstrakti syntaksi joka kuvaa sen semanttisen puurakenteen, jota merkkijono esittää. Abstrakti syntaksi voidaan nähdä tämän kaltaisena data-määritelmänä jossa ei ole jäänteitä konkreettisesta syntaksista. Jäsennyspuissa on vielä sen jäänteitä. 134

14 import Text.Parsec import Text.Parsec.Combinator -- Tässä otetaan käyttöön Parsecin Haskell-selaaja. import qualified Text.Parsec.Token as Token import Text.Parsec.Language(haskellDef) lexer = Token.makeTokenParser haskelldef -- "A parser for things..." type Parser thing = Parsec String () thing -- Jäsennyspuutyypit. data PuuS = VaihtoehtoS1 PuuS PuuA PuuB VaihtoehtoS2 PuuB deriving (Show) data PuuA = VaihtoehtoA1 VaihtoehtoA2 deriving (Show) data PuuB = VaihtoehtoB1 PuuB PuuC PuuD VaihtoehtoB2 PuuD deriving (Show) data PuuC = VaihtoehtoC1 VaihtoehtoC2 deriving (Show) data PuuD = VaihtoehtoD1 PuuS VaihtoehtoD2 Double VaihtoehtoD3 String deriving (Show) -- Tässä on jäsennyksen pääohjelma. Se kutsuu alkusymbolin -- jäsennysfunktiota. (Tyhjää) merkkijonoparametria -- käytetään virheilmoituksissa. jasenna = parse (do s <- parses eof return s) "" parses :: Parser PuuS parses = chainl1 (fmap VaihtoehtoS2 parseb) parsea parsea :: Parser (PuuS -> PuuS -> PuuS) parsea = do char + return $ \ vasen (VaihtoehtoS2 oikea) -> VaihtoehtoS1 vasen VaihtoehtoA1 oikea do char - return $ \ vasen (VaihtoehtoS2 oikea) -> 135

15 VaihtoehtoS1 vasen VaihtoehtoA2 oikea parseb :: Parser (PuuB) parseb = chainl1 (fmap VaihtoehtoB2 parsed) parsec parsec :: Parser (PuuB -> PuuB -> PuuB) parsec = do char * return $ \ vasen (VaihtoehtoB2 oikea) -> VaihtoehtoB1 vasen VaihtoehtoC1 oikea do char / return $ \ vasen (VaihtoehtoB2 oikea) -> VaihtoehtoB1 vasen VaihtoehtoC2 oikea parsed :: Parser PuuD parsed = Token.whiteSpace lexer >> (do s <- Token.parens lexer parses return $ VaihtoehtoD1 s (try $ do e <- Token.float lexer return $ VaihtoehtoD2 e) do e <- Token.natural lexer return $ VaihtoehtoD2 $ frominteger e do x <- Token.identifier lexer return $ VaihtoehtoD3 x) Semanttiset rakenteet eivät aina ole jäsennyspuita tai abstraktia syntaksia. Semanttinen rakenne valitaan halutun käyttötarkoituksen mukaan. Valitaan käyttötarkoitukseksemme laatia semanttisena rakenteena merkkijonosta funktio tyyppiä joka [(String,Double)] -> Either String Double ottaa sisään syötelistan pareja (x,d) jossa x on muuttujannimi ja d sitä vastaava liukulukuarvo antaa vastauksenaan merkkijonon kuvaaman lausekkeen arvon kun sen jokaiselle muuttujalle x annetaan sitä vastaava arvo d tai virheilmoituksen jos syötelistasta puuttuikin jokin sellainen muuttujannimi x joka esiintyy lausekkeessa. Nyt meillä on kaksi monadia sisäkkäin: Ulompana on Parsecin jäsennysmonadi. Sisempänä on tämä semanttinen funktio, joka on Either String -virheenkäsittelymonadissa. 136

16 import Text.Parsec import Text.Parsec.Combinator import Control.Monad.Error -- Tässä otetaan käyttöön Parsecin Haskell-selaaja. import qualified Text.Parsec.Token as Token import Text.Parsec.Language(haskellDef) lexer = Token.makeTokenParser haskelldef -- "A parser for things..." type Parser thing = Parsec String () thing -- Käännöksen tulostyyppi. type LookupFn = [(String,Double)] -> Either String Double -- Tässä on jäsennyksen pääohjelma. Se kutsuu alkusymbolin -- jäsennysfunktiota. (Tyhjää) merkkijonoparametria -- käytetään virheilmoituksissa. jasenna = parse (do s <- parses eof return s) "" parses :: Parser LookupFn parses = chainl1 parseb parsea parsea :: Parser (LookupFn -> LookupFn -> LookupFn) parsea = do char + return $ binop (+) do char - return $ binop (-) binop :: (Double -> Double -> Double) -> LookupFn -> LookupFn -> LookupFn binop op p q xs = do p <- p xs q <- q xs return $ p op q parseb :: Parser LookupFn parseb = chainl1 parsed parsec parsec :: Parser (LookupFn -> LookupFn -> LookupFn) 137

17 parsec = do char * return $ binop (*) do char / return $ binop (/) parsed :: Parser LookupFn parsed = Token.whiteSpace lexer >> (Token.parens lexer parses (try $ do e <- Token.float lexer return $ const $ return e) do e <- Token.natural lexer return $ const $ return $ frominteger e do x <- Token.identifier lexer return $ maybe (throwerror $ "Muuttujalta " ++ x ++ " puuttuu arvo!") return. lookup x) kaanna :: (Monad m) => String -> m LookupFn kaanna = either (error. show) return. jasenna Parsec on esimerkki sovelluskohtaisesta kielestä (Domain Specific Language, DSL). DSL-ideassa lähestytään yleistä ohjelmointiongelmaa niin, että 1 ensin suunnitellaan ja toteutetaan juuri tällaisiin ohjelmointiongelmiin soveltuva pieni ohjelmointikieli 2 sitten käytetään tätä pientä kieltä kun ratkotaan tämän ohjelmointiongelman tapauksia. Parsecissa yleinen ohjelmointiongelma on jäsennys. 1 Parsecissa on rekursiivisesti etenevän jäsentämisen primitiivit sekä välineet niiden yhdistelemiseksi toisiinsa. 2 Näillä Parsecin primitiiveillä on vaivattomampaa kirjoittaa annetulle kieliopille rekursiivisesti etenevä jäsentäjä kuin perus-haskellilla. Haskell on hyvä alusta DSL-ohjelmoinnille: Toteutettava DSL voi lainata Haskellin funktiokäsitteen itselleen, koska laiskuutensa nojalla Haskell vain välittää parametreja funktioiden välillä laskematta niitä DSL voi itse päättää milloin se ne laskee. Laiskuutensa vuoksi Haskellilla on myös vaivatonta määritellä uusia DSLkontrollirakenteita kuten Parsecin. Muissa ohjelmointikielissä käytettäisiin makroja tms. 138

18 DSL vodaan määritellä monadisena, jolloin sen peräkkäissuoritus voidaan määritellä sen metodina (>>=) kirjoittaa do-syntaksilla. Esimerkiksi Parsec määritteli oman peräkkäissuorituksensa tarkoittavan että jäsennä syötettä eteenpäin. 8 Abstraktit tietotyypit Haskellissa on yksinkertainen modulijärjestelmä, joka on tarkoitettu abstraktien (abstract) tietotyyppien määrittelemiseen. Yleisesti tietotyyppi on abstrakti, jos sen toteutus on piilotettu sitä käyttävältä ohjelmakoodilta, jotta koodin täytyy käyttää tätä tyyppiä vain siten kuin sen ohjelmoija on tarkoittanut. Algebrallisilla tietotyypeillä se tarkoittaa tietotyyppiä, jonka konstruktorit on piilotettu sitä käyttävältä ohjelmakoodilta, koska silloin koodi ei voi luoda eikä tutkia sen arvoja omin päin vaan ainoastaan siten kuin sen ohjelmoija on tarkoittanut. Luvussa 6.2 kuvatut eksistentiaaliset tyypit ovat tällaisia abstrakteja tyyppejä, koska niiden arvoa pystyi käsittelemään vain tyyppiluokkana annetun rajapinnan kautta (jos sellainen annettiin). Ohjelmointikielten teoriassa modulit voidaankin nähdä tapana määritellä eksistentiaalisia tyyppejä. Funktionaalisessa ML-kieliperheessä kuten Standard ML (Milner et al., 1997, luvut 3 ja 5) ja (O)Caml on kehitetty paljon Haskellia monipuolisempia modulijärjestelmiä. Tosin niissä ei vuorostaan ole tyyppiluokkia. Haskellin moduleilla ilmaistaan, mitkä ohjelman tässä lähdekooditiedostossa määritellyistä funktioista, tyypeistä ja tyyppiluokista ovat paikallisia eli käytettävissä vain tässä samassa lähdekooditiedostossa julkisia eli käytettävissä kaikissa muissakin lähdekooditiedostoissa, jotka ottavat ne käyttöön importilla. Jos Haskell-lähdekooditiedosto on oma modulinsa, niin silloin sen rakenne on: module Hierarkinen.Modulin.Nimi viennit where tuonnit määritelmät ghci olettaa näin otsikoidun hierarkisen modulin löytyvän tiedostosta nimeltä Linuxissa Hierarkinen/Modulin/Nimi.hs Windowsissa hierarkinen\modulin\nimi.hs jonka polku alkaa 139

19 nykyisestä työhakemistosta josta ohjelmoija voi siis aloittaa tälle nyt tekeillä olevalle ohjelmalleen sen oman moduli- ja tiedostohierarkian asennuksen yhteydessä määritellystä pakkaushakemistosta josta alkaen se löytää vakiokirjastonsa kuten Data.Word jne. muista hakemistoista joita voi antaa optioina joko komentorivillä tai lähdekooditiedoston erikoiskommentissa {-# OPTIONS_GHC... #-} Ainakin Linuxissa näitä(kin) optioita voi asettaa myös 8.1 Tuonnit työhakemistokohtaisessa alustustiedostossa./.ghci tai käyttäjäkohtaisessa alustustiedostossa /.ghci. Modulin tuonnit koostuvat tuontilauseista jollaisen perusmuoto on import [qualified] Toinen.Hierarkinen [as Lyhenne] johon tutustuimmekin jo luvussa 4.6. Jos haluaakin tuoda modulin tekemistä määritelmistä vain osan, niin ne voi antaa monikkona (eli suluissa (...) pilkuin, eroteltuna) koko importin lopussa. Tai jos haluaakin tuoda modulin tekemistä määritelmistä muut kuin tässä monikossa mainitut, niin tämän monikon eteen voi kirjoittaa hiding. 8.2 Viennit Modulin viennit on sekin monikko, jossa kerrotaan mitä määritelmiään tämä moduli julkistaa ja miten. Jos tämä monikko viennit puuttuu, niin tämä moduli julkistaa kaikki määritelmänsä (paitsi importit). Yksinkertaisin julkistettava määritelmä on jonkin muuttujan nimi. Toinen julkistettava määritelmä on module Toinen.Hierarkinen jossa tässä samassa modulissa on myös import Toinen.Hierarkinen ja joka myös julkistaa sen modulin Toinen.Hierarkinen jonka se itse on ottanut käyttöön. Esimerkiksi moduli Data.Array julkistaa myös modulin Data.Ix, koska jos jokin moduli käyttää taulukoita, niin se käyttänee myös taulukkoindeksien operaatioita. Tällöin taulukkoja käyttävä modulissa riittää pelkkä import Data.Array 140

20 Kolmas julkistettava määritelmä on type-synonyymi. Se julkistetaan kirjoittamalla sen nimi monikkoon viennit. Neljäs julkistettava määritelmä on tyyppiluokka. Se voidaan julkistetaan kolmella eri tavalla: Pelkkä TyyppiLuokanNimi julkaisee sen siten, että muut modulit voivat käyttää sitä rajoitteissaan (...) => mutta eivät voi liittää omia tyyppejään sen uusiksi jäseniksi koska tämä moduli ei julkistanutkaan sen metodeja. Sen perään voi kirjoittaa monikkona niiden sen metodien nimet, jotka tämä moduli haluaa julkistaa. Silloin muut modulit voivat liittää omia tyyppejään sen jäseniksi määrittelemällä nämä metodit niiden instanceissa. Tämän monikon erikoismuotona on(..) joka tarkoittaa kaikki sen metodit. Viides julkistettava määritelmä on data-tyyppi. Sekin voidaan julkistaa vastaavasti kolmella eri tavalla: Pelkkä TyypinNimi julkistaa sen kokonaan abstraktina tyyppinä, jota muut modulit voivat käyttää omissa tyypeissään ::... mutta eivät voi käyttää koodissaan hahmojen tai lausekkeiden kautta koska tämä moduli ei julkistanutkaan sen konstruktoreja. Sen perään voi kirjoittaa monikkona niiden sen konstruktoreiden ja kenttien nimet, jotka tämä moduli haluaa julkistaa. Silloin muut modulit voivat käyttää niitä koodissaan, jolloin TyypinNimi onkin vain osittain abstrakti. Tämän monikon erikoismuotona on (..) joka tarkoittaa kaikki sen konstruktorit ja kentännimet. Silloin myös TyypinNimi on muissakin moduleissa täysin vapaasti käytettävissä samoin kuin niiden määrittelemät tyypit. Modulissa voi olla määritelmä muuttuja :: Tyyppi jossa moduli julkaisee tämän muuttujan mutta ei julkaise jotakin sen Tyyppiin sisältyvää itse määrittelemäänsä tyyppiä tai tyyppiluokkaa. Koska muissa moduleissa on voitava käyttää tätä julkaistua muuttujaa, niin myös tämä julkistamaton tyyppi tai tyyppiluokat julkistetaan, mutta vain tyypinpäättelyä varten, eli sellaisena etteivät muut modulit voikaan käyttää sitä omissa tyypeissään. Esimerkkinä tehdään luvun pinosta abstrakti tietotyyppi. 141

21 module Stack(Stack,emptyStack,push,pop) where newtype Stack t = IntoStack { fromstack :: [t] } deriving (Show) emptystack :: Stack t emptystack = IntoStack [] push :: t -> Stack t -> Stack t push x = IntoStack. (x :). fromstack pop :: u -> (t -> Stack t -> u) -> Stack t -> u pop e _ (IntoStack []) = e pop _ f (IntoStack (x:xs)) = f x (IntoStack xs) 8.3 Päämoduli Koko ohjelman päämoduli on poikkeus: Sen rakenne on module Main(main) where... main :: IO () main =... Sen tiedostonimi saa olla mikä tahansa ohjelma.hs. Sen kääntäminen komennolla ghc ohjelma.hs tuottaa siitä suorituskelpoisen ohjelmatiedoston nimeltään Linuxissa ohjelma Windowsissa ohjelma.exe samaan hakemistoon. Tämä main on standardoitu nimi Haskellin pääohjelmalle, joka suoritetaan ajamalla tämä ohjelmatiedosto. Pääohjelmaa ei tarvitse kirjoittaa omaksi modulikseen Main. Riittää määritellä tämä main :: IO () lähdekooditiedostossa ohjelma.hs. 142

22 9 Curryn ja Howardin vastaavuudesta Curryn ja Howardin vastaavuus (the Curry-Howard correspondence) (Sørensen and Urzyczyn, 2006) on symmetria formaalin loogisen todistusteorian ja funktionaalisen ohjelmoinnin välillä. Tietojenkäsittelyteoriassa se on inspiroinut esimerkiksi ohjelmointikielten tyyppiteoriaa ohjelmien verifiointia formaalia ohjelmankehitystä. Kyseessä on jälleen sama loogikko Haskell B. Curry sekä hänen oppilaansa William A. Howard. Tässä on sen perusintuitio. Otamme käyttöön merkintöjä todistusteoriasta: Merkintä nämä = tuo luetaan, että näistä oletuksista voidaan todistaa tuo johtopäätös. Nämä oletukset ja johtopäätökset ovat nyt muotoa eli tämä λ-lauseke on tuota tyyppiä. Esitämme merkinnällä sääntöjä tämän = käytölle. Perussääntö on lauseke :: tyyppi jos olemme osoittaneet kaikki nämä niin voimme osoittaa myös tämän e :: t,... = e :: t eli jos jokin kuuluu jo oletuksiin, niin se voidaan triviaalisti todistaa niistä. Käytämme yksinkertaista tyypitettyä λ-laskentaa, jonka tyyppirakenne on: Tulotyyppi (t,u) jolla on konstruktori (x,y) sekä kirjastofunktiot fst ja snd. Funktiotyyppi t -> u. Summatyyppi Either t u jolla on konstruktorit Left ja Right sekä kirjastofunktio either. Käytämme näitä kirjastofunktioita case-hahmonsovituksen sijasta. Kirjoitamme merkinnöillämme tämän kielen tyypityssääntöjä: 143

23 Tulotyypin konstruktorin tyypityssääntö on Γ = x :: t Γ = y :: u Γ = (x,y) :: (t,u) (17) ja sen kirjastofunktioiden tyypityssäännöt ovat Γ = z :: (t,u) Γ = fst z :: t ja Γ = z :: (t,u) Γ = snd z :: u. (18) Funktiotyypin konstruktorin λ tyypityssääntö on x :: t, Γ = e :: u Γ = λx.e :: t -> u (19) ja funktionkutsun tyypityssääntö on Γ = f :: t -> u Γ = f a :: u. Γ = a :: t (20) Summatyypin konstruktoreiden tyypityssäännöt ovat Γ = z :: t Γ = Left z :: Either t u ja Γ = z :: u Γ = Right z :: Either t u sekä sen kirjastofunktion tyypityssääntö on Γ = f :: t -> v Γ = g :: u -> v Γ = either f g :: Either t u -> v. (21) (22) (23) Ohjelmointikielten tyyppijärjestelmien teoriassa käytetään tällaisia sääntöjä, koska niillä voidaan spesifioida, mitä tyyppijärjestelmän toteutusten pitää päätellä ohjelmakoodista niitä tutkimalla loogisessa todistusteoriassa kehitetyin välinein voidaan analysoida tyyppijärjestelmän ominaisuuksia. Unohdetaan hetkeksi näistä säännöistä kaikki osat lauseke ::. Tulotyypin konstruktorin tyypityssääntö (17) pelkistyy muotoon = t = u = (t,u) ja sen kirjastofunktioiden tyypityssäännöt (18) muotoihin = (t,u) = t ja = (t,u) = u. Mutta nämähän ovat samat kuin konjunktion t u käyttösäännöt lauselogiikan todistuksissa! 144

24 Curryn ja Howardin vastaavuuden ensimmäinen osa onkin että lauselogiikan kaavat ovat λ-laskennan tyyppejä ( formulæ as types ) tässä mielessä. Ohjelmoinnissa tyyppi (t,u) onkin sellainen, jonka arvoissa on 1. kenttä tyyppiä t ja 2. kenttä tyyppiä u. Tästä syystä Haskell käyttää monikoita esimerkiksi rajoitteissaan(...)=>. Funktiotyypin tyypityssääntö (19) pelkistyy muotoon t, Γ = u Γ = t -> u ja tyypityssääntö (20) pelkistyy muotoon (24) Γ = t -> u Γ = u Γ = t jotka ovat puolestaan implikaation t u käyttösäännöt. Erityisesti sääntö (25) on päättelyaskel Modus Ponens. Summatyypin konstruktoreiden tyypityssäännöt (21) ja (22) pelkistyvät muotoihin = t = u ja = Either t u = Either t u ja sen kirjastofunktion tyypityssääntö (23) pelkistyy muotoon = t -> v = u -> v = Either t u -> v (25) (26) jotka ovat puolestaan disjunktion t u käyttösäännöt. Säännön (24) nojalla sääntö (26) kertoo, miten t u toimii ollessaan oletuksena. Ohjelmoinnissa tyyppi Either t u onkin sellainen, jonka arvossa on joko kenttä tyyppiä t tai kenttä tyyppiä u, ja tiedämme kumpi niistä. Tämä on kuitenkin konstruktiivinen eli intuitionistinen logiikka, koska t u voidaan osoittaa vain jos joko t voidaan osoittaa tai u voidaan osoittaa. Tällaisessa logiikassa esimerkiksi väitettä Marsissa joko on elämää tai siellä ei ole elämää ei voikaan (vielä) osoittaa, koska emme ole osoittaneet kumpaakaan näistä kahdesta mahdollisuudesta. Tutummassa klassisessa logiikassa ei sanotakaan voidaan osoittaa vaan on totta. Sellaisessa logiikassa Mars-esimerkkiväitteemme on totta, koska joko Marsissa on elämää tai siellä ei ole elämää on totta, vaikka emme tiedäkään (vielä) kumpi niistä on totta. Palautetaan sitten sääntöihin niistä unohdetut osat lauseke ::. Ne voidaan nähdä esityksinä vastaavan todistuksen rakenteelle, koska lausekkeen uloimmainen konstruktori tai funktionkutsu identifioi sen säännön, jota käytetään seuraavaksi. Curryn ja Howardin vastaavuuden toinen osa onkin, että lauselogiikan todistukset ovat λ-laskennan termejä eli laajemmin tulkittuna funktionaalisia ohjelmia ( proofs as programs ) tässä mielessä. 145

25 Tässä valossa tyypitetty β-reduktioaskel (β) eli funktionaalisen ohjelman suorituksen perusaskel (λx.f :: t -> u) (g :: t) f[x g] :: u on todistuksen sieventämistä poistamalla siitä jokin Modus Ponens -päättelyaskel (25) siten, että väitteen t todistus g sijoitetaan kaikkialle missä oletusta x käytetään. Voidaan määritellä kolme ongelmaa: Tyypintarkistus: Annetaan lauseke ja tyyppi, ja pitää selvittää päteekö niille lauseke :: tyyppi vaiko ei. Tämä on se ongelma, jota kaikki staattisesti tyypitetyt ohjelmointikielet ratkovat käännösaikana. Tutkimuksessa pyritään kehittämään sellaisia ilmaisuvoimaisia tyyppijärjestelmiä, jotka rajoittaisivat mahdollisimman vähän ohjelmoijan ilmaisunvapautta. Tyypinpäättely: Annetaan vain lauseke, ja pitää löytää sellainen tyyppi jolla lauseke :: tyyppi pätee (tai osoittaa, ettei sellaista tyyppiä ole). Tämä on se ongelma, jota tyypinpäättelevät ohjelmointikielet kuten Haskell ratkovat käännösaikana. Tutkimuksessa pyritään kehittämään sellaisia päättelymekanismeja, joilla tällaiset ilmaisuvoimaisemmat tyyppijärjestelmät olisivat ohjelmoijalle näkymättömiä. Tyyppiohjattu ohjelmointi: Annetaan vain tyyppi, ja pitää löytää sellainen lauseke jolla lauseke :: tyyppi pätee (tai osoittaa, ettei sellaista lauseketta ole). Curryn ja Howardin vastaavuuden näkökulmasta tämä ongelma on: Tässä on spesifikaatio logiikalla ilmaistuna. Kehitä sen mukainen ohjelma! Käytimme kurssilla perusversiota tästä lähestymistavasta, kun lähdimme ohjelmoimaan funktiota 1 kirjoittamalla ensin sille tyypin 2 sitten valitsemalla jonkin parametrin ja haarautumalla koodissa sen tyypin konstruktoreiden mukaan. Kysymystä Kuuluuko tähän tyyppiin yhtään lauseketta? kutsutaan sen asutusongelmaksi (type inhabitation problem). Ohjelmointinäkökulmasta se on Onko tämä spesifikaatio mahdollinen vai mahdoton toteuttaa? On kehitetty logiikkoja, joiden tietokonetoteutukset pystyvät generoimaan todistuksesta sitä vastaavan funktionaalisen ohjelmakoodin. Silloin ohjelmoijan työ muuttuu koodin kirjoittamisesta spesifikaation ristiriidattomuuden osoittamiseksi konstruktiivisesti, jotta todistuksesta voidaan tuottaa sitä vastaava ohjelmakoodi. Nämä välineet eivät vielä ole nousseet tutkimuslaboratorioista ohjelmistoteollisuuteen. Ehkä joskus tulevaisuudessa? Ehkä sellaisissa ohjelmointiongelmissa, joissa ohjelman oikeellisuus on kriittistä ja sen testaaminen vaikeaa? Jos näin käy, niin sen mukana funktionaalisen ohjelmoinnin rooli korostuu. 146

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

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

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

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

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

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

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

Jäsennysalgoritmeja. TIE448 Kääntäjätekniikka, syksy Antti-Juhani Kaijanaho. 29. syyskuuta 2009 TIETOTEKNIIKAN LAITOS. Jäsennysalgoritmeja

Jäsennysalgoritmeja. TIE448 Kääntäjätekniikka, syksy Antti-Juhani Kaijanaho. 29. syyskuuta 2009 TIETOTEKNIIKAN LAITOS. Jäsennysalgoritmeja TIE448 Kääntäjätekniikka, syksy 2009 Antti-Juhani Kaijanaho TIETOTEKNIIKAN LAITOS 29. syyskuuta 2009 Sisällys Sisällys Seuraava deadline Vaihe B tiistai 6.10. klo 10 selaaja ja jäsentäjä toimivat Kääntäjän

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

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

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

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

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

follow(a) first(α j ) x

follow(a) first(α j ) x Tästä ensimmäisestä LL(1)-ehdosta (14) seuraa erityisesti, että korkeintaan yksi välikkeen A säännöistä voi tuottaa tyhjän merkkijonon ε eli tehdä välikkeestä A tyhjentyvän (eli nollautuvan). Toinen osa

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

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

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

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

TIEA241 Automaatit ja kieliopit, kesä Antti-Juhani Kaijanaho. 10. kesäkuuta 2013 TIEA241 Automaatit ja kieliopit, kesä 2013 etenevä Antti-Juhani Kaijanaho TIETOTEKNIIKAN LAITOS 10. kesäkuuta 2013 Sisällys etenevä etenevä Chomskyn hierarkia (ja muutakin) kieli säännöllinen LL(k) LR(1)

Lisätiedot

jäsentäminen TIEA241 Automaatit ja kieliopit, syksy 2015 Antti-Juhani Kaijanaho 26. marraskuuta 2015 TIETOTEKNIIKAN LAITOS

jäsentäminen TIEA241 Automaatit ja kieliopit, syksy 2015 Antti-Juhani Kaijanaho 26. marraskuuta 2015 TIETOTEKNIIKAN LAITOS TIEA241 Automaatit ja kieliopit, syksy 2015 Antti-Juhani Kaijanaho TIETOTEKNIIKAN LAITOS 26. marraskuuta 2015 Sisällys Tunnistamis- ja jäsennysongelma Olkoon G = (N, Σ, P, S) kontekstiton kielioppi ja

Lisätiedot

jäsentämisestä TIEA241 Automaatit ja kieliopit, syksy 2015 Antti-Juhani Kaijanaho 27. marraskuuta 2015 TIETOTEKNIIKAN LAITOS

jäsentämisestä TIEA241 Automaatit ja kieliopit, syksy 2015 Antti-Juhani Kaijanaho 27. marraskuuta 2015 TIETOTEKNIIKAN LAITOS TIEA241 Automaatit ja kieliopit, syksy 2015 Antti-Juhani Kaijanaho TIETOTEKNIIKAN LAITOS 27. marraskuuta 2015 Sisällys Rekursiivisesti etenevä engl. recursive descent parsing Tehdään kustakin välikesymbolista

Lisätiedot

Attribuuttikieliopit

Attribuuttikieliopit TIEA241 Automaatit ja kieliopit, kevät 2011 (IV) Antti-Juhani Kaijanaho TIETOTEKNIIKAN LAITOS 3. toukokuuta 2011 Sisällys t Chomskyn hierarkia kieli säännöllinen kontekstiton kontekstinen rekursiivisesti

Lisätiedot

TIEA241 Automaatit ja kieliopit, kevät 2011 (IV) Antti-Juhani Kaijanaho. 29. huhtikuuta 2011

TIEA241 Automaatit ja kieliopit, kevät 2011 (IV) Antti-Juhani Kaijanaho. 29. huhtikuuta 2011 TIEA241 Automaatit ja kieliopit, kevät 2011 (IV) Antti-Juhani Kaijanaho TIETOTEKNIIKAN LAITOS 29. huhtikuuta 2011 Sisällys Chomskyn hierarkia kieli säännöllinen kontekstiton kontekstinen rekursiivisesti

Lisätiedot

jäsennyksestä TIEA241 Automaatit ja kieliopit, syksy 2016 Antti-Juhani Kaijanaho 29. syyskuuta 2016 TIETOTEKNIIKAN LAITOS Kontekstittomien kielioppien

jäsennyksestä TIEA241 Automaatit ja kieliopit, syksy 2016 Antti-Juhani Kaijanaho 29. syyskuuta 2016 TIETOTEKNIIKAN LAITOS Kontekstittomien kielioppien TIEA241 Automaatit ja kieliopit, syksy 2016 Antti-Juhani Kaijanaho TIETOTEKNIIKAN LAITOS 29. syyskuuta 2016 Sisällys Harjoitustehtävätilastoa Tilanne 29.9.2016 klo 8:41 (lähes kaikki kommentoitu) passed

Lisätiedot

ICS-C2000 Tietojenkäsittelyteoria Kevät 2016

ICS-C2000 Tietojenkäsittelyteoria Kevät 2016 ICS-C2000 Tietojenkäsittelyteoria Kevät 2016 Kierros 6, 22. 26. helmikuuta Huom: arviointiviikolla 15. 19.2. ei ole laskuharjoituksia! Demonstraatiotehtävien ratkaisut D1: (a) Osoita, että seuraava yhteydetön

Lisätiedot

Yhteydettömän kieliopin jäsennysongelma

Yhteydettömän kieliopin jäsennysongelma Yhteydettömän kieliopin jäsennysongelma Yhteydettömän kieliopin jäsennysongelmalla tarkoitetaan laskentaongelmaa Annettu: yhteydetön kielioppi G, merkkijono w Kysymys: päteekö w L(G). Ongelma voidaan periaatteessa

Lisätiedot

TIEA241 Automaatit ja kieliopit, kevät Antti-Juhani Kaijanaho. 12. kesäkuuta 2013

TIEA241 Automaatit ja kieliopit, kevät Antti-Juhani Kaijanaho. 12. kesäkuuta 2013 TIEA241 Automaatit ja kieliopit, kevät 2012 Antti-Juhani Kaijanaho TIETOTEKNIIKAN LAITOS 12. kesäkuuta 2013 Sisällys t Chomskyn hierarkia (ja vähän muutakin) kieli säännöllinen LL(k) LR(1) kontekstiton

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

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

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

Testaa: Vertaa pinon merkkijono syötteeseen merkki kerrallaan. Jos löytyy ero, hylkää. Jos pino tyhjenee samaan aikaan, kun syöte loppuu, niin

Testaa: Vertaa pinon merkkijono syötteeseen merkki kerrallaan. Jos löytyy ero, hylkää. Jos pino tyhjenee samaan aikaan, kun syöte loppuu, niin Yhteydettömien kielioppien ja pinoautomaattien yhteys [Sipser s. 117 124] Todistamme, että yhteydettömien kielioppien tuottamat kielet ovat tasan samat kuin ne, jotka voidaan tunnistaa pinoautomaatilla.

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

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

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

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

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

Laskennan mallit (syksy 2010) Harjoitus 8, ratkaisuja

Laskennan mallit (syksy 2010) Harjoitus 8, ratkaisuja 582206 Laskennan mallit (syksy 2010) Harjoitus 8, ratkaisuja 1. Tarkastellaan yhteydetöntä kielioppia S SAB ε A aa a B bb ε Esitä merkkijonolle aa kaksi erilaista jäsennyspuuta ja kummallekin siitä vastaava

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

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

Yhteydettömät kieliopit [Sipser luku 2.1]

Yhteydettömät kieliopit [Sipser luku 2.1] Yhteydettömät kieliopit [ipser luku 2.1] Johdantoesimerkkinä tarkastelemme kieltä L = { a n b m a n n > 0, m > 0 }, joka on yhteydetön (mutta ei säännöllinen). Vastaavan kieliopin ytimenä on säännöt eli

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

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

TIEA241 Automaatit ja kieliopit, kevät Antti-Juhani Kaijanaho. 16. helmikuuta 2012

TIEA241 Automaatit ja kieliopit, kevät Antti-Juhani Kaijanaho. 16. helmikuuta 2012 TIEA241 Automaatit ja kieliopit, kevät 2012 Antti-Juhani Kaijanaho TIETOTEKNIIKAN LAITOS 16. helmikuuta 2012 Sisällys t Sisällys t Chomskyn hierarkia kieli säännöllinen kontekstiton kontekstinen rekursiivisesti

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

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

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

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

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

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

Ongelma(t): Miten jollakin korkeamman tason ohjelmointikielellä esitetty algoritmi saadaan suoritettua mikro-ohjelmoitavalla tietokoneella ja siinä

Ongelma(t): Miten jollakin korkeamman tason ohjelmointikielellä esitetty algoritmi saadaan suoritettua mikro-ohjelmoitavalla tietokoneella ja siinä Ongelma(t): Miten jollakin korkeamman tason ohjelmointikielellä esitetty algoritmi saadaan suoritettua mikro-ohjelmoitavalla tietokoneella ja siinä olevilla komponenteilla? Voisiko jollakin ohjelmointikielellä

Lisätiedot

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

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

Lisätiedot

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

on rekursiivisesti numeroituva, mutta ei rekursiivinen.

on rekursiivisesti numeroituva, mutta ei rekursiivinen. 6.5 Turingin koneiden pysähtymisongelma Lause 6.9 Kieli H = { M pysähtyy syötteellä w} on rekursiivisesti numeroituva, mutta ei rekursiivinen. Todistus. Todetaan ensin, että kieli H on rekursiivisesti

Lisätiedot

Luonnollisen päättelyn luotettavuus

Luonnollisen päättelyn luotettavuus Luonnollisen päättelyn luotettavuus Luotettavuuden todistamiseksi määrittelemme täsmällisesti, milloin merkkijono on deduktio. Tässä ei ole sisällytetty päättelysääntöihin iteraatiosääntöä, koska sitä

Lisätiedot

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

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

Lisätiedot

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

Sisällys. 12. Näppäimistöltä lukeminen. Yleistä. Yleistä 12.1 12.2 12.3 12.4

Sisällys. 12. Näppäimistöltä lukeminen. Yleistä. Yleistä 12.1 12.2 12.3 12.4 Sisällys 12. Näppäimistöltä lukeminen Arvojen lukeminen näppäimistöltä yleisesti. Arvojen lukeminen näppäimistöltä Java-kielessä.. Luetun arvon tarkistaminen. Tietovirrat ja ohjausmerkit. Scanner-luokka.

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

M =(K, Σ, Γ,, s, F ) Σ ={a, b} Γ ={c, d} = {( (s, a, e), (s, cd) ), ( (s, e, e), (f, e) ), (f, e, d), (f, e)

M =(K, Σ, Γ,, s, F ) Σ ={a, b} Γ ={c, d} = {( (s, a, e), (s, cd) ), ( (s, e, e), (f, e) ), (f, e, d), (f, e) Tik-79.148 Kevät 2001 Tietojenkäsittelyteorian perusteet Laskuharjoitus 7 Demonstraatiotehtävien ratkaisut 1. Pinoautomaatti M = K Σ Γ s F missä K Σ s ja F on määritelty samalla tavalla kuin tilakoneellekin.

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 2016-2017 ari.vesanen (at) oulu.fi 5. Rekursio ja induktio Rekursio tarkoittaa jonkin asian määrittelyä itseensä viittaamalla Tietojenkäsittelyssä algoritmin määrittely niin,

Lisätiedot

Ohjelmoinnin perusteet Y Python

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

Lisätiedot

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

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

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

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 1.3.2010 T-106.1208 Ohjelmoinnin perusteet Y 1.3.2010 1 / 36 Monikko Monikko (engl. tuple) muistuttaa listaa, mutta monikon sisältöä ei voi muuttaa sen jälkeen,

Lisätiedot

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python Ohjelmoinnin perusteet Y Python T-106.1208 2.3.2011 T-106.1208 Ohjelmoinnin perusteet Y 2.3.2011 1 / 39 Kertausta: tiedoston avaaminen Kun ohjelma haluaa lukea tai kirjoittaa tekstitiedostoon, on ohjelmalle

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

ICS-C2000 Tietojenkäsittelyteoria Kevät 2016

ICS-C2000 Tietojenkäsittelyteoria Kevät 2016 ICS-C2000 Tietojenkäsittelyteoria Kevät 206 Kierros 0, 2. 24. maaliskuuta Huom! Perjantaina 25. maaliskuuta ei ole laskareita (pitkäperjantai), käykää vapaasti valitsemassanne ryhmässä aiemmin viikolla.

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

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 8. syyskuuta 2016

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 8. syyskuuta 2016 TIEA241 Automaatit ja kieliopit, syksy 2016 Antti-Juhani Kaijanaho TIETOTEKNIIKAN LAITOS 8. syyskuuta 2016 Sisällys a https://tim.jyu.fi/view/kurssit/tie/ tiea241/2016/videoiden%20hakemisto Matemaattisen

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

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

Taas laskin. TIES341 Funktio ohjelmointi 2 Kevät 2006

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

Lisätiedot

uv n, v 1, ja uv i w A kaikilla

uv n, v 1, ja uv i w A kaikilla 2.8 Säännöllisten kielten rajoituksista Kardinaliteettisyistä on oltava olemassa (paljon) ei-säännöllisiä kieliä: kieliä on ylinumeroituva määrä, säännöllisiä lausekkeita vain numeroituvasti. Voidaanko

Lisätiedot

Säännöllisten kielten sulkeumaominaisuudet

Säännöllisten kielten sulkeumaominaisuudet Säännöllisten kielten sulkeumaominaisuudet Osoitamme nyt, että säännöllisten kielten joukko on suljettu yhdisteen, konkatenaation ja tähtioperaation suhteen. Toisin sanoen jos A ja B ovat säännöllisiä,

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

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

b) Määritä myös seuraavat joukot ja anna kussakin tapauksessa lyhyt sanallinen perustelu.

b) Määritä myös seuraavat joukot ja anna kussakin tapauksessa lyhyt sanallinen perustelu. Johdatus yliopistomatematiikkaan Helsingin yliopisto, matematiikan ja tilastotieteen laitos Kurssikoe 23.10.2017 Ohjeita: Vastaa kaikkiin tehtäviin. Ratkaisut voi kirjoittaa samalle konseptiarkille, jos

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

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

Rekursiiviset palautukset [HMU 9.3.1]

Rekursiiviset palautukset [HMU 9.3.1] Rekursiiviset palautukset [HMU 9.3.1] Yleisesti sanomme, että ongelma P voidaan palauttaa ongelmaan Q, jos mistä tahansa ongelmalle Q annetusta ratkaisualgoritmista voidaan jotenkin muodostaa ongelmalle

Lisätiedot

ITKP102 Ohjelmointi 1 (6 op)

ITKP102 Ohjelmointi 1 (6 op) ITKP102 Ohjelmointi 1 (6 op) Tentaattori: Antti-Jussi Lakanen 20. huhtikuuta 2018 Vastaa kaikkiin tehtäviin. Tee kukin tehtävä omalle konseptiarkille. Noudata ohjelmointitehtävissä kurssin koodauskäytänteitä.

Lisätiedot

S BAB ABA A aas bba B bbs c

S BAB ABA A aas bba B bbs c T-79.148 Kevät 2003 Tietojenkäsittelyteorian perusteet Harjoitus 8 Demonstraatiotehtävien ratkaisut 4. Tehtävä: Laadi algoritmi, joka testaa onko annetun yhteydettömän kieliopin G = V, Σ, P, S) tuottama

Lisätiedot

TIEA241 Automaatit ja kieliopit, kevät Antti-Juhani Kaijanaho. 2. helmikuuta 2012

TIEA241 Automaatit ja kieliopit, kevät Antti-Juhani Kaijanaho. 2. helmikuuta 2012 TIEA241 Automaatit ja, kevät 2012 Antti-Juhani Kaijanaho TIETOTEKNIIKAN LAITOS 2. helmikuuta 2012 Sisällys Sisällys Chomskyn hierarkia kieli säännöllinen kontekstiton kontekstinen rekursiivisesti lueteltava

Lisätiedot

T Syksy 2002 Tietojenkäsittelyteorian perusteet Harjoitus 8 Demonstraatiotehtävien ratkaisut

T Syksy 2002 Tietojenkäsittelyteorian perusteet Harjoitus 8 Demonstraatiotehtävien ratkaisut T-79.148 Syksy 2002 Tietojenkäsittelyteorian perusteet Harjoitus 8 Demonstraatiotehtävien ratkaisut 4. Tehtävä: Laadi algoritmi, joka testaa onko annetun yhteydettömän kieliopin G = V, Σ, P, S tuottama

Lisätiedot

Rajoittamattomat kieliopit (Unrestricted Grammars)

Rajoittamattomat kieliopit (Unrestricted Grammars) Rajoittamattomat kieliopit (Unrestricted Grammars) Laura Pesola Laskennanteorian opintopiiri 13.2.2013 Formaalit kieliopit Sisältävät aina Säännöt (esim. A -> B C abc) Muuttujat (A, B, C, S) Aloitussymboli

Lisätiedot

Matematiikan tukikurssi, kurssikerta 2

Matematiikan tukikurssi, kurssikerta 2 Matematiikan tukikurssi kurssikerta 1 Relaatioista Oletetaan kaksi alkiota a ja b. Näistä kumpikin kuuluu johonkin tiettyyn joukkoon mahdollisesti ne kuuluvat eri joukkoihin; merkitään a A ja b B. Voidaan

Lisätiedot

12. Näppäimistöltä lukeminen 12.1

12. Näppäimistöltä lukeminen 12.1 12. Näppäimistöltä lukeminen 12.1 Sisällys Arvojen lukeminen näppäimistöltä yleisesti. Arvojen lukeminen näppäimistöltä Java-kielessä. In-luokka. Luetun arvon tarkistaminen. Tietovirrat ja ohjausmerkit.

Lisätiedot

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

Alityypitys. TIES542 Ohjelmointikielten periaatteet, kevät Antti-Juhani Kaijanaho. Jyväskylän yliopisto Tietotekniikan laitos Alityypitys TIES542 Ohjelmointikielten periaatteet, kevät 2007 Antti-Juhani Kaijanaho Jyväskylän yliopisto Tietotekniikan laitos 5. maaliskuuta 2007 Muistatko tietueet? {I 1 = E 1,..., I n = E n } : {I

Lisätiedot

Rekursiivinen Derives on periaatteessa aivan toimiva algoritmi, mutta erittäin tehoton. Jos tarkastellaan esim. kieliopinpätkää

Rekursiivinen Derives on periaatteessa aivan toimiva algoritmi, mutta erittäin tehoton. Jos tarkastellaan esim. kieliopinpätkää Rekursiivinen Derives on periaatteessa aivan toimiva algoritmi, mutta erittäin tehoton. Jos tarkastellaan esim. kieliopinpätkää S AB CA... A CB...... ja kutsua Derives(S, abcde), niin kutsu Derives(B,

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

vaihtoehtoja TIEA241 Automaatit ja kieliopit, syksy 2016 Antti-Juhani Kaijanaho 13. lokakuuta 2016 TIETOTEKNIIKAN LAITOS

vaihtoehtoja TIEA241 Automaatit ja kieliopit, syksy 2016 Antti-Juhani Kaijanaho 13. lokakuuta 2016 TIETOTEKNIIKAN LAITOS TIEA241 Automaatit ja kieliopit, syksy 2016 Antti-Juhani Kaijanaho TIETOTEKNIIKAN LAITOS 13. lokakuuta 2016 Sisällys Harjoitustehtävätilastoa Tilanne 13.10.2016 klo 9:42 passed waiting redo submitters

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

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

FORMAALI SYSTEEMI (in Nutshell): aakkosto: alkeismerkkien joukko kieliopin määräämä syntaksi: sallittujen merkkijonojen rakenne, formaali kuvaus

FORMAALI SYSTEEMI (in Nutshell): aakkosto: alkeismerkkien joukko kieliopin määräämä syntaksi: sallittujen merkkijonojen rakenne, formaali kuvaus FORMAALI SYSTEEMI (in Nutshell): Formaali kieli: aakkosto: alkeismerkkien joukko kieliopin määräämä syntaksi: sallittujen merkkijonojen rakenne, formaali kuvaus esim. SSM:n tai EBNF:n avulla Semantiikka:

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

(0 1) 010(0 1) Koska kieli on yksinkertainen, muodostetaan sen tunnistava epädeterministinen q 0 q 1 q 2 q3

(0 1) 010(0 1) Koska kieli on yksinkertainen, muodostetaan sen tunnistava epädeterministinen q 0 q 1 q 2 q3 T-79.48 Tietojenkäsittelyteorian perusteet Tentti 25..23 mallivastaukset. Tehtävä: Kuvaa seuraavat kielet sekä säännölisten lausekkeiden että determinististen äärellisten automaattien avulla: (a) L = {w

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