Esimerkki: Laskin (alkua) TIEA341 Funktio ohjelmointi 1 Syksy 2005

Samankaltaiset tiedostot
Jäsennys. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Tyyppejä ja vähän muutakin. TIEA341 Funktio ohjelmointi 1 Syksy 2005

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Taas laskin. TIES341 Funktio ohjelmointi 2 Kevät 2006

5.5 Jäsenninkombinaattoreista

Ohjelmointiharjoituksia Arduino-ympäristössä

TIEA341 Funktio-ohjelmointi 1, kevät 2008

TIEA341 Funktio-ohjelmointi 1, kevät 2008

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Muuttujatyypit ovat Boolean, Byte, Integer, Long, Double, Currency, Date, Object, String, Variant (oletus)

tään painetussa ja käsin kirjoitetussa materiaalissa usein pienillä kreikkalaisilla

Funktionimien kuormitus. TIES341 Funktio ohjelmointi 2 Kevät 2006

Luento 5. Timo Savola. 28. huhtikuuta 2006

Ohjelmoinnin perusteet Y Python

Laajennetaan vielä Ydin-Haskellia ymmärtämään vakiomäärittelyt. Määrittely on muotoa

Metodien tekeminen Javalla

Koottu lause; { ja } -merkkien väliin kirjoitetut lauseet muodostavat lohkon, jonka sisällä lauseet suoritetaan peräkkäin.

ITKP102 Ohjelmointi 1 (6 op)

Javan perusteet. Ohjelman tehtävät: tietojen syöttö, lukeminen prosessointi, halutun informaation tulostaminen tulostus tiedon varastointi

Java-kielen perusteet

Algoritmit 1. Demot Timo Männikkö

System.out.printf("%d / %d = %.2f%n", ekaluku, tokaluku, osamaara);

Ohjelmassa henkilön etunimi ja sukunimi luetaan kahteen muuttujaan seuraavasti:

TIEA341 Funktio-ohjelmointi 1, kevät 2008

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset

Java-kielen perusteet

Tyyppiluokat II konstruktoriluokat, funktionaaliset riippuvuudet. TIES341 Funktio-ohjelmointi 2 Kevät 2006

Harjoitus 3 (viikko 39)

Ohjelmoinnin perusteet Y Python

Ohjelmointi 1 Taulukot ja merkkijonot

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

Metodit. Metodien määrittely. Metodin parametrit ja paluuarvo. Metodien suorittaminen eli kutsuminen. Metodien kuormittaminen

Ohjelmoinnin perusteet Y Python

Java-kielen perusteet

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Luku 5. Monadit. 5.1 Siirrännän ongelma

Lisää laskentoa. TIEA341 Funktio ohjelmointi 1 Syksy 2005

ITKP102 Ohjelmointi 1 (6 op), arvosteluraportti

815338A Ohjelmointikielten periaatteet Harjoitus 7 Vastaukset

jäsennyksestä TIEA241 Automaatit ja kieliopit, syksy 2016 Antti-Juhani Kaijanaho 29. syyskuuta 2016 TIETOTEKNIIKAN LAITOS Kontekstittomien kielioppien

Java-kielen perusteita

Olio-ohjelmointi Javalla

System.out.printf("%d / %d = %.2f%n", ekaluku, tokaluku, osamaara);

Luku 3. Listankäsittelyä. 3.1 Listat

TIEA341 Funktio-ohjelmointi 1, kevät 2008

ITKP102 Ohjelmointi 1 (6 op)

Alkuarvot ja tyyppimuunnokset (1/5) Alkuarvot ja tyyppimuunnokset (2/5) Alkuarvot ja tyyppimuunnokset (3/5)

Harjoitustyön testaus. Juha Taina

Ohjelmoinnin perusteet Y Python

Harjoitus 4 (viikko 47)

13 Operaattoreiden ylimäärittelyjä

Se mistä tilasta aloitetaan, merkitään tyhjästä tulevalla nuolella. Yllä olevassa esimerkissä aloitustila on A.

Uusi näkökulma. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Sisällys. 1. Omat operaatiot. Yleistä operaatioista. Yleistä operaatioista

ITKP102 Ohjelmointi 1 (6 op), arvosteluraportti

1. Omat operaatiot 1.1

Ohjelmoinnin perusteet Y Python

11. Javan valintarakenteet 11.1

Muuttujien roolit Kiintoarvo cin >> r;

Luku 6. Dynaaminen ohjelmointi. 6.1 Funktion muisti

