Z-skeemojen animointi Haskellilla



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

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

Haskell ohjelmointikielen tyyppijärjestelmä

TIEA341 Funktio-ohjelmointi 1, kevät 2008

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

815338A Ohjelmointikielten periaatteet Harjoitus 7 Vastaukset

TIEA341 Funktio-ohjelmointi 1, kevät 2008

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Luku 3. Listankäsittelyä. 3.1 Listat

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

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

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

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

TIEA341 Funktio-ohjelmointi 1, kevät 2008

TIEA341 Funktio-ohjelmointi 1, kevät 2008

TIEA341 Funktio-ohjelmointi 1, kevät 2008

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

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

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

Ohjelmoinnin peruskurssien laaja oppimäärä

TIEA341 Funktio-ohjelmointi 1, kevät 2008

1.3Lohkorakenne muodostetaan käyttämällä a) puolipistettä b) aaltosulkeita c) BEGIN ja END lausekkeita d) sisennystä

ELM GROUP 04. Teemu Laakso Henrik Talarmo

Abstraktit tietotyypit. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Computing Curricula raportin vertailu kolmeen suomalaiseen koulutusohjelmaan

5.3 Laskimen muunnelmia 5.3. LASKIMEN MUUNNELMIA 57

Taas laskin. TIES341 Funktio ohjelmointi 2 Kevät 2006

Kuvaus eli funktio f joukolta X joukkoon Y tarkoittaa havainnollisesti vastaavuutta, joka liittää joukon X jokaiseen alkioon joukon Y tietyn alkion.

Ohjelmoinnin peruskurssien laaja oppimäärä

1.3 Lohkorakenne muodostetaan käyttämällä a) puolipistettä b) aaltosulkeita c) BEGIN ja END lausekkeita d) sisennystä

Ohjelmoinnin peruskurssien laaja oppimäärä

TIE PRINCIPLES OF PROGRAMMING LANGUAGES Eiffel-ohjelmointikieli

Ohjelmoinnin peruskurssien laaja oppimäärä

Funktio-ohjelmoinnin hyödyntäminen peliohjelmoinnissa

5.5 Jäsenninkombinaattoreista

ITKP102 Ohjelmointi 1 (6 op)

Tietueet. Tietueiden määrittely

Ohjelmoinnin peruskurssien laaja oppimäärä

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

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

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

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

Ohjelmoinnin perusteet Y Python

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

TIES542 kevät 2009 Tyyppijärjestelmän laajennoksia

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

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

Oliosuunnitteluesimerkki: Yrityksen palkanlaskentajärjestelmä

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

Common Lisp Object System

Tarkennamme geneeristä painamiskorotusalgoritmia

TIE Tietorakenteet ja algoritmit 1. TIE Tietorakenteet ja algoritmit

ITKP102 Ohjelmointi 1 (6 op)

Johnson, A Theoretician's Guide to the Experimental Analysis of Algorithms.

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

Rekursiiviset tyypit

Kuvaus eli funktio f joukolta X joukkoon Y tarkoittaa havainnollisesti vastaavuutta, joka liittää joukon X jokaiseen alkioon joukon Y tietyn alkion.

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssien laaja oppimäärä

ITKP102 Ohjelmointi 1 (6 op)

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

Ohjelmoinnin perusteet Y Python

7/20: Paketti kasassa ensimmäistä kertaa

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

Ohjelmoinnin jatkokurssi, kurssikoe

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

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin perusteet Y Python

15. Ohjelmoinnin tekniikkaa 15.1

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

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Kehittää ohjelmointitehtävien ratkaisemisessa tarvittavia metakognitioita!

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset

Sisällys. JAVA-OHJELMOINTI Osa 7: Abstrakti luokka ja rajapinta. Abstraktin luokan idea. Abstrakti luokka ja metodi. Esimerkki

Tietorakenteet ja algoritmit

Ohjelmoinnin peruskurssien laaja oppimäärä

14.1 Rekursio tyypitetyssä lambda-kielessä

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

Nollasummapelit ja bayesilaiset pelit

1 Kannat ja kannanvaihto

Osoitin ja viittaus C++:ssa

Yksinkertaiset tyypit

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

