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 1 : T 1,..., I n : T n } {real = 3.0, imag = 5.0} : {real : Real, imag : Real} i, j {1,..., n} : i j I i I j Γ E 1 : T 1 Γ E n : T n Γ {I 1 = E 1,..., I n = E n} : {I n : T 1,..., I n : T n} 1 k n Γ {I 1 = E 1,..., I k = E k,..., I n = E n} : {I n : T 1,..., I k : T k,..., I n : T n} Γ {I 1 = E 1,..., I k = E k,..., I n = E n}.i k : T k
Kysymys Onko seuraava lauseke hyvin tyypitetty? (λr : {x : Int, y : Int}.r.x){x = 0, y = 1} Vastaus 1. x ja y ovat eri nimet 2. r.x on sallittu, koska r:ssä on kenttä x 3. lauseke itse on sallittu, jos argumentilla ja parametrilla on sama tyyppi 4. argumentin tyyppi on {x : Int, y : Int} 5. parametrin tyyppi on {x : Int, y : Int} 6. Vastaus on siis: lauseke on hyvin tyypitetty.
Kysymys Onko seuraava lauseke hyvin tyypitetty? (λr : {x : Int}.r.x){x = 0, y = 1} Vastaus 1. x ja y ovat eri nimet 2. r.x on sallittu, koska r:ssä on kenttä x 3. lauseke itse on sallittu, jos argumentilla ja parametrilla on sama tyyppi 4. argumentin tyyppi on {x : Int, y : Int} 5. parametrin tyyppi on {x : Int} 6. Vastaus on siis: lauseke ei ole hyvin tyypitetty.
Pitäisikö se sallia? Lausekkeen (λr : {x : Int}.r.x){x = 0, y = 1} laskeminen onnistuu tyypityksen vääryydestä huolimatta: (λr : {x : Int}.r.x){x = 0, y = 1} {x = 0, y = 1}.x 0 Tyypityksen asettama rajoitus on siten turha! Yksi ratkaisu on luopua tyypityksestä...... mutta miten tyypitys korjattaisiin?
Määritelmä (Subsumptioperiaate) Tyyppi T 1 kelpaa tyypiksi T 2, jos kaikki lausekkeet E : T 1 ovat (semanttisesti) käytettävissä siellä, missä T 2 :n lausekkeita voidaan käyttää, eli seuraavat kaksi väitettä pätevät kaikilla lausekkeilla E, E 1 : T 1 ja E 2 : T 2 1. Jos E[x := E 2 ] : U 2 ja E[x := E 1 ] : U 1, niin U 1 <: U 2. 2. Jos E[x := E 2 ] ei jää jumiin, niin E[x := E 1 ] ei jää jumiin. Huomautus Jos T 1 kelpaa tyypiksi T 2, sanotaan, että T 1 on T 2 :n alityyppi (engl. subtype) ja merkitään T 1 <: T 2. Alityyppirelaatiota kutsutaan myös subsumptiorelaatioksi.
Riittää laajentaa tyypityssääntöjä seuraavalla lisäsäännöllä (subsumptiosääntö): Γ E : T 1 T 1 <: T 2 Γ E : T 2
Määritelmä Merkitään tyypin T arvojen joukkoa V(T ). Väite (Osajoukkotulkinta) Jos T 1 <: T 2 niin V(T 1 ) V(T 2 ). Todistus. Seuraa subsumptioperiaatteesta, subsumptiosäännöstä ja siitä, että tyypin arvot ovat (ainakin luennoilla tarkastelluissa λ-laskennon laajennuksissa) tyypin lausekkeita.
Lienee selvää, että alityypitys on refleksiivinen ja transitiivinen: T <: T T 1 <: T 2 T 2 <: T 3 T 1 <: T 3
Tarkastellaan lauseketta E.I k. Sen tyyppi riippuu ainoastaan E:n I k -kentän tyypistä Tietuetyypin lopusta saadaan unohtaa kenttiä vapaasti: n m {I 1 : T 1,..., I n : T n } <: {I 1 : T 1,..., I m : T m } Tietuetyypin kentät saavat alityypittyä vapaasti: T 1 <: T 1 T n <: T n {I 1 : T 1,..., I n : T n } <: {I 1 : T 1,..., I n : T n}
Saako kenttiä permutoida, ts. onko seuraava hyväksyttävä sääntö? f : {1,..., n} {1,..., n} f on bijektio {I 1 : T 1,..., I n : T n } <: {I f (1) : T f (1),..., I f (n) : T f (n) } Formaalin semantiikan kautta tulkittuna subsumptiosääntö sallii tämän. Jos sääntö hyväksytään, (<:) ei ole antisymmetrinen eikä siten myöskään osittaisjärjestys. Kääntäjän toteutus menee hankalaksi Ilman permutaatiosääntöä kentän etäisyys tietueen alusta on käännösaikainen vakio. Permutaation kanssa kenttä pitää etsiä joka kerta erikseen, koska sen paikka ei ole etukäteen tiedossa. Tietueisiin pitää tallettaa tieto siitä, missä mikäkin kenttä on.
Kysymys Onko seuraava lauseke hyvin tyypitetty? (λr : {x : Int}.r.x){x = 0, y = 1} Vastaus 1. x ja y ovat eri nimet 2. r.x on sallittu, koska r:ssä on kenttä x 3. lauseke itse on sallittu, jos argumentilla ja parametrilla on sama tyyppi 4. argumentin tyyppi on {x : Int, y : Int} 5. argumentin tyyppi on myös {x : Int} (susumptiosääntö) 6. parametrin tyyppi on {x : Int} 7. Vastaus on siis: lauseke on hyvin tyypitetty.
Kysymys Milloin T 1 T 2 <: T 1 T 2? Vastaus 1. Olkoon f : T 1 T 2 ja f : T 1 T 2. 2. Kysymys on siitä, milloin f kelpaa f :n paikalle? 3. Sen tulee ottaa vastaan ainakin kaikki f :lle kelpaavat argumentit, mutta enemmänkin saa sille kelvata: T 1 <: T 1. alityypitys on parametrin osalta kontravariantti 4. Se saa palauttaa mitä vain mitä f palauttaa, mutta ei enempää; se saa toke palauttaa vähemmän: T 2 <: T 2 alityypitys on paluutyypin osalta kovariantti 5. Näin ollen: T 1 <: T 1 T 2 <: T 2 T 1 T 2 <: T 1 T 2
Kysymys Milloin variantti on toisen variantin alityyppi? Vastaus Keskeinen kysymys on case-lausekkeen käyttäytyminen: case E of I 1 = I 1 E 1,..., I 1 = I 1 E n vaatii, että E:llä on enintään kentät I 1,..., I n. Kenttiä saadaan lisätä: n m I 1 : T 1,..., I n : T n <: I 1 : T 1,..., I m : T m Kentät saavat alityypittyä vapaasti: T 1 <: T 1 T n <: T n I 1 : T 1,..., I n : T n <: I 1 : T 1,..., I n : T n
Permutaatio f : {1,..., n} {1,..., n} f on bijektio I 1 : T 1,..., I n : T n <: I f (1) : T f (1),..., I f (n) : T f (n) on varianttien kanssa melko välttämätön. Kääntäjäteknistä ongelmaa ei ole: variantin kentät alkavat aina samasta kohtaa Permutaatio rikkoo edelleen antisymmetrian ja siten osittaisjärjestys-ominaisuuden Yksi ratkaisu tähän on käyttää eksplisiittistä tyyppiyhtäläisyysrelaatiota T 1 T 2 ja määritellä se seuraavasti: T 1 <: T 2 T 2 <: T 1 T 1 T 2
Top Top-tyyppi on hyödyllinen laajennus: tällöin kaikilla lausekepareilla on yhteinen tyyppi (niiden tyyppien join). Top-tyyppisellä arvolla ei voi juuri mitään tehdä. T ::= Top T <: Top
Bottom Bottom-tyyppi on myös hyödyllinen laajennus: se kelpaa kaikkiin konteksteihin Bottom-tyypissä ei ole arvoja Bottom-tyyppinen lauseke jää ikuiseen silmukkaan tai keskeyttää ohjelman Bottom-tyypin palauttava funktio ei koskaan palaa Monimutkaistaa tyyppitarkastusta T ::= Bottom T <: Bottom
Askriptio Muistathan: E : T on lauseke, joka väittää, että E:n tyyppi on T Varianttien kanssa oli pakollinen, ei enää Lauseke a = 5 voidaan tyypittää rauhassa a : Int Alityypitys huolehtii siitä, että se kelpaa sinne minne pitääkin ilman askriptiota Alityypityksen kanssa askriptio on ns. upcast: sillä saa tehdä tyyppimuunnoksen tyypistä sen ylityyppiin Myös downcast on mahdollinen valinta, mutta se vaatii ajonaikaisen tyyppitarkastuksen: Γ E : T 1 T 2 <: T 1 Γ (E : T 2 ) : T 2