Ohjelmointi 1 C#, kevät 2013, 2. tentti

Ohjelmoinnin perusteet Y Python

Yhteydettömän kieliopin jäsennysongelma

TIEA241 Automaatit ja kieliopit, kevät 2011 (IV) Antti-Juhani Kaijanaho. 29. huhtikuuta 2011

C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. C-ohjelma. Operaatioiden suoritusjärjestys

Flash ActionScript osa 4

Algoritmit 1. Demot Timo Männikkö

5.3 Laskimen muunnelmia 5.3. LASKIMEN MUUNNELMIA 57

n. asteen polynomilla on enintään n nollakohtaa ja enintään n - 1 ääriarvokohtaa.

Kerta 2. Kerta 2 Kerta 3 Kerta 4 Kerta Toteuta Pythonilla seuraava ohjelma:

Harjoitus 2 (viikko 45)

TAMPEREEN TEKNILLINEN YLIOPISTO

Pythonin Kertaus. Cse-a1130. Tietotekniikka Sovelluksissa. Versio 0.01b

Ohjelmoinnin perusteet Y Python

Laiska laskenta, korekursio ja äärettömyys. TIEA341 Funktio ohjelmointi Syksy 2005

7. Näytölle tulostaminen 7.1

Ohjelmoinnin perusteet Y Python

Jäsennysalgoritmeja. TIE448 Kääntäjätekniikka, syksy Antti-Juhani Kaijanaho. 29. syyskuuta 2009 TIETOTEKNIIKAN LAITOS. Jäsennysalgoritmeja

Tapahtumapohjainen ohjelmointi. Juha Järvensivu 2007

Esimerkki 1: Kahviautomaatti.

811312A Tietorakenteet ja algoritmit Kertausta kurssin alkuosasta

Ohjelmoinnin perusteet Y Python

Sisällys. 12. Näppäimistöltä lukeminen. Yleistä. Yleistä

ICS-C2000 Tietojenkäsittelyteoria Kevät 2016

Kielioppia: toisin kuin Javassa

TIEA341 Funktio-ohjelmointi 1, kevät 2008


Ohjelmoinnin perusteet Y Python

Harjoitustyö: virtuaalikone

ITKP102 Ohjelmointi 1 (6 op), arvosteluraportti

Johdatus f90/95 ohjelmointiin. H, R & R luvut 1-3

811312A Tietorakenteet ja algoritmit Kertausta kurssin alkuosasta

Jatkeet. TIES341 Funktio ohjelmointi 2 Kevät 2006

Makrojen mystinen maailma lyhyt oppimäärä

14. Hyvä ohjelmointitapa 14.1

List-luokan soveltamista. Listaan lisääminen Listan läpikäynti Listasta etsiminen Listan sisällön muuttaminen Listasta poistaminen Listan kopioiminen

811120P Diskreetit rakenteet

ITKP102 Ohjelmointi 1 (6 op), arvosteluraportti

Perusteet. Pasi Sarolahti Aalto University School of Electrical Engineering. C-ohjelmointi Kevät Pasi Sarolahti

Transkriptio:

Esimerkki: Laskin (alkua) TIEA341 Funktio ohjelmointi 1 Syksy 2005

Esimerkki: Laskin Liukulukulaskentaa Yhteen, vähennys, kerto ja jakolaskut Syötteenä laskutehtävä, tulosteena tulos tai virheilmoitus

Ohjelman rakenne Syöte on merkkijono Laskennan helpottamiseksi se muutetaan ns. rakennepuumuotoon (laskutehtävän jäsennys ) Rakennepuumuotoinen laskutehtävä ratkaistaan Tuloksena tulos Se on muutettava merkkijonoksi tulostusta varten

Ohjelman rakenne data Laskutehtava =... data Tulos =... jasenna :: String > Either String Laskutehtava laske :: Laskutehtava > Tulos muotoile :: Tulos > String main :: IO ()

Laskutehtävä ja tulos data Laskutehtava = Luku Double Yhteen Laskutehtava Laskutehtava Vahennys Laskutehtava Laskutehtava Tulo Laskutehtava Laskutehtava Osamaara Laskutehtava Laskutehtava deriving (Show) data Tulos = LukuTulos Double VirheTulos String deriving (Show)

