Uusi näkökulma TIEA341 Funktio ohjelmointi 1 Syksy 2005
Aloitetaan alusta... Otetaan uusi näkökulma Haskelliin ohjelmointi laskentana kertausta toisaalta, uusia käsitteitä toisaalta helpottanee sitten lopulta hahmottamaan, mistä funktio ohjelmoinnissa oikein on kyse: Funktio ohjelmointi on pohjimmiltaan laskentoa
Kohdekieli ja metakieli 1 Kohdekielellä tarkoitetaan kieltä, jota tarkastellaan Tällä kurssilla Haskell, laskinesimerkissä aritmetiikka Metakieli on kieli, jolla kohdekieltä tarkastellaan Tällä kurssilla suomi, laskinesimerkissä Haskell Toisaalta: kohdekieli esiintyy metakielisessä tekstissä suorina lainauksina. Hän sanoi: I like it here. englanti on tässä kohdekieli suomi on tässä metakieli
Kohdekieli ja metakieli 2 Jotta metakielellä voidaan puhua kohdekielestä, pitää metakielessä voida esittää kohdekielisiä ilmaisuja Hän sanoi: I like it here. jasenna 1 + 1 Yhteen (Luku 1) (Luku 1) On mahdollista, että metakieli ja kohdekieli ovat samat ns. metasirkulaarinen tilanne Kappas vain, sanoi mörökölli.
Eräs kohdekieli: Aritmetiikka Lasketaan rationaaliluvuilla vakiot yhteen, vähennys, kerto ja jakolasku Laajennetaan sitä määrittelyillä: vakio = lauseke funktio parametrit = lauseke esim: square x = x * x Huom! Haskellin alikieli :) Leibnitzin laki: samat voidaan korvata toisillaan ilman, että mikään muuttuu
Laskento nojaa Leibnitzin lakiin square x = x * x Laskentaympäristö: Vakioiden ja funktioiden määrittelyt, joita voi laskiessa käyttää 2 * square 3 + x ==> 2 * (3 * 3) + x ==> 2 * 9 + x ==> 18 + x
Laajennetun aritmetiikan laskusäännöt Normaalin aritmetiikan laskusäännöt, plus: Funktion laventaminen (ns. sievennys) Jos laskentaympäristössä on f x 1... x n = e ja lausekkeessa on osalausekkeena f e 1... e m ja n = m niin silloin osalauseke f e 1... e m voidaan korvata e:llä kunhan siinä ensin kukin x i korvataan e i :llä Vakion laventaminen funktion laventamisen erityistapaus, jossa n = m = 0.
Muuttujan korvaaminen lausekkeella Yllättävän yleinen toimenpide Merkintä: e[x 1 e 1,..., x n e n ] Tarkoittaa: lausekkeessa e korvataan kukin x i vastaavalla e i :llä Merkintä kuuluu metakieleen, ei kohdekieleen! Ts. (x + 1)[x 2] on metakielinen ilmaisu, joka tarkoittaa samaa kuin 2 + 1.
Esimerkki cube a = a * double a double a = a * a cube 42 ==> ( sievennys/cube) 42 * double 42 ==> ( sievennys/double) 42 * (42 * 42) ==> 42 * 1764 ==> 74088
Sievennyksestä vielä Alilauseketta, jota voidaan sieventää, sanotaan redeksiksi Funktiolauseke f e 1... e n on redeksi, jos ympäristössä on vastaava f x 1... x n =... Esim. 4 + 6 on yhteenlaskuredeksi, mutta x + 6 ei muuttujaa ei voi laskea yhteen kokonaisluvun kanssa Lausekkeessa voi olla useita redeksejä, ja redeksi voi olla toisen redeksin sisällä: f (2+2) sisältää kaksi redeksiä, jos laskentaympäristössä on f x =...
Normaalimuoto Normaalimuoto on sellainen lauseke, jossa ei ole yhtään redeksiä (ts. siihen ei voi soveltaa mitään sievennyssääntöä) Esimerkkejä: x + 1 f x (kun ympäristössä ei ole f x =...) 4 + x * 6 12 Mutta seuraavat eivät ole normaalimuodossa: 1 + 1, 4 + 4 * 5, f z (kun ympäristössä on f x =...)
Laskentajärjestys Monet lausekkeet voidaan laskea monessa eri järjestyksessä Jos lausekkeessa on useita redeksejä, voidaan valita, kumpi sievennetään ensin Esim. (2 * 3) + (4 * 6) kaksi * redeksiä Joskus valinnalla on merkitystä: Kun ympäristössä on f x = 2 ja g x = g (g x): f (g 2) kaksi redeksiä: f (g 2) ja g 2 jos sievennetään ulompi ensin: f (g 2) ==> 2 jos sisempi ensin: f (g 2) ==> f (g (g 2)) ==> f (g (g (g 2))) ==>...
Applikatiivinen järjestys Valitaan sievennettävä redeksi seuraavasti: valitaan vasemmanpuoleisin redeksi mutta jos sen sisällä on redeksi, valitaan sisälläolevista vasemmanpuoleisin mutta jos sen sisällä... jne Sisältä ulos päin strategia Argumentit ensin, sitten vasta sovelletaan funktiota Esimerkki: Kun ympäristössä on f x = 2 ja g x = g (g x): f (g 2) sievennetään g 2 ensin
Normaalijärjestys Valitaan uloimmista redekseistä vasemmanpuoleisin Ulkoa sisäänpäin strategia Korvaa funktiokutsut määrittelyillään ennen argumenttien sievennystä Esimerkki Kun ympäristössä on f x = 2 ja g x = g (g x): f (g 2) sievennetään ensin f (g 2) ==> 2 Teoreema (todistus sivuutetaan): Jos lausekkeella on normaalimuoto, normaalijärjestys löytää sen
Ohjelmoidaanpa edellinen data Expr = Const Rational App String [Expr] Add Expr Expr Sub Expr Expr Mul Expr Expr Div Expr Expr type Env = Map String ([String], Expr) sievenna :: Env > Expr > Expr
Sievennys, normaalijärjestyksessä sievenna _ (Add (Const n) (Const m)) = Const (n+m) sievenna _ (Sub (Const n) (Const m)) = Const (n m) sievenna _ (Mul (Const n) (Const m)) = Const (n*m) sievenna _ (Div (Const n) (Const m)) = Const (n/m) sievenna e (Add e1 e2) = apu e Add e1 e2 sievenna e (Sub e1 e2) = apu e Sub e1 e2 sievenna e (Mul e1 e2) = apu e Mul e1 e2 sievenna e (Div e1 e2) = apu e Div e1 e2... apu e op e1 e2 e1 /= e1' e2 /= e2' = sievenna e (op e1' e2') where e1' = sievenna e e1 e2' = sievenna e e2 apu _ op e1 e2 = op e1 e2
Sievennys jatkuu sievenna env (App f args) = case Map.lookup f env of Just (pars, e) length pars == length arg > sievenna env' e where env' = Map.union mp env args' = map (\a > ([],a)) args mp = zip pars args' _ > App f (map (sievenna env) args)