1. Mitä tehdään ensiksi?

MS-A0402 Diskreetin matematiikan perusteet Esimerkkejä, todistuksia ym., osa I

Määrittelydokumentti

Sisällys. 12. Näppäimistöltä lukeminen. Yleistä. Yleistä

MS-A0402 Diskreetin matematiikan perusteet Esimerkkejä, todistuksia ym., osa I

15. Ohjelmoinnin tekniikkaa 15.1

Imperatiivisten ohjelmien organisointiparadigmojen. historia

Imperatiivisten ohjelmien organisointiparadigmojen historia

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

1. Olio-ohjelmointi 1.1

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

Täydentäviä muistiinpanoja laskennan rajoista

Ydin-Haskell Tiivismoniste

TIETORAKENTEET JA ALGORITMIT

Transkriptio:

Z-skeemojen animointi Haskellilla Antti-Juhani Kaijanaho 6. toukokuuta 2001 Sisältö 1 Johdanto 2 2 Joitakin funktionaalisen ohjelmoinnin käsitteitä 3 2.1 Imperatiivinen funktionaalinen ohjelmointi 3 2.2 Hindley-Milner-tyyppijärjestelmä 3 3 Joukot ja logiikka 4 4 Funktiot 5 5 Skeemat 5 5.1 Tilaskeemat 5 5.2 Operaatioskeemat 6 5.3 Käyttöliittymä 7 6 Pääohjelma 8 7 Jatkoa 9 Formaalit menetelmät -kurssin seminaarityö 1

1 Johdanto Formaaleilla menetelmillä pyritään luomaan täsmällinen ja yksikäsitteinen ohjelman toiminnallisuuden määritelmä (specifications). Kun ohjelmasta on sitten tehty toteutus, on suhteellisen helppo varmistaa, että ohjelma täyttää määritelmän. Mutta kuinka voidaan olla varmoja, että määritelmä vastaa ohjelmalle asetettuja vaatimuksia (requirements), kuinka se voidaan validoida? Spesifikaation validointi voidaan tehdä esimerkiksi johtamalla siitä yleisiä lauseita, joita verrataan vaatimuksiin. Jos vaatimukset ja lauseet eivät käy yksiin, spesifikaatio on rikki. On esitetty, että tämän tulisi olla ainoa validoinnin keino [5]. Toinen tapa on animoida spesifikaatio. Tällöin spesifikaatio on joko sellaisenaan tai suhteellisen pienin muutoksin ajettavissa (executable) joko tulkin tai kääntäjän avulla. Tätä lähestymistapaa on puolustettu mm. artikkelissa [3]. Animoinnin tuottama ajattava ohjelma on vain harvoin ohjelman käypä implementaatio. Animointi on yleensä varsin suoraviivainen tai vähintäänkin mekaaninen prosessi, jonka on tarkoitus olla mahdollisimman nopea. Sen sijaan tuotettu ohjelma on usein hyvin tehoton jopa käyttökelvottomuuteen asti. Animoinnissa epätriviaalit ongelmat lakaistaan yleensä maton alle, jolloin animoinnin tulos saattaa sisältää jopa eksponentiaalisia algoritmeja. Tämä ei haittaa, koska animoinnin tulosta ei olekaan tarkoitus käyttää oikeasti, vaan sillä tarkastetaan, että spesifikaation mukainen ohjelma toimii niinkuin vaatimuksissa on määrätty. 1 Z-notaation [15] animointia on tutkittu varsin paljon. Yleensä esitetyt animointimenetelmät muuntavat spesifikaation mekaanisesti jollakin kielellä kirjoitetuksi ohjelmaksi, joka voidaan sitten ajaa tulkin avulla tai kääntää ajettavaksi, konekieliseksi ohjelmaksi. Esimerkiksi Mirandaa [1], Haskellia [4, 13, 14] ja LSL:ää [3] on käytetty Z-notaation animointiin. Tarkastelen tässä kirjoitelmassa Z:lla [15] kirjoitettujen spesifikaatioiden animointia Haskellilla [10, 11]. Oletan lukijan hallitsevan sekä Z:aa että Haskellia jonkin verran. Haskellia taitamattomat voivat tutustua seuraaviin materiaaleihin: [2, 6, 7, 12]. Tässä kirjoitelmassa käytetään esimerkkinä BlockHandler-spesifikaatiota, joka on kokonaisuudessaan luentomonisteessa [8, luku 12]. Sen animaation listaus on liitteenä. Pääosan kirjoitelmasta muodostaa sellaisen epämuodollisen ajattelutavan esittely, jota soveltamalla Z-notaatio kääntyy suhteellisen helposti Haskelliksi. Metodi on suurimmaksi osaksi täysin mekaaninen, ja uskon, että lisätutkimuksella se voidaan saattaa täysin mekaaniseksi. Metodi on kokonaisuudessaan itse muodostamani, mutta osa sen ideoista on peräsin Abdallahin et al. [1] ja Goodmanin [4] metodeista. Kumpaakaan metodia ei olisi voinut käyttää sellaisenaan: Abdallahin et al. metodin kohdekieli on Miranda, joka joissakin kohdin eroaa Haskellista, ja Goodmanin metodista, jonka kohdekieli oli varsin ratkaisevasti vanhentunut Haskellin versio, tiedossani oli vain yleinen esittely. Olen koonnut Haskell-modulin Z, joka sisältää joitakin usein tarvittavia määrittelyjä. Sen listaus on liitteenä. 1. Ehkä se on jopa hyvä asia. Onhan tunnettua, että liian hyvältä näyttävän prototyypin näyttäminen tilaajalle saattaa katkaista rahahanat, kun tilaaja kuvittelee ohjelman olevan valmis. 2

