Haskell ohjelmointikielen tyyppijärjestelmä

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

Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Taas laskin. TIES341 Funktio ohjelmointi 2 Kevät 2006

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

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

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

Ydin-Haskell Tiivismoniste

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

Funktionimien kuormitus. TIES341 Funktio ohjelmointi 2 Kevät 2006

14.1 Rekursio tyypitetyssä lambda-kielessä

TIES542 kevät 2009 Tyyppijärjestelmän laajennoksia

lausekkeiden tapauksessa. Jotkin ohjelmointikielet on määritelty sellaisiksi,

TIEA341 Funktio-ohjelmointi 1, kevät 2008

ELM GROUP 04. Teemu Laakso Henrik Talarmo

TIEA341 Funktio-ohjelmointi 1, kevät 2008

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

Ruby. Tampere University of Technology Department of Pervasive Computing TIE Principles of Programming Languages

TIES542 kevät 2009 Rekursiiviset tyypit

Common Lisp Object System

5.5 Jäsenninkombinaattoreista

TIE Principles of Programming Languages. Seminaariesityksen essee. Ryhmä 18: Heidi Vulli, Joni Heikkilä

Demo 7 ( ) Antti-Juhani Kaijanaho. 9. joulukuuta 2005

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset

TIES542 kevät 2009 Tyyppiteorian alkeet

7/20: Paketti kasassa ensimmäistä kertaa

Rekursiiviset tyypit

TIE Principles of Programming Languages CEYLON

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmointikieli TIE Principles of Programming Languages Syksy 2017 Ryhmä 19

2.4 Normaalimuoto, pohja ja laskentajärjestys 2.4. NORMAALIMUOTO, POHJA JA LASKENTAJÄRJESTYS 13

Lisää laskentoa. TIEA341 Funktio ohjelmointi 1 Syksy 2005

TIEA341 Funktio-ohjelmointi 1, kevät 2008

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

815338A Ohjelmointikielten periaatteet Harjoitus 7 Vastaukset

Taulukot. Jukka Harju, Jukka Juslin

TIEA341 Funktio-ohjelmointi 1, kevät 2008

sama tyyppi (joka vastaa kaikkien mahdollisten arvojen summa-aluetta). Esimerkiksi

11.4. Context-free kielet 1 / 17

Ohjelmoinnin peruskurssien laaja oppimäärä

MS-A0402 Diskreetin matematiikan perusteet

Chapel. TIE Ryhmä 91. Joonas Eloranta Lari Valtonen

Staattinen tyyppijärjestelmä

15. Ohjelmoinnin tekniikkaa 15.1

Luku 3. Listankäsittelyä. 3.1 Listat

Ohjelmoinnin peruskurssien laaja oppimäärä

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

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

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Ohjelmoinnin peruskurssien laaja oppimäärä

Rajoittamattomat kieliopit (Unrestricted Grammars)

Opiskelijoiden suurimmat haasteet Haskell-ohjelmointikielen tyyppijärjestelmän kanssa.

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

1 Tavoitteet. 2 Periaatteet ja ominaisuudet. 2.1 Tyyppipäättely

Yksinkertaiset tyypit

TIE PRINCIPLES OF PROGRAMMING LANGUAGES Eiffel-ohjelmointikieli

Tyyppipäättely. Keijo Mattila Tiivistelmä

811120P Diskreetit rakenteet

UML-kielen formalisointi Object-Z:lla

Jäsennys. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Ohjelmoinnin peruskurssien laaja oppimäärä

TIEA255 Tietotekniikan teemaseminaari ohjelmointikielet ja kehitysalustat. Antti-Juhani Kaijanaho. 16. helmikuuta 2011

Dart. Ryhmä 38. Ville Tahvanainen. Juha Häkli

7. Näytölle tulostaminen 7.1

Funktionaalinen ohjelmointi

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

Ohjelmointi 1 Taulukot ja merkkijonot

Groovy. Niko Jäntti Jesper Haapalinna Group 31

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

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

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

815338A Ohjelmointikielten periaatteet

815338A Ohjelmointikielten periaatteet Harjoitus 5 Vastaukset

ITKP102 Ohjelmointi 1 (6 op)

Funktio-ohjelmoinnin hyödyntäminen peliohjelmoinnissa

17. Javan omat luokat 17.1

Lyhyt kertaus osoittimista

Lisää pysähtymisaiheisia ongelmia

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

