Esittely latautuu. Ole hyvä ja odota

Esittely latautuu. Ole hyvä ja odota

Taas laskin TIES341 Funktio-ohjelmointi 2 Kevät 2006.

Samankaltaiset esitykset


Esitys aiheesta: "Taas laskin TIES341 Funktio-ohjelmointi 2 Kevät 2006."— Esityksen transkriptio:

1 Taas laskin TIES341 Funktio-ohjelmointi 2 Kevät 2006

2 Rakennepuutyyppi data Term = C Rational | T | F | V String | Term :+: Term| Term :-: Term | Term :*: Term| Term :/: Term | Term :==: Term| Term :/=: Term | Term : =: Term | Term : : Term | Let (String,Term) Term | If Term Term Term -- funktiokutsu | Term :@: Term -- rekursiivinen funktiomäärittely | Fun [(String,[String],Term)] Term deriving (Show,Eq,Ord)

3 Laskin ● Laskimen keskeiset määrittelyt: – eval :: (MonadError String e,MonadReader ValueEnv m) => Expr -> m Value – data Value = R Rational | B Bool | FV [String] [Value] ValueEnv – type ValueEnv = Map String Value ● eval on primitiivirekursiivinen! ● eval käyttää MonadReaderia laskentaympäristön hallintaan – laskentaympäristö: muuttujien arvot ko.kohdassa – koska muuttujiin ei voi sijoittaa, MonadReader riittää