2 Joitakin funktionaalisen ohjelmoinnin käsitteitä Funktionaalisen ohjelmoinnin perusidea on ajatella ohjelmaa funktiona eikä käskynä: sen sijaan, että ohjelma muuttaa maailman tilaa, se ottaa maailman tilan parametrinaan ja palauttaa uuden maailman tilan. Tämän vuoksi funktionaalinen ohjelmointi soveltuu varsin hyvin Z-skeemojen animointiin, sillä niissä myös luodaan uusi tila eikä muuteta vanhaa. 2.1 Imperatiivinen funktionaalinen ohjelmointi Haskell noudattaa uudempaa imperatiivisen funktionaalisen ohjelmoinnin paradigmaa suhteessaan ulkomaailman kanssa operointiin. Tässä mallissa puhtaasti funktonaalinen ohjelma tuottaa tuloksenaan arvon, joka esittää potentiaalista tekoa. Tämän teon kuvaama teko tehdään, kun ohjelma päättyy. Näin imperatiivisesti funktionaalinen ohjelma ikäänkuin päättyy ennen kuin se on alkanutkaan. Imperatiivisen funktionaalisen ohjelmoinnin keskeinen käsite on monadi. Monadikäsite on peräisin maailman hyödyttömimmäksi kutsutusta matematiikan osa-alueesta eli kategoriateoriasta. Matemaattisesti ottaen monadi on mikä tahansa joukko Y X, jolle on määritelty operaatiot return : X Y X ja >>= : Y X (X Y X ) Y X siten, että tietyt lait [16, luku 2.5] pätevät. Ohjelmoijan kannalta monadi on geneerisesti polymorfinen tyyppi, jonka arvot esittävät potentiaalisia tekoja. Monadioperaatio return ruiskuttaa puhtaan arvon monadiin, jolloin tuloksena on potentiaalinen teko, joka aktualisoituessaan ei tee mitään muuta kuin tuottaa tuloksekseen kyseisen arvon. Operaatio >>= taas peräkkäistää kaksi tekoa: se ottaa kaksi parametria (potentiaalisen teon ja funktion, joka tuottaa potentiaalisen teon) ja tuottaa potentiaalisen teon, joka aktualisoituessaan ensin aktualisoi ensimmäisen argumentin, antaa sitten tuon teon tuloksen toiselle argumentille argumenttina ja aktualisoi lopuksi tuon argumentin palauttaman potentiaalisen teon. Haskellissa on kaksi hyödyllistä ja käytännönläheistä esimerkkiä monadista. Toinen on IOmonadi ja toinen Maybe-monadi. IO-monadi on Haskellin tapa olla yhteydessä ulkomaailmaan. Siihen kuuluu monadioperaatioiden lisäksi primitiivifunktioita kuten getline. Maybe-monadi mallittaa epävarmuutta: sen arvot ovat joko Just jotakin tai Nothing. 2.2 Hindley-Milner-tyyppijärjestelmä Haskellin edustamassa funktionaalisen ohjelmoinnin koulukunnassa käytetään Hindley-Milner-tyyppisysteemin [9] muunnelmia. Hindley-Milner-tyypitystä käyttävät kielet ovat erittäin vahvasti tyypitettyjä 2. Haskellin käyttämässä Hindley-Milner-tyypityksessä on olemassa mm. seuraavat tavat muodostaa tyyppejä: tyyppivakiot (esimerkiksi Bool), algebralliset tyypit (olennaisesti karteesisten tulojen erillisiä yhdisteitä) ja funktiotyypit. Lisäksi Haskell sisältää Hindley-Milner-tyypityksen laajennoksen, tyyppiluokat [17], jotka mahdollistavat olio-ohjelmoinnista tutun rajapinnan perinnän (mutta ei toteutuksen perintää). Näiden avulla ohjelmoija voi ilmaista minkä tahansa lausekkeen tyypin tai olla ilmaisematta, sillä kääntäjä osaa useimmissa tapauksissa päätellä ne. 2. Näihin verrattuna esimerkiksi C on heikosti tyypitetty. 3