Luku 15. Parametripolymorfismi Kumitus

AS C-ohjelmoinnin peruskurssi 2013: C-kieli käytännössä ja erot Pythoniin

Säännöllisen kielen tunnistavat Turingin koneet

SQL-perusteet, SELECT-, INSERT-, CREATE-lauseet

on rekursiivisesti numeroituva, mutta ei rekursiivinen.

Loppukurssin järjestelyt C:n edistyneet piirteet

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 30. marraskuuta 2015

T Olio-ohjelmointi Osa 5: Periytyminen ja polymorfismi Jukka Jauhiainen OAMK Tekniikan yksikkö 2010

.NET ajoympäristö. Juha Järvensivu 2007

Ohjelmoinnin peruskurssien laaja oppimäärä

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

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

5.3 Laskimen muunnelmia 5.3. LASKIMEN MUUNNELMIA 57

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

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

Staattinen metaohjelmointi

Ohjelmoinnin peruskurssien laaja oppimäärä

Tietueet. Tietueiden määrittely

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Vertailulauseet. Ehtolausekkeet. Vertailulauseet. Vertailulauseet. if-lauseke. if-lauseke. Javan perusteet 2004

Transkriptio:

Haskell ohjelmointikielen tyyppijärjestelmä Sakari Jokinen Helsinki 19. huhtikuuta 2004 Ohjelmointikielten perusteet - seminaarityö HELSINGIN YLIOPISTO Tietojenkäsittelytieteen laitos

1 Johdanto 1 Tyyppien avulla voidaan rajoittaa datalle suoritettavia operaatioita semanttisesti oikeisiin. Staattisesti tyypitetty ohjelma suorittaa tyyppien semanttisen tarkistuksen ennen ajoa. Staattinen tyypitys voi kuitenkin haitata koodin uudelleenkäyttöä koska lisäyksien joukossa voi olla uusia datatyyppejä ja valmiissa koodissa tyypit on jo määritelty [Car89]. Haskell ohjelmontikielen käyttämä tyyppijärjestelmä pyrkii mahdollistamaan koodin uudelleenkäytön sekä samalla säilyttämään staattisen tyypityksen. Haskell on puhtaasti funktionaalinen laiskasti evaluoiva ohjelmointikieli. Haskell 98 on stabiili versio haskelista. Stabiili tarkoittaa tässä sitä, että toteuttajat lupautuvat tukemaan kieltä tulevaisuudessa kuten se on määritelty [Jon98]. Haskell kielestä on tehty useita toteutuksia kuten GHC sekä Hugs, jotka kumpikin tarjoavat lisäyksiä Haskell 98 määrittelyyn. Tämä artikkeli viittaa jatkossa Haskell 98 kieleen. Kappaleessa 2 käydään lävitse Haskell kielen syntaksia. Kappaleessa 3 käsitellään tyyppiluokkia. Kappaleessa 4 esitellään algebralliset tyypit. Kappale 5 käsittelee Haskell tyyppijärjestelmään kuuluvaa tyyppienpäättelyä. 2 Haskell 2.1 Yleinen syntaksi sekä semantiikka Tämän kappaleen tarkoitus on esitellä artikkelin esimerkeissä käytetty Haskell syntaksi ja semantiikka. Haskell on funktionaalinen ohjelmointikieli. Tämä tarkoittaa sitä, että funktiot ovat ensimmäisen luokan olioita eikä sivuefektejä ole, eli kielessä ei voida asettaa muuttujaa tuhoavasti(destructive update). Funktioita

2 voidaan osittain applikoida (partial application). x = f Asettaa x:n arvoksi f. (a,b) = (1,2) c = (1,2) Ensimmäinen lause asettaa a:n arvoksi 1 sekä b:n arvoksi 2 käyttäen hahmonsovitusta. Toinen lause asettaa c:n arvoksi kaksikon (1,2). (,) on kaksikkotyypin konstruktori, Konstruktoreilla voidaan rakentaa uusia arvoja, sekä käyttää purkamaan konstruktorilla luotuja arvoja. a:st = [1,2,3] : on listakonstruktori. [1,2,3] on syntaktista sokeria määritelmälle 1:(2:(3:[])). Lause asettaa a:lle arvon 1 sekä st:lle arvon 2:(3:[]). let g = a in z let lauseen oikea puoli g = a määrittelee funktion g = a let lauseen loppuosassa z. Erikoismerkeillä +,-,*,... nimetyt funktiot ovat infix muodossa, prefix muotoon ne saa ympäröimällä ne suluilla. a * b == (*) a b 2.2 Tyypit Kaikilla lauseilla on tyyppi Haskell kielessä. Lauseen tyyppi ilmaistaan tyyppinotaation avulla.