4 Paloja laskimesta eval F = return (B False) eval (V s) = do e <- ask case lookupFM e s of Just v -> return v eval (t1 :+: t2) = do R v1 <- eval t1 R v2 <- eval t2 return $ apply (+) v1 v2 eval (Let (x,e) e') = do v <- eval e local (\env -> addToFM env x v) $ eval e' eval (If te th el) = do B ter <- eval te case ter of True -> eval th False -> eval el ● Huomaa: – laskin kaatuu, jos syötteessä on tyyppivirheitä ● sen sijaan nollallajakaminen aiheuttaa siistin poikkeuksen ● tarkoituksellista!

5 Funktiot ● Funktio on arvo, joka pitää sisällään: – termin – muuttujanimien (“parametrien”) listan – laskentaympäristön ● termin vapaiden muuttujien arvot funktionluontikohdassa! ● (Täysi) funktiokutsu: – funktiotermi lasketaan ympäristössä, jossa parametreille on annettu argumenttilausekkeiden arvot ● huom! laskentaympäristö johdetaan funktiossa mukana pidetystä laskentaympäristöstä, ei kutsun ympäristöstä – muuten tulee ns. “dynamic scoping”, jossa funktio näkee kutsujansa paikalliset muuttujat

6 Osittaiskutsu ● Jos funktiolla on 3 parametria ja sitä kutsutaan kahdella, mitä tapahtuu? – palautetaan funktio, joka ottaa sen puuttuvan, kolmannen parametrin – tätä sanotaan osittaiskutsuksi (partial application) ● Osittaiskutsun vuoksi funktioarvo sisältää em:n lisäksi: – listan arvoja, jotka on osittaiskutsuilla annettu osalle parametreista

7 Arvot data Value = R Rational | B Bool | FV [String] [Value] Term ValueEnv deriving (Show) Funktion parametrit Jo annettujen argumenttien arvot

8 Kutsu eval (f :@: e) = do FV xs vs b env <- eval f ev <- eval e let vs' = ev : vs case length xs == length vs' of True -> local (\_ -> Map.union (Map.fromList (zip xs (reverse vs'))) env) $ eval b False -> return $ FV xs vs' b env

9 Funktioiden määrittely eval (Fun defs t) = do env <- ask let fs = map (\(f,ps,b) -> (f, FV ps [] b env)) defs local (\env -> Map.fromList fs `Map.union` env) $ eval t

10 Tyyppitarkastus ● Tyyppitarkastus pitää huolen siitä, että lauseke on “hyvinmääritelty” – ei yritetä laskea funktioita yhteen – ei yritetä käyttää muuttujia, joita ei ole määritelty ● Laskimen ei tarvitse tarkistaa näitä – mahdollisesti jopa nopeusetu – tyyppivirheet havaitaan heti alussa ● Periaate: – lasketaan lausekkeen arvo “abstraktisti” – eli lasketaan tyypeillä (arvojoukoilla) ei arvoilla – primitiivirekursio, pääsääntöisesti etenee rakennepuun latvoista tyveen

11 Tyypit data Type = RT | BT | Type :-> Type deriving (Show,Eq,Ord)

12 Ongelma: funktioiden tyyppitarkastus ● Miten selvittää funktion tyyppi, jos sitä ei ole kerrottu? ● Miten selvittää keskenään rekursiivisten funktioiden tyypit?! ● Ratkaisu: – “arvataan”, että kaksiparametrisen funktion tyyppi on vaikkapa a -> b -> c – annetaan tyyppitarkastuksen tarkentaa nuo tyyppimuuttujat

13 Tyypit, uudestaan data Type = RT | BT | TVar Int | Type :-> Type deriving (Show,Eq,Ord)

14 Korvaus ● Korvaus on kuvaus tyyppimuuttujilta tyypeille ● Korvasta voidaan soveltaa tyyppeihin: – korvataan tyypissä esiintyvät tyyppimuuttujat samanaikaisesti korvauksen mukaisilla tyypeillä type Subst = Map Int Type subst :: MonadState Subst m => Type -> m Type subst RT = return RT subst BT = return BT subst (TVar n) = do sb <- get case Map.lookup n sb of Just ty -> return ty Nothing -> return $ TVar n subst (t :-> u) = do t' <- subst t u' <- subst u return (t' :-> u')

15 Unifikaatio (1) ● Unifikaatio-ongelma: – Onko olemassa korvaus, joka saa nämä kaksi tyyppiä olemaan samat? ● Robinsonin unifikaatio-algoritmi (JACM 1965): – vertaile kahden tyypin konstruktoria: onko samat? – jos kyseessä ei ole TVar, käy rekursiivisesti läpi alityypit ● esim. t -> u ==> unify t, unify u – jos jompi kumpi on TVar, lisää korvaukseen sijoitus tuosta muuttujasta toiseen tyyppiin – jos kumpikaan ei ole TVar eikä niillä ole samat konstruktorit, unifikaatio epäonnituu

16 Unifikaatio (2) occursIn :: Int -> Type -> Bool n `occursIn` TVar n' = n == n' n `occursIn` (t :-> u) = n `occursIn` t && n `occursIn` u _ `occursIn` _ = False unify :: (MonadError String m, MonadState Subst m) => Type -> Type -> m () unify RT RT = return () unify BT BT = return () unify (t :-> u) (t' :-> u') = do unify t t' v <- subst u v' <- subst u' unify v v' unify (TVar n) ty | n `occursIn` ty = throwError "occurs check failed" | otherwise = modify (\sb -> addToFM sb n ty) unify t1 t2@(TVar _) = unify t2 t1 unify _ _ = throwError "unification failed"

17 “Occurs check” ● Jos ollaan lisäämässä sijoitusta muuttujasta a tyyppiin t, pitää tarkistaa, esiintyykö a t:ssä ● jos esiintyy, niin tyyppi on äärettömän pitkä ● se on hylättävä

18 Tyyppitarkastus ● Tyyppi, jota ei heti pystytä päättelemään, jätetään avoimeksi – laitetaan tyypiksi uusi tyyppimuuttuja ● sellainen, jota ei ole vielä käytetty ● vrt. D4:n UniqueSupply ● Tyyppien samuuden tarkastamisen sijasta koetetaan unifioida ne ● Koodi nähtiin viime luennolla

19 Polymorfismi? ● Edellä esitelty tyyppimuuttujatemppu ratkaisee mainiosti funktioiden tyypityksen ongelman ● Sivutuotteena syntyy “melkein geneerisiä” tyyppejä – esim. id x = x, tyypitys a -> a – mutta ei täysin ● fun g x y = 0; id x = x in g (id 3) (id True) – ei tyypity oikein, koska id on monomorfinen: sitä voi käyttää vain yhden tyypin kanssa ● Ratkaisu: joka kerta kun funktion nimi kysytään ympäristöstä, annetaan sille eri tyyppimuuttujat

20 Tyyppiskeemat ja tyypin yleistäminen ● Tyyppiskeema on tyyppimuuttujajoukon (listan) ja tyypin muodostama pari – idea: listatut tyyppimuuttujat ovat “geneerisiä” eli “polymorfisia”, muut “monomorfisia” – Tyyppiympäristö yhdistää nyt muuttujia tyyppiskeemoihin ● Fun-rakenteen tyypitys etenee seuraavasti: – “arvataan” funktioiden tyypit – tyypitetään funktiot ympäristössä, jossa arvatut tyypit ovat monomorfisia (tyyppiskeeman tyyppimuuttujalista on tyhjä) – tyypitetään “in”-lauseke ympäristössä, jossa funktioiden tyypit ovat geneerisiä

21 Yleistämisestä ● Yleistäminen tapahtuu fun-lausekkeen tyypityksen yhteydessä kun määritellyt funktiot on tyypitetty mutta ennen kuin “in”-lauseke tyypitetään ● Kunkin funktion tyypistä yleistetään kaikki ne tyyppimuuttujat, jotka eivät esiinny vapaana fun-lausekkeen tyyppiympäristön tyypeissä – “vapaana” tarkoittaa: ei ole geneerinen muuttuja ko. yhteydessä


Lataa ppt "Taas laskin TIES341 Funktio-ohjelmointi 2 Kevät 2006."

Samankaltaiset esitykset


Iklan oleh Google