Z-notaatio P tyyppi joukko1 joukko2 joukko1 joukko2 joukko1 \ joukko2 joukko1 joukko2 joukko1 = joukko2 alkio joukko Haskell-notaatio P tyyppi emptyp joukko1 $\/ joukko2 joukko1 $/\ joukko2 joukko1 $\ joukko2 joukko1 $ = joukko2 joukko1 = joukko2 alkio memberof joukko listtoset lista settolist joukko 3 Joukot ja logiikka Taulukko 1: Z-modulin joukko-operaatioita Z:n joukko voidaan esittää Haskellissa listana. Z-modulissa joukko käsitetään listaksi, joka on kapseloitu omaksi parametrisoiduksi tietotyypikseen P a. Joukoille on Z-modulissa määritelty operaatioita, jotka on esitetty taulukossa 1. Logiikka voidaan kirjoittaa Haskellilla pääosin sellaisenaan. Z-moduli määrittelee myös kvanttorit forall :: P a -> (a -> Bool) -> Bool ja exists :: P a -> (a -> Bool) -> Bool. Z-lauseke x : joukko predikaatti kirjoitetaan Haskellilla forall joukko $ \x -> predikaatti ja vastaavasti Z-lauseke x : joukko predikaatti kirjoitetaan exists joukko $ \x -> predikaatti Kvanttoreita käytettäessä on huomattava, että joukko, jonka yli kvantifioidaan, on valittava tarkasti. Aina ei voida valita samoin kuin Z-notaatiossa. Yleisesti ottaen ei voida kvantifioida yli jonkin tyypin, vaan mielummin kvantifioidaan yli jonkin konkreettisen joukon. Vaikka äärettömien joukkojen käyttö onnistuukin Haskellissa varsin hyvin, ei sellaisen yli kvantifiointi ole mahdollista kuin triviaaleissa tapauksissa. Jos tätä tarvitaan jonkin muuttujan arvon määrittelemiseen, joudutaan määritelmä kirjoittamaan hieman konstruktiivisempaan muotoon, mikä usein onnistuu helposti Haskellin standardifunktioiden kuten filter luovalla käytöllä. Tästä olkoon esimerkkinä joukkojen leikkauksen Haskell-määritelmä Z-modulista: xset $/\ yset = listtoset $ (flip filter) xs $ \x -> exists ys $ \y -> x == y where xs = settolist xset ys = settolist yset 4