3 q :: Int q on tyyppiä Int f :: Int -> Char->Int f on tyyppiä funktio Int tyypistä funktioon Char tyypistä Int tyyppiin, eli ekvivalentti tyypin Int -> (Char -> Int) kanssa. l :: [Int] l on tyyppiä lista joka koostuu Int tyypeistä. t :: (Int,Int,Char) t on tyyppiä monikko jonka ensimmäinen jäsen on tyyppiä Int, toinen jäsen tyyppiä Int, sekä kolmas jäsen tyyppiä Char. Yllä Int ja Char tyypit ovat tyyppivakioita. v :: a -> a v:n tyyppi on funktio joltain tyypiltä a samalle tyypille a olevia arvoja. a v:n tyypissä on tyyppimuuttuja se voi viitata mihin tahansa tyyppiin. c :: (Ctx a) => a->a c on tyyppiä funktio tyypistä a tyyppiin a siten että tyyppi a kuuluu tyyppiluokkaan Ctx (kts kappale 3). a:n sanotaan olevan rajoitettu tyyppimuuttuja ja Ctx on a:n konteksti [Jon98].

3 Tyyppiluokat 4 Parametrinen polymorfismi tarkoittaa sitä että funktio on määritelty usealla eri tyypille ja toimii samalla tavalla kaikille. Ad-hoc polymorfismi tarkoittaa sitä että funktio on määritelty usealla eri tyypille ja toimii kaikille eri tavoin [WaB88]. square x = x * x square 3 square 3.14 square funktio on esimerkki parametrisestä polymorfismista. Sen odotetaan toimivan niin kokonaisluvuilla kuin reaaliluvuilla. * funktio on esimerkki ad-hoc polymorfismista. Sen toteutus on todennäköisesti erilainen kokonais -sekä rationaaliluvuilla. Tyyppiluokat ovat Haskell kielen menetelmä toteuttaa ad-hoc polymorfismi [WaB88]. Samalla saadaan menetelmä parametrisen polymorfismin toteuttamiseksi. Tyyppiluokka määritteelee joukon funktioita jotka luokkaan kuuluvien tyyppien tulee toteuttaa. Jos jotain luokan funktiota ei toteuteta niin toteuttamaton funktio sidotaan undefined funktioon. Tästä ei anneta käännösvirhettä [Jon98]. class Num a where (+), (*):: a->a->a negate :: a->a instance Num Int where (+) = addint (*) = mullint negate = negint class Num määrittelee luokan Num jolle kuuluu (+),(-) sekä negate funktiot. instance Num Int määrittelee tyypin Int kuuluvaksi Num luokkaan ja samalla antaa

5 luokan funktioiden toteutukset. square :: Num a => a->a square x = x * x square funktio voidaan määritellä tyyppiluokkien avulla siten että sen saamille argumenteille on toteutettu * funktio. 4 Algebralliset datatyypit Algebralliset datatyypit (Algebraic Data Types) luodaan data avainsanan avulla. data Tree = Nil Node Int Tree Tree Komento data luo uuden algebrallisen datatyypin Tree. Esimerkissä Nil sekä Node ovat konstruktoreita. Nil :: Tree Node :: Int->Tree ->Tree -> Tree Algebralliset tyypit voivat olla rekursiivisesti määriteltyjä kuten esimerkissä. Node konstruktori ottaa Tree tyyppisen argumentin sekä palauttaa Tree arvon. Algebrallisen datatyypin määrittelyyn voidaan myös antaa tyyppimuuttujia, jolloin saadaan polymorfisia algebrallisia datatyypeejä. Tyyppimuuttujia voi rajoittaa kontekstilla samalla tavalla kuin polymorfisilla funktioilla. data (Eq a) => Tree a = Nil Node a (Tree a) (Tree a)

