Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Racket jatko 5. Rekursio

1,455 views

Published on

Koodausta kouluun - Opettajan diat
- Rekursio

Published in: Education
  • Be the first to comment

  • Be the first to like this

Racket jatko 5. Rekursio

  1. 1. Racket – jatko 5. REKURSIO
  2. 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 2
  3. 3. Rekursio 3 Funktio, joka kutsuu itse itseään on rekursiivinen.
  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. 4
  5. 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) 5
  6. 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 6 display- read ARGUMENTIT PALUUARVO kuva ”tikkataulu” merkkijono Asenna paketti DrRacket:issa: File -> Package manager Package source: teachpacks (lopuksi paina enter) sivuvaikutus
  7. 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 7 display- value ARGUMENTIT PALUUARVO merkkijono 35 luku ”Tulos on:” luku 35 sivuvaikutus
  8. 8. display-info display-info-timer 8 ◦ 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”
  9. 9. display-select 9 ◦ 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”)
  10. 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). 10 muuttujan nimi muuttujan arvo
  11. 11. 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
  12. 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))))) 12 Tämä älykkäämpi versio kysyy käyttäjältä jatketaanko parametreja ei tarvita
  13. 13. 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>)
  14. 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) 14
  15. 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)) 15 akkumulaattori
  16. 16. Silmukka laskurilla ja akkumulaattorilla 16 (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
  17. 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) 17 akkumulaattori
  18. 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ä. 18 vaatii let*, koska vastaus tarvitsee a:n ja b:n ja niitä vasta määritellään
  19. 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ä. 19
  20. 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. 20
  21. 21. Rekursio - alkeistapauksella 2121 (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
  22. 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") 22 Alkeistapaus : pienin piirrettävä pallo
  23. 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) 23 Alkeistapaus : pienin piirrettävä kolmio
  24. 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) 24 Alkeistapaus : 0 päivää töissä -> palkka 0 snt ensimmäisen päivän palkka päivä jota lasketaan Lasketaan päivän palkka ja siirrytään seuraavaan päivään

×