Z-notaatio tyyppi1 tyyppi2 f x dom f ran f joukko f f joukko Haskell-notaatio F tyyppi1 tyyppi2 f @@ x dom f ran f joukko < f f > joukko 4 Funktiot Taulukko 2: Z-modulin funktio-operaatioita Z:n funktiot ovat yleensä tietorakenteita eivätkä proseduureja, joten niiden esittämiseen eivät sovi Haskellin funktiot. Sen sijaan Z-modulissa määritellään abstrakti, parametrisoitu tietotyyppi F a b. Se noudattaa osittaisfunktion invarianttia, joten kaikilla määrittelytyypin alkioilla ei ole välttämättä kuvaa. Tällaisia funktioita pääsee rakentamaan ja muuttamaan Haskell-funktioiden makef :: (Eq a, Eq b) => P (a, b) -> F a b (joka konstruoi funktion joukosta, joka on karteesisen tulon osajoukko) ja f2p :: F a b -> P (a, b) (joka toimii toisin päin) avulla. Taulukossa 2 esitellään funktioiden operaatiot, joista osan epäilemättä saisi suhteellisen helposti yleistettyä relaatioillekin. Haskellin funktioita on toki hyvä käyttää silloin, kun funktion määritelmä ei muutu ohjelman aikana. 5 Skeemat Voi olla hyvä idea kirjoittaa jokaisen skeeman käännös omaksi Haskell-modulikseen, mutta se ei ole ehdottaman välttämätöntä. 5.1 Tilaskeemat Yksinkertaiset tilaskeemat, jotka viittaavat vain omiin tilamuuttujiinsa, voidaan toteuttaa Haskellissa algebrallisena tietotyyppinä. Tällöin kutakin tilamuuttujaa varten varataan tyypissä yksi paikka. Muuttujien nimiä ei voi järkevästi kirjata tietotyyppiin standardi-haskellissa, mutta se ei käytännössä juurikaan haittaa. Tilaskeemaa vastaava algebrallinen tietotyyppi on hyvä parametrisoida ja varata tyypin viimeinen (tai ensimmäinen) paikka parametrityyppiseksi. Tällöin operaatioskeemojen syötteet ja tulosteet on helppo kuljettaa tilan mukana. Esimerkiksi BlockHandler-skeema toteutetaan tietotyyppimäärittelynä seuraavasti: data BlockHandler a = BlockHandler (P BlockType) [P BlockType] a Tilan invariantit saadaan mallinnettua niin, että konstruktorin sijaan käytetään aina erillistä luontifunktiota tila-arvon luontiin. Tällainen luontifunktio sitten tarkistaa invariantin ennen kuin luo arvon. Esimerkiksi: 5

makeblockhandler used blockseq more forall (listtoset blockseq) ($ = used) && (forall blockinx $ \i -> forall blockinx $ \j -> i == j (blockseq!! i) $/\ (blockseq!! j) == emptyp) = (BlockHandler used blockseq more) otherwise = error "unsatisfied invariant for BlockHandler" where blockinx = (listtoset [0.. length blockseq - 1]) Tilaskeemoja, jotka viittaavat oman tilansa ulkopuolelle, ei voi toteuttaa itsenäisinä, vaan ne on yhdistettävä johonkin toiseen tilaskeemaan. Kahden tilaskeeman yhdistämisen tapauksessa luodaan kolmen skeeman (kaksi yhdistettävää ja yhdiste) sijasta kaksi: toinen on perusskeema ja toinen on sen laajennos. Laajennoksen tilan yhdeksi komponentiksi otetaan perusskeeman tila. Esimerkiksi: data UserBlockHandler a = UserBlockHandler (BlockHandler a) (P UserType) (F BlockType UserType) a 5.2 Operaatioskeemat Operaatioskeemat mallinnetaan Haskellin funktioina, jotka ottavat tilan parametrinaan ja palauttavat sen Maybe-monadissa. Skeeman syötteet ja tulosteet välitetään tilan tyyppiparametrisoidussa paikassa. Tyypillisen operaatioskeeman tyyppimerkintä on siis Tilatyyppi Syötetyyppi -> Maybe (Tilatyyppi Tulostyyppi) Osittaiseksi operaatioskeemaksi sanotaan operaatioskeemaa, jonka esiehdot saattavat hylätä joitakin tila-syötekombinaatioita. Tällaisen skeeman animaation runko on tavallisesti seuraava: skeema (tilan-pattern-match) = precond (esiehto) (paluutilan-konstruointi) where jälkitilamuuttujien-määrittelyt Esimerkiksi: addblocks :: BlockHandler (P BlockType) -> Maybe (BlockHandler ReportType) addblocks (BlockHandler used blockseq ablocks) = precond (ablocks $ = used) (makeblockhandler used blockseq "") where used = used blockseq = blockseq ++ [ablocks] Tässä käytetty precond on Z-modulissa määritelty Haskell-funktio. Huomaa, että samaksi operaatioskeemaksi yhdistettävien osittaisten operaatioskeemojen tyyppitunnisteiden on oltava samat, joten niillä on oltava täsmälleen samat syötteet ja tulosteet osa voi 6