Laske (1) Primitiivirekursiolla: laske :: Laskutehtava > Tulos laske (Luku l) = LukuTulos l laske (Yhteen t1 t2) = case (laske t1, laske t2) of (VirheTulos s, VirheTulos s') > VirheTulos (s ++ \n ++ s') ensin lasketaan osatehtävät osatehtävän virhe on hoidettava (VirheTulos s, _) > VirheTulos s (_, VirheTulos s) > VirheTulos s (LukuTulos a, LukuTulos b) > LukuTulos (a + b) laske (Vähennä t1 t2) = (samaan tapaan) itse tehtävän ratkaisu laske (Tulo t1 t2) = (samaan tapaan) (jatkuu)

Laske (2) laske :: Laskutehtava > Tulos (jatkoa) laske (Osamaara t1 t2) = case (laske t1, laske t2) of (VirheTulos s, VirheTulos s') > VirheTulos (s ++ \n : s') (VirheTulos s, _) > VirheTulos s (_, VirheTulos s) > VirheTulos s (LukuTulos a, LukuTulos 0) > VirheTulos Nollalla jako (LukuTulos a, LukuTulos b) > LukuTulos (a / b)

Grrr... Aika sotkuista, vai mitä?... ja aika lailla samojen asioiden toistoa, mutta siten, että keskellä on vaihtelua Noh, tuohan vain tarkoittaa, että pitää abstrahoida eli tehdä funktio tai funktioita, joilla tuon tekeminen on helppoa Abstrahoidaan ensin virheenkäsittely

Tadaa andthen :: Tulos > (Double > Tulos) > Tulos andthen... laske :: Laskutehtava > Tulos laske (Luku l) = LukuTulos l laske (Yhteen t1 t2) = laske t1 `andthen` \d1 > laske t2 `andthen` \d2 > LukuTulos (d1+d2) laske (Vahennys t1 t2) = (samaan tapaan) laske (Tulo t1 t2) = (samaan tapaan) laske (Osamaara t1 t2) = laske t1 `andthen` \d1 > laske t2 `andthen` \d2 > if d2 == 0 then VirheTulos nollalla jako else LukuTulos (d1/d2)

andthen andthen :: Tulos > (Double > Tulos) > Tulos jos eka parametri on LukuTulos, anna se parametrifunktiolle, tulos on funktion tulos jos eka parametri on VirheTulos, palauta se andthen :: Tulos > (Double > Tulos) > Tulos andthen (LukuTulos d) f = f d andthen t@(virhetulos _) _ = t

laske (Yhteen (Luku 1) (Luku 1))

laske (Yhteen t1 t2) = laske t1 `andthen` \d1 -> laske t2 `andthen` \d2 -> LukuTulos (t1+t2) laske (Yhteen (Luku 1) (Luku 1)) laske (Luku 1) `andthen` \d1 > laske (Luku 1) `andthen` \d2 > LukuTulos (d1 + d2)

laske (Luku d) = LukuTulos d laske (Yhteen (Luku 1) (Luku 1)) laske (Luku 1) `andthen` \d1 > laske (Luku 1) `andthen` \d2 > LukuTulos (d1 + d2) LukuTulos 1 `andthen` \d1 > LukuTulos 1 `andthen` \d2 > LukuTulos (d1 + d2)

andthen (LukuTulos d) f = f d laske (Yhteen (Luku 1) (Luku 1)) laske (Luku 1) `andthen` \d1 > laske (Luku 1) `andthen` \d2 > LukuTulos (d1 + d2) LukuTulos 1 `andthen` \d1 > LukuTulos 1 `andthen` \d2 > LukuTulos (d1 + d2) (\d1 > (\d2 > LukuTulos (d1 + d2)) 1) 1

(\x ->... x...) t... t... laske (Yhteen (Luku 1) (Luku 1)) laske (Luku 1) `andthen` \d1 > laske (Luku 1) `andthen` \d2 > LukuTulos (d1 + d2) LukuTulos 1 `andthen` \d1 > LukuTulos 1 `andthen` \d2 > LukuTulos (d1 + d2) (\d1 > (\d2 > LukuTulos (d1 + d2)) 1) 1 (\d2 > LukuTulos (1 + d2)) 1

(\x ->... x...) t... t... laske (Yhteen (Luku 1) (Luku 1)) laske (Luku 1) `andthen` \d1 > laske (Luku 1) `andthen` \d2 > LukuTulos (d1 + d2) LukuTulos 1 `andthen` \d1 > LukuTulos 1 `andthen` \d2 > LukuTulos (d1 + d2) (\d1 > (\d2 > LukuTulos (d1 + d2)) 1) 1 (\d2 > LukuTulos (1 + d2)) 1 LukuTulos (1 + 1)

