27
Racket 4. JAKSO

Racket MOOC (kevät 2016) - jakso 4

Embed Size (px)

Citation preview

Page 1: Racket MOOC (kevät 2016) -  jakso 4

Racket 4. JAKSO

Page 2: Racket MOOC (kevät 2016) -  jakso 4

2

Sisällysluettelo 5A. REKURSIO (SILMUKKA)

1. Silmukat ja sivuvaikutukset

2. display-read, display-value, display-info, display-select

3. Ikuinen silmukka

4. Silmukka lopetusehdolla

5. Silmukka akkumulaattorilla

5B. REKURSIO (INDUKTIOPERIAATE)

6. Rekursio alkeistapauksen avulla

Page 3: Racket MOOC (kevät 2016) -  jakso 4

3

Rekursio

Funktio, joka kutsuu itse itseään on rekursiivinen.

Page 4: Racket MOOC (kevät 2016) -  jakso 4

4

Rekursiolla voi tehdä silmukan

Rekursiivisen funktion avulla voidaan toteuttaa silmukka, eli saadaan ohjelma toistamaan jotain toimintoa monta kertaa.

Jotta silmukka päättyy joskus, meillä on oltava lopetusehto (if tai cond).

Jotta silmukka ”muistaa” mitä on jo tehty, välituloksia säilytetään funktion parametreissa.

Kutsuttaessa rekursiivista funktiota, annamme lähtötilanteen argumentit. Kun lopetusehto toteutuu, funktiopalauttaa paluuarvon.

Page 5: Racket MOOC (kevät 2016) -  jakso 4

5

Silmukat ja sivuvaikutukset

Yksinkertaisin silmukka on ikuinen silmukka. Usein se on ohjelmointivirhe, jossa lopetusehto puuttuu tai ehto ei koskaan toteudu.

Seuraavaksi yksinkertaisin silmukka ottaa sisäänsä kierrosten lukumäärän ja lopettaa, kun vaadittu määrän toistoja on suoritettu.

Edellä mainitut silmukat ovat turhia, jos käytössämme on vain puhtaita funktioita. Jos ohjelmalla on ns. sivuvaikutuksia, nämä silmukat voivat olla myös hyödyllisiä. Sivuvaikutuksella tarkoitetaan koodia, joka ulottaa toimintansa funktion ulkopuolelle: muuttaa globaalia muuttujaa, tuottaa käyttäjälle ääntä tai kuvaa, kysyy käyttäjän syötettä, kirjoittaa tiedostoon jne.

Harjoittelemme sivuvaikutuksia ja silmukoita display-read – kirjaston avulla. Huom. Näiden funktioiden kanssa ei voi käyttää check-expect:iä!

(require teachpacks/display-read)

Page 6: Racket MOOC (kevät 2016) -  jakso 4

6

display-read display-read-number◦ display-read näyttää käyttäjälle kuvan/merkkijonon/luvun

(=sivuvaikutus) ja palauttaa käyttäjän editoriin kirjoittaman merkkijonon

◦ display-read-number muuntaa annetun merkkijonon luvuksi

display-read

ARGUMENTIT PALUUARVO

kuva”tikkataulu”

merkkijono

Asenna paketti DrRacket:issa:File -> Package managerPackage source: teachpacks (lopuksi paina enter)

sivuvaikutus

Page 7: Racket MOOC (kevät 2016) -  jakso 4

7

display-value◦ display-value näyttää käyttäjälle kuvan/merkkijonon/luvun ja

annetun arvon (jos sen voi näyttää) ja palauttaa annetun arvon

display-value

ARGUMENTIT PALUUARVO

merkkijono35

luku

”Tulos on:”

luku35

sivuvaikutus

Page 8: Racket MOOC (kevät 2016) -  jakso 4

8

display-infodisplay-info-timer◦ display-info näyttää käyttäjälle kuvan/merkkijonon/luvun ja palauttaa

annetun arvon ◦ display-info-timer ottaa lisäksi ajan, joka kertoo kunka kauan info-

ruutu pidetään näkyvissä)

display-info

ARGUMENTIT PALUUARVO

lukumerkkijono”Game over”

sivuvaikutus

”Game over”

Page 9: Racket MOOC (kevät 2016) -  jakso 4

9

display-select◦ display-select näyttää käyttäjälle näyttää käyttäjälle