toki jäädä joiltakin skeemoilta käyttämättä, kuten edellisessä esimerkissä. Osittaiset operaatioskeemat, jotka käyttävät laajennettua tilaa, ovat hitusen monimutkaisempia sisäkkäisten tilojen vuoksi. Jokseenkin hankalia ovat tilanteet, joissa operaatioskeema laajentaa olemassaolevaa skeemaa. Tästä annan vain esimerkin: removeuserblocks :: UserBlockHandler () -> Maybe (UserBlockHandler ReportType) removeuserblocks (UserBlockHandler bh@(blockhandler used blockseq _) users bl_use _) = precond ((ran hrs $ = users) && (isjust bh )) $ makeuserblockhandler ((\(Just x) -> x) bh ) users bl_use "" where hrs = head blockseq < bl_use bh = removeblocks bh users = users bl_use = makef ((f2p bl_use) $\ (f2p hrs)) Osittaisista operaatioskeemoista kootaan toisia operaatioskeemoja Z-modulissa määriteltyä \/- operaattoria käyttäen: doaddblocks :: BlockHandler (P BlockType) -> Maybe (BlockHandler ReportType) doaddblocks = addblocks \/ freeblocktoqueue 5.3 Käyttöliittymä Käyttöliittymäskeemojen animointi on kinkkistä puuhaa. Käyttämäni tapa on luultavasti epäoptimaalinen, mutta yksinkertaisen tavan löytäminen ei ole ihan helppoa. Perusidea on se, että kuten edellä komentoskeemat animoidaan erikseen. Aiemmasta poiketen kuitenkin nämä on tarkoitus yhdistää varsinaisiin operaatioskeemoihin konjunktiivisesti eikä disjunktiivisesti, joten komentoskeemojen animointistrategiakin on erilainen. Komentoskeeman animaation tyyppitunniste on seuraavanlainen: Tilatyyppi Komentotyyppi -> IO (Maybe (Tilatyyppi Operaaation-syötetyyppi)) Toisin sanoen komentoskeeman tulee komennon tarkistettuaan lukea käyttäjältä tarvittavat syötteet. Tämä tekee komentoskeeman animaatiokaavasta sotkuisen: skeema (tilan-pattern-match) = if onko-komento-oikea then return Nothing else do kysy-syötteet return $ Just $ konstruoi-paluutila Esimerkki: doblocksofusercommand :: UserBlockHandler (Command) -> IO (Maybe (UserBlockHandler (UserType))) 7

doblocksofusercommand (UserBlockHandler (BlockHandler used blockseq _) users bl_use cmd) = if cmd /= "bou" then return Nothing else do putstr "user> " user <- getline return $ Just $ (UserBlockHandler (BlockHandler used blockseq user) users bl_use user) Suoritusskeeman animaation tehtävänä on yhdistää komentoskeema ja vastaava operaatioskeema konjunktiivisesti. Tässä käytetään hyväksi Maybe-tyypin monadisuutta: yhdistäminen tehdään monadioperaatiolla»=. Animaatiokaava on kuitenkin hieman monimutkaisempi, koska myös IOmonadi on kuvassa mukana: Esimerkki: suoritusskeema a = do res <- komentoskeema a return $ res»= operaatioskeema codoremoveuserblocks a = do res <- doremoveuserblockscommand a return $ res >>= doremoveuserblocks Jäljelle jää enää kokonaisuus, josta näytän aluksi animaatiokaavan skeema u = try [ suoritusskeema1, suoritusskeema2,... suoritusskeeman ] u»= putstrln. show ja sitten esimerkin handleuserblocks u = try [ codoaddblocks, codoremoveuserblocks, codoblocksofuser, unknowncommand ] u >>= putstrln. show Haskell-funktio try määritellään Z-modulissa. 6 Pääohjelma Toimiakseen animoitu ohjelma tarvitsee pääohjelman. Sen animointikaava on seuraavanlainen: main :: IO () main= main initialisoi-tila where 8

