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,..., T, U,... Välimerkkejä λ ; τ = Vakiot ovat datakoostimien erityistapaus. Lausekkeet (ε ja sen alaindeksoidut versiot edustavat alilauseketta): x pohjalauseke muuttujalauseke ε 1 ε 2 kutsulauseke C konstruktorilauseke λx ε abstraktiolauseke case ε of ϕ 1 ε 1 ;... ; ϕ n ε n case-lauseke (n 1) let f 1 x 11... x 1m1 = ε 1 ;... ; f n x n1... x nmn = ε n in ε let-lauseke (n 1, m i 0) Kutsulausekkeet assosioivat vasemmalle, ts. ε 1 ε 2 ε 3 tarkoittaa (ε 1 ε 2 )ε 3. Lauseke on heikossa päänormaalimuodossa, jos se on konstruktorilauseke tai 1
abstraktiolauseke. Lauseke on normaalimuodossa, jos se on konstruktorilauseke, jonka alilausekkeet ovat normaalimuodossa, tai lambdalauseke, jonka alilauseke on heikossa päänormaalimuodossa. Lauseke on (vahvassa) päänormaalimuodossa, jos se on konstruktorilauseke tai lambdalauseke, jonka alilauseke on normaalimuodossa. Hahmot (ϕ): C x 1... x n koostinhahmo (n 0) (C x 1... x n ) laiska koostinhahmo (n 0) x muuttujahahmo Huomaa, että hahmot eivät ole rekursiivisia! Käytännössä muuttujan paikalle käy hahmossa aina myös jokeri (_). Tyypit (τ): T τ 1... τ n nimetty tyyppi (n 0) α τ 1 τ 2 tyyppimuuttuja funktiotyyppi Funktiotyyppi assosioi oikealle, ts. τ 1 τ 2 τ 3 on sama kuin τ 1 (τ 2 τ 3 ). Tyyppiskeema on muotoa (α 1,..., α n )τ. Tyyppitykset: ɛ :: τ x :: τ C :: τ T/n lausekkeen tyyppi muuttujan tyyppi konstruktorin tyyppi tyyppinimen parametrien määrä (n on lukuvakio) 2
Tyypityksissä x :: τ ja C :: τ voi τ poikkeuksellisesti olla myös tyyppiskeema. Tyyppiympäristö on tyypitysten joukko, jolla on seuraavat ominaisuudet: Se ei sisällä lausekkeen tyypitystä. Jos siinä on sekä x 1 :: τ 1 että x 2 :: τ 2 niin x 1 ja x 2 ovat eri muuttujia. Jos siinä on sekä C 1 :: τ 1 että C 2 :: τ 2 niin C 1 ja C 2 ovat eri konstruktoreja. Jos siinä on sekä T 1 /n 1 että T 2 /n 2 niin T 1 ja T 2 ovat eri tyyppikonstruktoreja. Tyyppiympäristöä merkitään usein Γ:lla. Tyyppiympäristön laajentaminen Γ, x :: τ tarkoittaa uutta tyyppiympäristöä, joka on muuten sama kuin Γ paitsi että se sisältää myös tyypityksen x :: τ (jos Γ:ssa on jokin toinen x:n tyypitys, se poistetaan). Vastaava laajennus toimii toki myös konstruktorin tyypityksellä ja tyyppinimen parametrien määrä -tyypityksellä. Arvoympäristö on muotoa x = ɛ olevien yhtälöiden joukko, jolla on se ominaisuus, että jos siinä on sekä x 1 = ε 1 ja x 2 = ε 2 niin x 1 ja x 2 ovat eri muuttujia. Arvoympäristöä merkitään usein Σ:lla. Arvoympäristöäkin laajennetaan edellä esitettyyn tapaan merkinnällä Σ, x = ɛ. Tyyppiväittämä on muotoa Γ ε :: τ. Korvausta merkitään tavanomaiseen tapaan ε{x 1 ε 1,..., x n ε n }. Tyyppisijoitus (σ) on äärellinen kuvaus (vrt. Haskellin Data.Map), joka liittää tyyppimuuttujaan tyypin. Merkitään τ σ:llä σ:n ilmaiseman korvauksen tekemisen τ:lla. 2 Tyyppiunikaatio Määritellään mgu(τ 1, τ 2 ) = σ seuraavasti: mgu(t τ 1... τ n, Uτ 1... τ n) = mgu(τ 1, τ 1) mgu(τ n, τ n) mgu(α, τ) = {(α τ)} mgu(τ, α) = {(α τ)} mgu(τ 1 τ 2, τ 3 τ 4 ) = mgu(τ 1, τ 3 ) mgu(τ 2, τ 4 ) kunhan τ:ssa ei esiinny α kunhan τ:ssa ei esiinny α 3
Jos mikään näistä yhtälöistä ei sovi, mgu ei ole siinä tapauksessa määritelty. Operaatio σ 1 σ 2 määritellään seuraavasti: jos σ 1 sisältää parin α τ ja σ 2 ei sisällä parin α:lle tai päinvastoin, σ 1 σ 2 sisältää ko. parin. Jos σ 1 sisältää parin α τ 1 ja σ 2 sisältää parin ατ 2, jos mgu(τ 1, τ 2 ) on olemassa, σ 1 σ 2 sisältää parin α mgu(τ 1, τ 2 ), muuten σ 1 σ 2 ei ole määritelty. 3 Tyyppijärjestelmä Tyyppialgoritmi on rekursiivinen. Sillä on syötteenä tyyppiväittämä, ja se joko onnistuu tai epäonnistuu. Tyyppialgoritmilla on myös tilamuuttujana sijoitus σ, joka on aluksi tyhjä. Tuota sijoitusta käytetään kaikkiin syötteissä esiintyviin tyyppeihin automaattisesti. Jos syöte on Γ :: τ, algoritmi onnistuu. Jos syöte on Γ x :: τ ja Γ:ssa on tyypitys x :: τ, tällöin σ korvataan σ mgu(τ, τ ):lla, jos se on olemassa. Jos tämä onnistuu, algoritmi onnistuu. Jos syöte on Γ C :: τ ja Γ:ssa on tyypitys C :: τ, tällöin σ korvataan σ mgu(τ, τ ):lla, jos se on olemassa. Jos tämä onnistuu, algoritmi onnistuu. Jos syöte on Γ ε 1 ε 2 :: τ, algoritmi onnistuu, jos se onnistuu rekursiivisesti syötteillä Γ ε 1 :: α τ ja Γ ε 2 :: α, missä α on uusi tyyppimuuttuja. Jos syöte on Γ λx ε :: τ, algoritmi onnistuu, jos se onnistuu rekursiivisesti syötteellä Γ, x :: α ε :: β, missä α ja β ovat uusia tyyppimuuttujia, ja jos σ:n korvaaminen σ mgu(τ, α β):lla onnistuu. Case-lausekeen case ε of ϕ 1 ε 1 ;... ; ϕ n ε n kohdalla tarkastetaan, että ε tyypittyy ja on samaa tyyppiä kuin jokainen hahmo (ts. niiden tyypeillä on mgu, joka lisätään σ:an) ja että kukin ε i tyypittyy ympäristössä, johon on lisätty kukin hahmossa ϕ i esiintyvälle muuttujalle ε:n tyypistä johdettu tyyppi. 4
Jos syöte on muotoa Γ let f 1 x 11... x 1m1 = ε 1 ;... ; f n x n1... x nmn = ε n in ε :: τ, rekursiivisesti käsitellään jokaisella i = 1,..., n tyyppiväittämä Γ λx i1... λx in ε i :: α i, missä jokainen α i on uusi tyyppimuuttuja; lisäksi käsitellään rekursiivisesti tyyppiväittämä Γ ε :: τ. Jos tämä kaikki onnistuu, algoritmi onnistuu. Edellä mainittu tyyppiympäristö Γ on Γ, f 1 :: α 1,..., f n :: α n ja Γ on Γ, f 1 :: ( γ 1 )α 1,..., f n :: ( γ n )α n, missä kukin γ i luettelee ne tyyppimuuttujat, jotka esiintyvät tyypissä α i σ. 4 Laskento Pitkälti kuten laajennettu aritmetiikka. Let-lausekkeet kuitenkin niin, että jokainen letissä määritelty f i x i1... x in = ε ymmärretään f i = λx i1... λx in ε. Lauseke (λx ε 1 )ε 2 on ns. β-redeksi ja sievenee muotoon ε 1 {x ε 2 }. 5