kuvan/merkkijonon/luvun sekä listan valintavaihtoehtoja (kuvia/merkkijonoja/lukuja) ja palauttaa valitun arvon

display-select

PALUUARVO

merkkijono

sivuvaikutus

”kyllä”

ARGUMENTIT

merkkijono”Jatketaanko?”

lista(list ”kyllä” ”ei”)

Page 10: Racket MOOC (kevät 2016) -  jakso 4

10

begin ja let Jotta saamme funktion tekemään sivuvaikutuksia JA palauttamaan paluuarvon, pitää muodostaa koodilohko begin:in avulla.

Begin evaluoi sen sisällä olevat lausekkeet järjestyksessä, ”hukkaa” niiden tuottaman paluuarvon viimeistä lukuunottamatta ja palauttaa sen.

Jotta saamme talteen käyttäjän antamat syötteet, tarvitsemme lisäksi funktion sisäisiä muuttujia. Näihin ns. lokaalit muuttujan arvot määritellään let tai let* rakenteella (let* jos let-lauseke käyttää toista let-lauseketta).

muuttujan nimi muuttujan arvo

Page 11: Racket MOOC (kevät 2016) -  jakso 4

Ikuinen silmukka laskurilla

11

(define (silmukka i)

(silmukka (add1 i))))uusi kierros

(silmukka 0)käynnistys

uusi kierros

