tiistai 27. tammikuuta 2009

Luento 6 - Denotaatio

Luennon 6 aiheena oli jo aiemmin sivuttu denotaatio. Denotaation ajatuksenahan on ohjelmointikielen esittäminen tietokoneesta riippumattomalla tavalla. Denotationaalinen tapa esittää ohjelmointikieli on hyvinkin matemaattinen. Matematiikan avulla esitystavasta saadaan eksakti ja tietyllä tavalla universaali. Luennolla painottui erityisesti matematiikan merkitys abstrahoinnin apuvälineenä. Denotaatiossa matemaattisen notaation tarkoitushan on yksinkertaistaa asioita sen sijaan että se tekisi niitä monimutkaisemmiksi kuin ne ovat.

Matemaattisen notaation käyttämisen hyödyistä mainittiin myös sen vaativuuden hyöty. Käytännössä se pakottaa miettimään asiat tarkemmalla tasolla kuin muuten kenties tulisi tehneeksi. Tässä mielessä lähestymistapa muistuttaa testaamisesta. Toisaalta voisi kuvitella, että kielten määritelmille voitaisiin niillekin antaa määritelmiä (lue testejä), joiden avulla pyrittäisiin takaamaan määritelmien jonkinmoinen oikeellisuus. Toisin sanoen kielen määritelmän voisi rajata jo sen määrittelyn avulla. Tiedä sitten tehdäänkö käytännössä näin.

Ohjelmointikielten suunnittelun tapauksessa formaali tapa lähestyä asioita on erittäin arvokasta. Tällä tavoin kieli voidaan todistaa toimivaksi jo ennen kuin sille tehdään toteutus. Ilman formaalia lähestymistapaa kieleen saattaa jäädä pieniä semanttisia "porsaanreikiä", jotka sitten myöhemmin siunataan ominaisuuksiksi, koska niitä on totuttu jo käyttämään.

Sen sijaan, että ikävystyttäisin lukijaa luennolla käytyjen esimerkkien tarkalla kertaamisella, tällä kertaa keskitynkin esimerkeissä esiintyneisiin avainasioihin ja niiden pohtimiseen kuitenkin seuraten niiden esiintymisjärjestystä. Toisaalta blogisofta antaa hieman huonosti myöden matemaattiselle notaatiolle. :)

Tietyssä mielessä denotationaalinen ohjelmointikielen määrittely on ohjelmointia sinänsä. Tässä tapauksessa ohjelmointikielenä on vain matematiikka. Oleellista määrittelyissä on nimenomaan kielen semantiikan määrittely. Määrittelyt, jotka eivät kuvaa semantiikkaa eivät ole hyödyllisiä, kuten luennolla näimme. Tähän palaan tuonnempana.

Luennolla kerrattiin erityissulkeiden (esim. E[[e]] merkitys). Ajatuksena on, että näiden semanttisten sulkeiden avulla voidaan erottaa metakieli todellisesta kielestä. Toisin sanoen notaation avulla voidaan kuvata, kuinka esimerkiksi tietty matemaattinen operaatio kuvautuu ohjelmointikieleen. Mielestäni on tärkeää muistaa, että tämä kuvaus ei ole aina identtinen. Toisin sanoen voi olla luontevaa, että metakielen '+' kuvautuu todellisessa kielessä '+' merkiksi, mutta esimerkiksi sanarikasta suomenkielistä ohjelmointikieltä laatiessa se voisi olla vaikka 'plus' (viisi plus kuusi) tai 'summaa' (summaa viisi ja kuusi). Käytännöllisempi esimerkki on tietenkin ohjelmointikielten käyttämä notaatio potenssin merkinnälle. Tavallisimpia tässä tapauksessa ovat ^ ja **.