1 + 1 2 laske (Yhteen (Luku 1) (Luku 1)) laske (Luku 1) `andthen` \d1 > laske (Luku 1) `andthen` \d2 > LukuTulos (d1 + d2) LukuTulos 1 `andthen` \d1 > LukuTulos 1 `andthen` \d2 > LukuTulos (d1 + d2) (\d1 > (\d2 > LukuTulos (d1 + d2)) 1) 1 (\d2 > LukuTulos (1 + d2)) 1 LukuTulos (1 + 1) LukuTulos 2

Uusi tehtävä laske (Yhteen (Osamaara (Luku 1) (Luku 0)) (Luku 1))...

laske (Yhteen t1 t2) = laske t1 `andthen` \d1 -> laske t2 `andthen` \d2 -> LukuTulos (d1 + d2) laske (Yhteen (Osamaara (Luku 1) (Luku 0)) (Luku 1)) laske (Osamaara (Luku 1) (Luku 0)) `andthen` \d1 > laske (Luku 1) `andthen` \d2 > LukuTulos (d1 + d2)...

laske (Osamaara t1 t2) = laske t1 `andthen` \d1' -> laske t2 `andthen` \d2' -> if d2' == 0 then VirheTulos nollalla jako else LukuTulos (d1' / d2')... laske (Osamaara (Luku 1) (Luku 0)) `andthen` \d1 > laske (Luku 1) `andthen` \d2 > LukuTulos (d1 + d2) laske (Luku 1) `andthen` \d1' > laske (Luku 0) `andthen` \d2' > if d2' == 0 then VirheTulos nollalla jako else LukuTulos (d1' / d2') `andthen` \d1 > laske (Luku 1) `andthen` \d2 > LukuTulos (d1 + d2)...

laske (Luku d) = LukuTulos d... laske (Luku 1) `andthen` \d1' > laske (Luku 0) `andthen` \d2' > if d2' == 0 then VirheTulos nollalla jako else LukuTulos (d1' / d2') `andthen` \d1 > laske (Luku 1) `andthen` \d2 > LukuTulos (d1 + d2) LukuTulos 1 `andthen` \d1' > LukuTulos 0 `andthen` \d2' > if d2' == 0 then VirheTulos nollalla jako else LukuTulos (d1' / d2') `andthen` \d1 > LukuTulos 1 `andthen` \d2 > LukuTulos (d1 + d2)...

andthen (LukuTulos d) f = f d (\x ->... x...) t... t...... LukuTulos 1 `andthen` \d1' > LukuTulos 0 `andthen` \d2' > if d2' == 0 then VirheTulos nollalla jako else LukuTulos (d1' / d2') `andthen` \d1 > LukuTulos 1 `andthen` \d2 > LukuTulos (d1 + d2) if 0 == 0 then VirheTulos nollalla jako else LukuTulos (1 / 0) `andthen` \d1 > LukuTulos (d1 + 1)...

if True then e1 else e2 e1... LukuTulos 1 `andthen` \d1' > LukuTulos 0 `andthen` \d2' > if d2' == 0 then VirheTulos nollalla jako else LukuTulos (d1' / d2') `andthen` \d1 > LukuTulos 1 `andthen` \d2 > LukuTulos (d1 + d2) if 0 == 0 then VirheTulos nollalla jako else LukuTulos (1 / 0) `andthen` \d1 > LukuTulos (d1 + 1) VirheTulos nollalla jako `andthen` \d1 > lukutulos (d1 + 1)...

andthen t@(virhetulos _) _ = t... if 0 == 0 then VirheTulos nollalla jako else LukuTulos (1 / 0) `andthen` \d1 > LukuTulos (d1 + 1) VirheTulos nollalla jako `andthen` \d1 > lukutulos (d1 + 1) VirheTulos nollalla jako

Muistattehan andthen :: Tulos > (Double > Tulos) > Tulos andthen (LukuTulos d) f = f d andthen t@(virhetulos _) _ = t laske :: Laskutehtava > Tulos laske (Luku l) = LukuTulos l laske (Yhteen t1 t2) = laske t1 `andthen` \d1 > laske t2 `andthen` \d2 > LukuTulos (d1+d2) laske (Vahennys t1 t2) = (samaan tapaan) laske (Tulo t1 t2) = (samaan tapaan) laske (Osamaara t1 t2) = laske t1 `andthen` \d1 > laske t2 `andthen` \d2 > if d2 == 0 then VirheTulos nollalla jako else LukuTulos (d1/d2)

