Lisää laskentoa TIEA341 Funktio ohjelmointi 1 Syksy 2005
Kertausta: Laajennettu 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
Kertausta: Laaj. 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.
Kertausta: Redeksit 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 =...
Kertausta: 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 =...)
Kertausta: 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
Kertausta: 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
Asian pihvi? Laajennettu aritmetiikka on yksinkertaistettu versio osasta Haskellia Kaikki se, mitä laajennetusta aritmetiikasta on sanottu, pätee soveltuvin osin myös Haskelliin Erityisesti: Haskell on pohjimmiltaan laskentoa kääntäjän tehtävänä on laskea meidän puolestamme silti on erittäin hyödyllistä osata tarvittaessa laskea käsin Haskell noudattaa normaalijärjestystä tai oikeastaan graafinsievennystä
DAG esitys ja graafinsievennys DAG esitys Lausekkeen rakennepuu, jossa yhteiset alilausekkeet on samastettu x = 2 * 2 * + Graafinsievennys Sievennetään DAG esitystä tavalliseen tapaan, mutta korvataan louksi DAG:ssa sievennetyn alilausekkeen juurisolmu vastauksen juurisolmulla x * (2 + x) * 2
x = 2 * 2 * x * (2 + x) + * 2 Redeksi
4 * (2 + 4) * + 4 2 Redeksi
4 * 6 * 6 4 Redeksi
24 24
Algebralliset tyypit laaj. aritmetiikassa Algebrallisen tyypin määrittely on luettavissa kontekstittomana kielioppina, joka sanoo, minkä näköisiä ko. tyypin normaalimuotoiset lausekkeet ovat data RatList = Cons Rational RatList Nil Nil Cons q Nil (jokaisella q :: Rational) Cons q1 (Cons q2 Nil) (jokaisella q1, q2 :: Rational)...
Heikko päänormaalimuoto (WHNF) Lauseke on heikossa päänormaalimuodossa, jos: se on vakio, tai se on konstruktorilauseke ei vaadita, että konstruktorin argumentit olisivat WHNF WNHF Ei WNHF 42 x Cons 42 Nil f (Cons 42 Nil) Cons (f x) y g x r Nil
Heikosta päänormaalimuodosta vielä Normaalimuotoinen lauseke on aina WHNF WHNF lauseke ei ole aina normaalimuotoinen Normaalijärjestyksessä etenevä laskenta löytää aina WHNF:n ennen normaalimuotoa toki tuo WHNF voi olla normaalimuoto itsekin :) WNHF on avainkäsite, kun mietitään hahmonsovitusta
Hahmonsovitus 1 Laajennetaan laajennettua aritmetiikkaa lisäämällä case lausekkeet nyt aluksi ilman vahteja case e of p 1 -> e 1 p 2 -> e 2... p n -> e n Hahmo p i voi olla vakio muuttuja konstruktori, jonka argumentit ovat muuttujia (huomaa poikkeus Haskellista)
Case lausekkeen sievennyssääntö case e of p 1 -> e 1 p 2 -> e 2... p n -> e n Esiehto: e on WHNF muodossa case lauseketta ei voi sieventää, jos tämä ei päde käytännössä tarkoittaa sievennä e WHNF muotoon ensin Valitse hahmoista p i ylin, johon WHNFmuotoinen e sopii jos sellaista ei ole, case lauseketta ei voi sieventää Korvaa case lauseke lausekkeella e i korvaa kuitenkin hahmossa p i esiintyvät muuttujat niillä e i :n osalausekkeilla, johon ne osuvat
f x = Cons x Nil case f 42 of Nil -> 0 Cons x y -> x+1 ==> case Cons 42 Nil of Nil -> 0 Cons x y -> x+1 ==> (x+1)[x 42,y Nil] eli 42+1 ==> 43
Haskellin case lausekkeesta 1 Haskell sieventää case lausekkeen samalla tavalla Ensiksi kuitenkin rekursiivisten hahmojen käytöt puretaan sisäkkäisiksi case lausekkeiksi: case e of Cons x (Cons y Nil) -> e' ==> case e of Cons x tmp -> case tmp of Cons y Nil -> e'
Haskellin case lausekkeesta 2 Sama tehdään vahdeille: case e of Cons x Nil x > 0 -> e1 x < 0 -> e2 ==> case e of Cons x Nil -> case x > 0 of True -> e1 False -> case x < 0 of True -> e2