6 Konstruktorien tyypit ovat tällöin Nil :: (Eq a) => Tree a Node :: (Eq a ) => a -> Tree a -> Tree a Algebrallisia datatyyppejä voidaan käyttää hahmon sovitukseen kuten muitakin tyyppejä. a = Node 1 Nil Nil (Node b ) = a b saa arvon 1. 5 Tyyppien päättely 5.1 Hindley-Milner tyyppijärjestelmä Haskell käyttää tyyppien päättelyyn tyyppiluokilla laajennettua Hindley-Milner algoritmia [Jon98]. Hindley-Milner algoritmi on ratkeava algoritmi, jolla pystytään päättelemään ohjelmalle yleisin mahdollinen tyyppi käyttämättä mitään explisiittistä tyyppinotaatiota [Car89]. Hindley-Milner tyyppijärjestelmässä tyyppimerkinnöillä voidaan vain rajoittaa löydettyä yleisintä mahdollista tyyppiä. Kun Hindley-Milner tyyppijärjestelmässä annetaan tyyppimuuttujalle tyyppi A niin kaikki tyyppimuuttujan esiintymät tyyppiympäristössä saavat saman tyypin. Tätä kutsutaan unifikaatioksi. Unifikaatio epäonnistuu kun yriteään asettaa samaa tyyppimuuttujaa kahdelle eri tyypille, tai yritetään asettaa tyyppimuuttujaan a tyyppi joka sisältää tyyppimuuttujan a [Car89]. Tyyppien päättely etenee unifikaation myötä.

7 Hindley-Milner tyyppijärjestelmä määrittää let lauseen tyypin seuraavasti; ensiksi let lauseen oikealle puolella annetaan tyyppi q. Seuraavaksi kaikki tyypissä q esiintyvät tyyppimuuttujat generalisoidaan. Generalisoinnissa kaikille tyypissä esiintyville tyyppimuuttujille annetaan universaalikvanttoroitu tyyppi, ellei niitä ole sidottu tyyppiympäristössä. Viimeiseksi let lauseen loppuosalle määritetään tyyppi. f x = let g y = (y, y) in... Edellisessä let lauseessa ensiksi määritellään g:n tyyppi. a: a -> (a,a), jossa a on universaalikvanttoroitu, eli voi saada tyypikseen kaikkia tyyppejä [Jon98]. Jos lauseen g tyypissä q oleva tyyppimuuttuja a esiintyy tyyppiympäristössä joudutaan rajoittaamaan g:n polymorfisuutta. f x = let g y z = ([x, y], z) in... g:n tyyppi ylläolevassa lauseessa, jos x:n tyyppi on a, on a->b->([a], b). g on monomorfinen tyyppimuuttujassa a. Monomorfisuudesta johtuu että kaikissa g:n applikaatioissa y:n tulee olla samaa tyyppiä [Jon98]. 5.2 Haskell tyyppijärjestelmä Haskell tyyppijärjestelmä poikkeaa paikoin tavallisesta Hindley-Milner tyyppijärjestelmästä: tyyppimuuttujien generalisointia on rajoitettu vahvemmin sekä tyyppiluokista johtuen joskus tarvitaan explisiittistä tyyppien merkintää. Haskell tyyppijärjestelmässä on mahdollista että jollakin lauseella on moniselitteinen tyyppi. Haskell kieli kieltää moniselitteiset tyypit joten tällöin tarvitaan tyyppien explisiittistä merkintää. let x = read... in show x

8 jossa show :: Show a => a -> String read :: Read a => String -> a read saa argumenttina merkkijonon ja palauttaa sitä vastaavan arvon tyyppiä a. show ottaa arvon tyyppiä a ja palauttaa sitä vastaavan merkkijonon. let lauseen tyyppi on (Read a, Show a) => String. Sisäänrakennetut tyypit kuten Int sekä Bool kuuluvat kumpikin kumpaankin luokkaan joten lauseen tyyppi on moniselitteinen [Jon98].Tilanne voidaan korjata antamalla explisiittisesti x:lle tyyppi. Toinen tapa jolla Haskell voi selvitä moniselitteisistä tyypeistä on käyttää oletusarvoisia tyyppejä. Lähteet Jon98 Jones S. P.(editor), Haskell 98 Language and Libraries the Revised Report. WaB88 Wadler P., Blott S., How to make ad-hoc polymorphism less addhoc, Proceedings of the 16th ACM SIGPLAN-SIGACTsymposium on Principles of programming languages, Pages: 60-76, 1989. Car89 Cardelli L., Basic Polymorphic Type-checking, Science of computer programming 8/2 (april 1987) revised 6/21/88.