main (tilan-pattern-match) = do putstr ": " cmd <- getline if cmd == "" then return () else do tilan-pattern-match <- luo-tila-jossa-cmd main luo-komennoton-tila Esimerkiksi: main :: IO () main = main inituserblockhandler where main (UserBlockHandler (BlockHandler a b _) c d _) = do putstr ": " cmd <- getline if cmd == "" then return () else do (UserBlockHandler (BlockHandler a b _) c d _) <- handleuserblocks (makeuserblockhandler (makeblockhandler a b cmd) c d cmd) main (makeuserblockhandler (makeblockhandler a b ()) c d ()) 7 Jatkoa Esittelemäni metodi tulisi formalisoida täysin mekaaniseksi proseduuriksi ja se tulisi todistaa oikeaksi. Viitteet [1] Ali E. Abdallah, Alexandra Barros, José B. Barros, ja Jonathan P. Bowen. Deriving correct prototypes from formal Z specifications. Tekninen raportti SBU-CISM-00-27, South Bank University School of Computing, Information Systems and Mathematics, 2000. [2] Richard Bird. Introduction to Functional Programming using Haskell. Prentice Hall, toinen laitos, 1998. [3] Norbert E. Fuchs. Specifications are (preferably) executable. IEE/BCS Software Engineering Journal, 7(5):323 334, 1992. 9

[4] Howard S. Goodman. The Z-into-Haskell tool-kit. Tekninen raportti, University of Birmingham School of Computer Science, huhtikuu, 1995. [5] I. J. Hayes ja C. B. Jones. Specifications are not (necessarily) executable. Tekninen raportti, Key Centre for Software Technology, Department of Computer Science, University of Queensland, St. Lucia, Queensland, Australia 4072, tammikuu 1990. [6] Paul Hudak, John Peterson, ja Joseph H. Fasel. A gentle introduction to Haskell 98. http://www.haskell.org/tutorial/, kesäkuu 2000. [7] Antti-Juhani Kaijanaho. Haskell 98: Puhdasta funktionalismia nonstriktissä paketissa. http://www.iki.fi/gaia/tekstit/ohjsem99/, 1999. [8] Tommi Kärkkäinen. Formaalit menetelmät. Luentomoniste, Jyväskylän yliopisto, tietotekniikan laitos, 2001. [9] Robin Milner. A theory of type polymorphism in programming. Journal of Computer and System Sciences, 7(3):348 375, 1978. [10] Simon Peyton Jones, John Hughes, et al. Report on the programming language Haskell 98 a non-strict, purely functional language. http://www.haskell.org/definition/, helmikuu 1999. [11] Simon Peyton Jones, John Hughes, et al. Standard libraries for the Haskell 98 programming language. http://www.haskell.org/definition/, helmikuu 1999. [12] Fethi Rabhi ja Guy Lapalme. Algorithms A Functional Programming Approach. Addison- Wesley, toinen laitos, 1999. [13] L. B. Sherrell ja D. L. Carver. Z meets Haskell: A case study. Kirjassa 17th Annual International Computer Software and Applications Conference, ss. 320 326, 1993. [14] L. B. Sherrell ja D. L. Carver. Experiences in translating Z designs to Haskell implementations. Software Practice and Experience, 24(12), 1994. [15] J. M. Spivey. The Z Notation: A Reference Manual. J. M. Spivey, Oriel College, Oxford, OX1 4EW, England, 1998. [16] Philip Wadler. How to declare an imperative. ACM Computing Surveys, 29(3), syyskuu 1997. [17] Philip Wadler ja Stephen Blott. How to make ad-hoc polymorphism less ad hoc. Kirjassa 16th ACM Symposium on Principles of Programming Languages, Austin, Texas, tammikuu 1989. 10