Ähh Selkeämpi, mutta on edelleen toistoa Voisiko tuon jotenkin kirjoittaa niin, että kussakin haarassa kutsutaan funktiota, jolle vain annetaan laskutoimitus, joka on suoritettava No tottahan toki:

andthen :: Tulos > (Double > Tulos) > Tulos (andthen kuten edellä) lift2t :: (Double > Double > Double) > Tulos > Tulos > Tulos precond2 :: (Double > Double > Bool) > String > (Tulos > Tulos > Tulos) > Tulos > Tulos > Tulos laske :: Laskutehtava > Tulos laske (Luku d) = LukuTulos d laske (Yhteen t1 t2) = lift2t (+) (laske t1) (laske t2) laske (Vahennys t1 t2) = lift2t ( ) (laske t1) (laske t2) laske (Tulo t1 t2) = lift2t (*) (laske t1) (laske t2) laske (Osamaara t1 t2) = (precond2 p s (lift2t (/))) (laske t1) (laske t2) where p _ x = x /= 0 s = nollalla jako

lift2t nostaa kaksiparametrisendouble funktion kaksiparametriseksi Tulos funktioksi lift2t :: (Double > Double > Double) > Tulos > Tulos > Tulos lift2t f t1 t2 = t1 `andthen` \d1 > t2 `andthen` \d2 > LukuTulos (f d1 d2) precond2 :: (Double > Double > Bool) > String > (Tulos > Tulos > Tulos) > Tulos > Tulos > Tulos precond2 p s f t1@(lukutulos d1) t2@(lukutulos d2) p d1 d2 = f t1 t2 otherwise = VirheTulos s precond2 _ t@(virhetulos _) _ = t precond2 t@(virhetulos _) = t precond2 estää funktion käyttämisen tilanteessa, jossa parametrit eivät sovi (kuten nollalla jako)

Ensimmäinen testiversio (1) data Laskutehtava =... deriving (Read, Show)... jasenna :: String > Either String Laskutehtava jasenna = Right. read muotoile :: Tulos > String muotoile = show main :: IO () main = do s < getline case s of "" > return () _ > do let (Right lt) = jasenna s tul = laske lt putstrln (muotoile tul) main

Ensimmäinen versio (2) Ei kovin käyttäjäystävällinen mutta on hyvä välivaihe testausta varten Kunnon jäsennys puuttuu Jäsennyksen virhetarkistus Kunnollinen tuloksen muotoilu puuttuu

Parempi muotoilu muotoile :: Tulos > String muotoile (LukuTulos d) = show d muotoile (VirheTulos s) = s

Jäsennys (1) Jäsennyksen tehtävänä on muuttaa merkkijono laskutehtävän rakennepuuksi: String > Laskutehtava virhetilanteiden vuoksi kuitenkin String > Either String Laskutehtava Jäsennys on erittäin paljon tutkittu ja hyvin ymmärretty ongelma

Jäsennys (2) Tavallisesti jäsennysongelma jaetaan kahtia: merkkijonon paloittelu sanasiksi vakiot, välimerkit ym. sanaslistan jäsentäminen Laskimen sanaset: data Sanaset = Vakio Double SulkuAuki SulkuKiinni Plus Miinus Kertaa Jako OutoMerkki Char deriving (Show)

palastele :: String > [Sanaset] palastele (' ':xs) = palastele xs palastele ('\t':xs) = palastele xs palastele ('\n':xs) = palastele xs palastele ('(':xs) = SulkuAuki : palastele xs palastele (')':xs) = SulkuKiinni : palastele xs palastele ('+':xs) = Plus : palastele xs palastele ('*':xs) = Kertaa : palastele xs palastele ('/':xs) = Jako : palastele xs palastele (' ':xs@(c:_)) '0' <= c && c <= '9' = let (d, r) = luku xs in Vakio ( d) : palastele r palastele (' ':xs) = Miinus : palastele xs palastele xs@(c:cs) '0' <= c && c <= '9' = let (d, r) = luku xs in Vakio d : palastele r otherwise = OutoMerkki c : palastele cs

luku :: String -> (Double, String) luku s = case span isdigit s of (n, '.':r) -> case span isdigit r of (m, r') -> (read (n++. ++m), r') (n, r) -> (read n, r) where isdigit c = '0' <= c && c <= '9'

Itse jäsennys Varsinainen jäsennys tehdään vaikkapa recursive descent tyylisesti siitä torstaina enemmän