Mikäli kielessä halutaan määritellä muuttujia, voidaan apuvälineenä käyttää ns. "currying" menetelmää. Muuttujien määrittely ei sinänsä ole mikään helppo temppu. Semanttisesti se voi tarkoittaa, että tiettyyn olioon assosioidaan toisen olion sisältämä tieto. Perinteisesti tämä tehdään vielä siten, että sijoitus tehdään lausekkeen vasemmalle puolelle siten, että olio, jonka tieto vasemmalla puolella olevaan olioon liitetään, on oikealla. Tätä ajatustapaa voi yleistää myös sijoitukseen, jossa useaan muuttujaan sijoitetaan tietoa samanaikaisesti tietyn ehdon mukaisesti (esim. "a, b, c = 3, 4, 6"). Käsittääkseni "currying" pyrkii ratkaisemaan juuri näitä ongelmia ja sinällään tarjoamaan omanlaisensa abstraktion apuvälineen. Mielenkiintoisesti kielten määrittelyissä käytetään apuvälineenä metamuuttujia, joiden avulla kuvataan muuttujan semantiikkaa.

Suoraviivaohjelmien tapauksessa esiteltiin ympäristön käsite. Aluksi notaatio ja ympäristön tarve tuntuivat oudoilta, mutta luennolla jaettua monistetta lainaten "Kun edellä muuttujien arvo määräytyy ympäristön (Env) perusteella, on lauseen muutettava ympäristöä." Toisin sanoen ympäristön tarve tulee suoraan suoraviivaohjelmien määritelmästä mikä tuntuu sinänsä luontevalta.

Kuten jossain aiemmassa blogipostissa olen varmaan maininnutkin, suoraviivaohjelmat ovat esiehto "oikeille" ohjelmille, joissa on myös ehtolauseita ja luuppeja. Ehtolause on joko tosi tai epätosi. Tietenkin tämä heijastuu myös itse määritelmään. Luuppien tapaus on ehtolauseita kinkkisempi. Ongelmaksi muodostuu nimenomaan se, kuinka luuppi kannattaisi määritellä. Syklinen, luupin itsensä avulla kuvaava määrittely ei kerro sen semantiikasta mitään. Tämän vuoksi esitettiin erityinen pohjan käsite, johon luupin käsite voidaan sitoa. Luupin tapauksessa luupilla voi olla konkreettinen pohja tai ei (eli luuppi ei pääty koskaan, jolloin se ei saavuta pohjaansa. Tämä ei tarkoita etteikö luuppia voitaisi ajatella pohjan käsitteen kautta.).

Äkkiseltään denotationaalinen kielen määrittely saattaa näyttää kryptiselta. Kuitenkin noiden määrittelyjen pienten palojen ymmärtäminen auttoi ymmärtämään sitä, mistä niissä pohjimmiltaan on kysymys, hieman paremmin. Loppujen lopuksi kaikki palautuu määritelmiin ja matemaattisiin työkaluihin, joiden tärkeimpänä tehtävänä on tehdä asioista mahdollisimman ymmärrettäviä, matemaattisessa mielessä (em. tarkoittaa myös sitä, että notaation ja käsitteiden tulee olla tuttua). Kurssin suurimpia anteja lienee nimenomaan se, että määritelmiä oppii ainakin jossain määrin ymmärtämään.

1 kommentti:

  1. Luennolla käsitelty kiintopisteoperaattorin merkitys selvisi toden teolla vasta myöhemmin. Kysymyshän on vain siitä, että kiintopisteoperaattorin avulla voidaan toteuttaa rekursio, koska se mahdollistaa viittaamisen aliohjelman itsensä ulkopuolelle.

    Jos while-luuppia pitäisi lähteä nyt purkamaan, tulisi siitä purettuna seuraavaa (f edustaa yhtä kierrosta)
    f(f(f(...(f(pohja))...))). Huomaa, että pohjaa ei ole välttämättä olemassa (ikuinen luuppi). Jos sitä ei ole olemassa, ei ohjelma myöskään pysähdy (ehdollinen break tulkitaan varmaan pohjaksi jos ehto toteutuu jossain vaiheessa).

    VastaaPoista