(begin (display-info-timer i 50)

uusi i:n arvo

i:n arvo alussa

Page 12: Racket MOOC (kevät 2016) -  jakso 4

12

Ikuinen silmukka(esimerkki)

Automaattilaskuri kysyy käyttäjältä syötteitä, tallentaa ne lokaaleihin muuttujiin (let), tutkii ovatko syötteet ok, jos ovat laskee tuloksen (kutsuu pinta-ala funktiota) ja ilmoittaa tuloksen käyttäjälle (display-value), ja palaa alkuun: (define (automaattilaskuri)

(let [(a (display-read-number ”Anna kanta:”)

(b (display-read-number ”Anna korkeus:”)]

(if (and (number? a)(number? b))

(begin (display-value ”Pinta-ala on:” (pinta-ala a b))

(automaattilaskuri))

(begin (display-info ”Anna lukuja!”)

(automaattilaskuri)))))

Tämä älykkäämpi versio kysyykäyttäjältä jatketaanko

parametreja ei tarvita

Page 13: Racket MOOC (kevät 2016) -  jakso 4

Silmukka laskurilla ja lopetusehdolla

13

(define (silmukka i)

(if (<= i 0)

”tämä on valmis”

(silmukka (sub1 i)))))

lopetusehto

loppuarvo

uusi kierros

uusi i:n arvo(silmukka 10)käynnistys

uusi kierros

(begin (<tehdään jotain>)

Page 14: Racket MOOC (kevät 2016) -  jakso 4

14

Silmukka laskurilla(esimerkki)

Rekursiiviselle funktiolle annetaan ”laskuri” - argumentti, jota vähennetään jokaisella kierroksella. Kun laskuri on nolla, silmukan suoritus päättyy.

Esim. Lähtölasku-silmukka: (define (lähtölasku laskuri)

(if (<= laskuri 0)

(display-info-timer ”LOPPU” 50)

(begin

(display-info-timer laskuri 50)

(lähtölasku (sub1 laskuri)))))

Lähtölasku-silmukan käynnistys (10, 9, 8, 7, 6, 5, 4, 3, 2, 1, LOPPU): (lähtölasku 10)

Page 15: Racket MOOC (kevät 2016) -  jakso 4

15

Silmukka akkumulaattorilla

Jos lisäämme silmukkaan (funktioon) yhden parametrin, akkumulaattorin, voimme tallentaa siihen tulosta pikkuhiljaa, kierros kierrokselta. Lopuksi voimme palauttaa akkumulaattoriin kerääntyneen ”valmiin” paluuarvon.

Esim. Tähdet-silmukka(define (tähdet i kuva) (if (<= i 0) kuva (tähdet (sub1 i) (place-image (star (* i 5) "solid" ”aqua")) (random 200)(random 200) kuva)))))

Tähdet-silmukan käynnistyksessä annetaan ”akkumulaattorille”-alkuarvo

(tähdet 10 (empty-scene 200 200))

akkumulaattori

Page 16: Racket MOOC (kevät 2016) -  jakso 4

16

Silmukka laskurilla ja akkumulaattorilla

(define (silmukka i tulos)

(if (<= i 0)

tulos

(silmukka (sub1 i) (f i tulos))))

lopetusehto

loppuarvo=akkumulaattori

uusi kierros

tallennetaan akkumulaattoriin tämän kierroksen tulos

uudet arvot

(silmukka 10 <tyhjä-tulos>)käynnistys

uusi kierros

Page 17: Racket MOOC (kevät 2016) -  jakso 4

17

Ympyräkuvio (kuva tallentuu akkumulaattoriin)

(define EPÄKESKO (overlay/xy (circle 30 "outline" "black")

100 30

(circle 20 0 "transparent")))

(define (pyöritä k osa kuva laskuri)

(if (< laskuri 0)

kuva

(pyöritä (+ k 5) osa (overlay (rotate k osa) kuva) (sub1 laskuri))))

(pyöritä 5 EPÄKESKO empty-image 100)

akkumulaattori

Page 18: Racket MOOC (kevät 2016) -  jakso 4

18

Kertolaskupeli(pisteet kerääntyvät akkumulaattoriin)

Arpoo kaksi lukua ja tallentaa ne lokaaleihin muuttujiin a ja b (let* [(a (random 10))

(b (random 10))

(vastaus (display-read-number (kysymys a b)))]

Kysyy käyttäjältä kertolaskun vastausta, tallentaa sen muuttujaan vastaus

Jos oikein, lisää pisteitä (pisteet on akkumulaattori) ja aloittaa uuden kierroksen

Jos väärin, ei lisää pisteitä ja aloittaa uuden kierroksen

Lataa esimerkkikoodi tästä.

vaatii let*, koska vastaus tarvitseea:n ja b:n ja niitä vasta määritellään

Page 19: Racket MOOC (kevät 2016) -  jakso 4

19

Arvaa mitä numeroa ajattelen(arvauskerrat kerääntyvät akkumulaattoriin)

Peli, jossa tietokone arpoo numeron ja pelaajaa kehoitetaan arvaamaan se. Tietokone antaa arvauksen perusteella vinkkejä ”pienempi” tai ”suurempi”.

Toteutettu silmukan avulla.

Käyttää valintalausetta (cond)

(cond [(and (number? arvaus)(< oikea arvaus))

"pienempi"]

[(and (number? arvaus)(> oikea arvaus))

"suurempi"]

[else "anna numero"])

Kierrokset tallennetaan akkumulaattoriin ja kerrotaan lopussa käyttäjälle.

Lataa esimerkkikoodi tästä.

Page 20: Racket MOOC (kevät 2016) -  jakso 4

20

Rekursio alkeistapauksen avulla

Joskus on tarve toteuttaa silmukoita, joissa lopputulos muodostuu hajoita ja hallitse menetelmällä eli lähdetään jakamaan ongelmaa pienemmäksi ja pienemmäksi, kunnes saavutetaan ns. alkeistapaus.

Rekursiota jatketaan siis kunnes alkeistapauksen ehto toteutuu ja sen arvo palautetaan kutsujalle, joka saa valmiiksi oman tuloksensa, joka palautetaan sen kutsujalle jne. Näin ei tarvita ”akkumulaattoria” vaan lopullinen vastaus saadaan kun päästään ensimmäiseen kutsujaan.

Esimerkiksi fraktaaleita piirrettäessa, aloitetaan isosta kuviosta, siirrytään pienempään, kunnes saavutetaan kuvion pienin piirrettävä osa.

Page 21: Racket MOOC (kevät 2016) -  jakso 4

21

Rekursio - alkeistapauksella

21

(define (r-funktio muuttuja)

(if (<alkeistapaus?>)

alkeistapaus

(f muuttuja (r-funktio (g muuttuja))

lopetusehto

alkeistapaus

uusi kierros

uusi kierros uudella muuttujan arvolla

(r-funktio 10)käynnistys

uusi kierros

Tämä funktio jää odottamaan lopputuloksia

Page 22: Racket MOOC (kevät 2016) -  jakso 4

22

Pienenevät pallot(define (pienenevät-pallot säde väri)

(if (<= säde 1)

(circle säde "solid" väri)

(beside

(circle säde "solid" väri)

(pienenevät-pallot (* säde (/ 4 5)) väri))))

(pienenevät-pallot 30 "red")

Alkeistapaus : pienin piirrettävä pallo

Page 23: Racket MOOC (kevät 2016) -  jakso 4

23

Sierpinskin kolmio – fraktaali

(require 2htdp/image)

(define (sierpinski koko)

(if (<= koko 2)

(triangle koko "outline" "blue")

(overlay (triangle koko "outline" "blue")

(let [(p-kolmio (sierpinski (/ koko 2)))]

(above p-kolmio

(beside p-kolmio p-kolmio))))))

(sierpinski 500)

Alkeistapaus : pienin piirrettävä kolmio

Page 24: Racket MOOC (kevät 2016) -  jakso 4

24

Vaatimattoman pojan palkka

Poika pyysi palkaksi ensimmäisenä päivänä 2snt, seuraavina päivinä aina 2 kertaa edellisen päivän palkka 20 päivän ajan. Kuinka paljon hän sai palkkaa yhteensä?

(define (laske-palkka p1 pv)

(if (<= pv 0)

0

(+ (expt p1 pv)

(laske-palkka p1 (sub1 pv)))))

(laske-palkka 2 20)

Alkeistapaus : 0 päivää töissä -> palkka 0 snt

ensimmäisen päivän palkkapäivä jota lasketaan

Lasketaan päivän palkkaja siirrytään seuraavaanpäivään

Page 25: Racket MOOC (kevät 2016) -  jakso 4

KOODIAAPINEN MOOC - SYKSY 2015

Vinkkejä viikkotehtävään

Tee oma versiosi jostakin viikon harjoitustehtävästä: laskuautomaatista, päässälaskutestistä tai kuvatehtävästä. Älä yritä tehdä liian monimutkaista ohjelmaa, muista että muut kurssilaiset arvoivat työsi!

math-utils – kirjastosta löytyvät funktiot pyöristämiseen sekä pinta-alan ja tilavuuden yksiköiden ilmoittamiseen.

Huomaa, että display-read – kirjastolla on eri nimi WeSchemessä!

(require wescheme/dhnSHUnLTh)

Huomaa, että math-utils –kirjastolla on eri nimi WeSchemessä!

(require wescheme/lenBmnorzi)

Page 26: Racket MOOC (kevät 2016) -  jakso 4

KOODIAAPINEN MOOC - SYKSY 2015

Vinkkejä viikkotehtävään

Koska display-read –kirjaston tuottamia sivuvaikutuksia ei voi testata automatisoidusti check-expect:ien avulla, on hyvä rajoittaa niiden käyttö vain yhteen kohtaan koodia ja pitää muu koodi ”puhtaana” sivuvaikutuksista.

1) Tee apufunktiosi puhtaina funktioina, ilman sivuvaikutuksia, ja testaa ne check-expectien avulla.

2) Käytä sivuvaikutuksia vain yhdessä funktiossa, siis siinä, joka toteuttaa silmukan:

◦ kysyy syötteet käyttäjältä (display-readin avulla), tallentaa lokaaleihin muuttujiin◦ tarkistaa, että syötteet ovat ok (if, cond...)◦ kutsuu apufunktioita, jotka tekevät ”itse asian” ( nämä on hyvin testattu check-

expect:in avulla!!!)◦ Ilmoittaa käyttäjälle tuloksen (display-readin avulla)

Page 27: Racket MOOC (kevät 2016) -  jakso 4

KOODIAAPINEN MOOC - SYKSY 2015

Vinkkejä viikkotehtäviin

(define (automaattilaskuri)(let [(a (display-read-number ”Anna kanta:”) (b (display-read-number ”Anna korkeus:”)] (if (and (number? a)(number? b))

(begin (display-value ”Pinta-ala on:” (pinta-ala a b)) (automaattilaskuri))

(begin (display-info ”Anna lukuja!”) (automaattilaskuri)))))

Sivuvaikutuksia sisältävä silmukka:

;; pinta-ala : Luku Luku -> Luku(define (pinta-ala a b) (* a b))

(check-expect (pinta-ala 10 30) 300)

Puhtaat funktiot (apufunktiot):

sivuvaikutukset

Ei sivuvaikutuksia.Testit!

Ei testejä