Ohjelmoinnin peruskurssien laaja oppimäärä

Samankaltaiset tiedostot
Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

815338A Ohjelmointikielten periaatteet Harjoitus 7 Vastaukset

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Tutoriaaliläsnäoloista

Ohjelmoinnin peruskurssien laaja oppimäärä

Luku 6. Dynaaminen ohjelmointi. 6.1 Funktion muisti

Scheme-kesäkurssi luento 1

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Scheme-kesäkurssi luento 3

Ohjelmoinnin peruskurssien laaja oppimäärä

Scheme-kesäkurssi luento 2

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssien laaja oppimäärä

Imperatiivisen ohjelmoinnin peruskäsitteet. Meidän käyttämän pseudokielen lauseiden syntaksi

11/20: Konepelti auki

IDL - proseduurit. ATK tähtitieteessä. IDL - proseduurit

ATK tähtitieteessä. Osa 3 - IDL proseduurit ja rakenteet. 18. syyskuuta 2014

Scheme-kesäkurssi luento 5

Ohjelmoinnin peruskurssi Y1

Tietorakenteet ja algoritmit

Algoritmit 1. Luento 3 Ti Timo Männikkö

Ohjelmoinnin perusteet Y Python

13. Loogiset operaatiot 13.1

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin peruskurssien laaja oppimäärä

Vasen johto S AB ab ab esittää jäsennyspuun kasvattamista vasemmalta alkaen:

815338A Ohjelmointikielten periaatteet

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen

Scheme-kesäkurssi luento 4

Ohjelmoinnin peruskurssien laaja oppimäärä, kevät

REKURSIO. Rekursiivinen ohjelma Kutsuu itseään. Rekursiivinen rakenne. Rakenne sisältyy itseensä. Rekursiivinen funktio. On määritelty itsensä avulla

Tietorakenteet ja algoritmit

Tietorakenteet ja algoritmit - syksy

Jatkeet. TIES341 Funktio ohjelmointi 2 Kevät 2006

Ohjelmoinnin perusteet Y Python

811120P Diskreetit rakenteet

Luento 4 Aliohjelmien toteutus

C++11 lambdat: [](){} Matti Rintala

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

Tähtitieteen käytännön menetelmiä Kevät 2009 Luento 4: Ohjelmointi, skriptaus ja Python

A TIETORAKENTEET JA ALGORITMIT

ELM GROUP 04. Teemu Laakso Henrik Talarmo

Algoritmit 2. Luento 13 Ti Timo Männikkö

Ohjelmoinnin peruskurssi Y1

Algoritmit 1. Luento 13 Ti Timo Männikkö

5/20: Algoritmirakenteita III

13. Loogiset operaatiot 13.1

812341A Olio-ohjelmointi, I Johdanto

Tähtitieteen käytännön menetelmiä Kevät 2009 Luento 5: Python

Ohjelmoinnin perusteet Y Python

Kysymyksiä koko kurssista?

815338A Ohjelmointikielten periaatteet

JOHDATUS TEKOÄLYYN TEEMU ROOS

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssi Y1

Pythonin alkeet Syksy 2010 Pythonin perusteet: Ohjelmointi, skriptaus ja Python

Ohjelmointi 1 / syksy /20: IDE

ICS-C2000 Tietojenkäsittelyteoria Kevät 2016

Algoritmit 2. Luento 8 To Timo Männikkö

Ohjelmoinnin peruskurssien laaja oppimäärä

Jakso 4 Aliohjelmien toteutus

Aliohjelmatyypit (2) Jakso 4 Aliohjelmien toteutus

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssi Y1

Harjoitus 1 -- Ratkaisut

Jakso 4 Aliohjelmien toteutus

Racket ohjelmointia osa 2. Tiina Partanen Lielahden koulu 2014

Ohjelmoinnin peruskurssien laaja oppimäärä

ITKP102 Ohjelmointi 1 (6 op)

Ohjelmoinnin peruskurssi Y1

Luento 4 Aliohjelmien toteutus

2. Seuraavassa kuvassa on verkon solmujen topologinen järjestys: x t v q z u s y w r. Kuva 1: Tehtävän 2 solmut järjestettynä topologisesti.

Java kahdessa tunnissa. Jyry Suvilehto

811312A Tietorakenteet ja algoritmit, , Harjoitus 7, ratkaisu

Transkriptio:

Ohjelmoinnin peruskurssien laaja oppimäärä Luento 1: Rekursiivinen ajattelutapa, Scheme-kielen perusteita (mm. SICP 11.2.4) Riku Saikkonen 10. 10. 2011

Sisältö 1 Kurssijärjestelyitä 2 Perusteita Scheme-kielestä, häntärekursio 3 Rekursio 4 Lukuohjeita SICP-kirjaan

Kurssijärjestelyitä kurssin sivuilla on nyt: SICP-kirjasta käsiteltävät kohdat ohjeita Schemen käytöstä ensimmäiset harjoitustehtävät (2 kierrosta 4:stä, deadlinet 21.10. ja 7.11.) hakekaa itsellenne Niksulan tunnus (T-talon huoneesta B210, vaikka luennon jälkeen) tehtäviin saa apua IRC:stä (kurssin kanavalta tai assistentilta) voimme järjestää myös laskuharjoituksia tms., jos niille näyttää olevan tarvetta pyyntö: olisi kiva, jos seuraisitte kurssiin kuluvaa aikaa sillä yritämme saada laajankin version syksyn kurssista mahtumaan 5 op:een eli noin 133 tuntiin

Kurssin käyttämä Schemen versio syksyn kurssilla käytetään Scheme-kielen R 5 RS-nimistä versiota ei siis uudempaa R 6 RS-versiota käytämme Scheme-toteutusta nimeltä Gambit-C http://www.iro.umontreal.ca/~gambit/ interaktiivinen tulkki ja tehokas kääntäjä hyvä debuggeri melko helppo liittää muihin ohjelmointikieliin kurssin käyttämä Scheme-toteutus löytyy Niksulasta: use scheme; scheme laajan kurssin sivuilla on ohje sen asentamisesta omalle koneelle

Sisältö 1 Kurssijärjestelyitä 2 Perusteita Scheme-kielestä, häntärekursio 3 Rekursio 4 Lukuohjeita SICP-kirjaan

Scheme ja Python Schemessä ja Pythonissa on paljon samaa, esimerkiksi: dynaaminen tyypitys (tyyppejä ei näy koodissa) samantapainen sisennystyyli (tosin Scheme ei pakota siihen) interaktiivinen tulkki ja Schemessä on erilaista muun muassa: perussyntaksi (esim. sulut) silmukkarakenteiden sijaan käytetään rekursiota muuttujien määrittelytapa ei olioita (ja funktioita käytetään enemmän) Pythonia paljon pienempi kieli monta eri toteutusta, joissa on omat standardikirjastot

Pieni Scheme-esimerkki (SICP 1.2.4) Kaksi potenssiinkorotusalgoritmia b n (define (square n) (* n n)) (define (slow-expt b n) (if (= n 0) 1 (* b (slow-expt b (- n 1))))) (define (fast-expt b n) (cond ((= n 0) 1) ((even? n) (square (fast-expt b (/ n 2)))) (else (* b (fast-expt b (- n 1)))))) Testiajo: (fast-expt 2 150) 1427247692705959881058285969449495136382746624

Silmukat ja häntärekursio (SICP 1.2.1) lausekielissä käytetään paljon silmukoita (for, while, jne.) Schemessä tyypillisempää on tehdä apufunktio, joka kutsuu itseään häntärekursiivisesti eli niin, että funktiokutsun jälkeen ei tehdä mitään Schemessä tämä on tehokasta (Javassa ja Pythonissa pino kasvaisi) häntärekursiivista koodia { voi lukea matemaattisemmin p jos c > n esim. iter(p, c) = iter(c p, c + 1) muuten Scheme (define (factorial n) (define (iter p c) (if (> c n) p (iter (* c p) (+ c 1)))) (iter 1 1)) Python rekursiivisesti def factorial(n): def iter(p, c): if c > n: return p else: return iter(c*p, c+1) return iter(1, 1) Python def factorial(n): p = 1 c = 1 while c <= n: p = c * p c = c + 1 return p

Tavallisessa rekursiossa pino kasvaa (SICP 1.2.1) Rekursiivinen kertomafunktio (define (fact n) (if (= n 0) 1 (* n (fact (- n 1))))) esim. (fact 4):ää evaluoidessa pinoon jää lauseke (* 4 ), kun (fact (- 4 1)):tä kutsutaan perustapaukseen päästessä pinossa on (* 4 (* 3 (* 2 (* 1 )))) oikealla on pino enemmän todellisuutta vastaavassa muodossa (tosin se riippuu toteutuksesta... ) Kutsupino lopussa: Paluuosoite fact:iin fact:n argumentti n=0 Paluuosoite fact:iin fact:n argumentti n=1 Paluuosoite fact:iin fact:n argumentti n=2 Paluuosoite fact:iin fact:n argumentti n=3 Paluuosoite tulkkiin fact:n argumentti n=4...

Häntärekursiossa pinon ei tarvitse kasvaa (SICP 1.2.1) Häntärekursiivinen kertoma (define (f-iter p c n) (if (> c n) p (f-iter (* c p) (+ c 1) n))) (define (fact n) (f-iter 1 1 n)) nyt (fact 4):ää evaluoidessa menossa on koko ajan vain yksi f-iter:n kutsu Kutsupino lopussa: Paluuosoite fact:iin f-iter:n argumentti p=24 f-iter:n argumentti c=5 f-iter:n argumentti n=4 Paluuosoite tulkkiin fact:n argumentti n=4... ensin (f-iter 1 1), sitten (f-iter 1 2),..., lopuksi (f-iter 24 5), joka palauttaa 5

Muita tapoja tehdä silmukoita Schemessä on myös muutama silmukkarakenne: nimetty let: lyhyempi syntaksi häntärekursiiviselle silmukalle do: yleistetty tavanomainen for- ja while-silmukka nämä on periaatteessa toteutettu funktionaalisesti häntärekursiolla näitä ei kuitenkaan yleensä käytetä (varsinkaan do:ta) lisäksi Schemen makroilla olisi helppo määritellä omia silmukkarakenteita (nämäkin kaksi voi toteuttaa makroilla) Nimetty let (define (factorial n) (let iter ((p 1) (c 1)) (if (> c n) p (iter (* c p) (+ c 1))))) do (define (factorial n) (do ((p 1 (* c p)) (c 1 (+ c 1))) ((> c n) p)))

Globaalien ja paikallisten muuttujien määritteleminen Schemessä on monta tapaa määritellä muuttujia ja proseduureja, mutta melkein aina kannattaa käyttää alla olevia tapoja globaalit muuttujat (vain päätasolla): globaali proseduuri: (define (f x)...) tai (define f (lambda (x)...)) globaali muuttuja: (define x 3) paikalliset (esim. funktion sisäiset) muuttujat: paikallinen proseduuri: (define (f x)...) (let ((f (lambda (x)...)))...) toimii myös, mutta tällöin funktiossa ei voi viitata itseensä paikallinen muuttuja: (let ((x 3))...) useampi edellisiin viittaava paikallinen muuttuja: (let* ((x 3) (y (+ x 1)))...) eri tapoihin määritellä muuttujia palataan tulkkien yhteydessä, mutta nämä säännöt riittävät käytännön ohjelmointiin

Sisältö 1 Kurssijärjestelyitä 2 Perusteita Scheme-kielestä, häntärekursio 3 Rekursio 4 Lukuohjeita SICP-kirjaan

Rekursiivinen ajattelutapa Tässä eräs tapa ratkaista ohjelmointiongelma rekursiivisesti (vrt. matemaattinen induktio): 1 Etsi perustapaukset eli triviaaliratkaisu. 2 Keksi tapa ratkaista iso ongelma muokkaamalla pienemmän ongelman ratkaisua tai yhdistämällä useamman pienemmän ongelman ratkaisut. Esimerkki: Kuinka monella eri tavalla annettu luku voidaan jakaa tekijöihin? (ei vain alkulukuihin esim. 12 = 2 2 3 = 2 6 = 3 4 eli 3 tavalla) Helpommin ratkaistava versio: Kuinka monella eri tavalla n voidaan jakaa tekijöihin käyttäen vain m 2:ta tai suurempia lukuja? Perustapaus: 0 tapaa, jos m m > n

Rekursiivinen ajattelutapa: tekijöihinjakoesimerkki Määritellään proseduuria f (n, m) = kuinka monella eri tavalla n voidaan jakaa tekijöihin käyttäen vain m:ää tai suurempia lukuja? Perustapaus: f (n, m) = 0, jos m m > n Helpompien ongelmien (pienempi n tai isompi m lähestyy perustapausta) ratkaisujen avulla kaksi vaihtoehtoa: jos n ei ole jaollinen m:llä, f (n, m) = f (n, m + 1) (sillä tekijoissä ei ole m:ää) muuten f (n, m) = 1 + f (n/m, m) + f (n, m + 1). Scheme-koodina (define (divisible? n m) (= (remainder n m) 0)) (define (f n m) (cond ((> (* m m) n) 0) ((divisible? n m) (+ 1 (f (/ n m) m) (f n (+ m 1)))) (else (f n (+ m 1))))) (define (ways-to-factor n) (f n 2))

Toinen rekursioesimerkki: Robotit ruudukossa ### # # ### # # # ### eräs tehtävä (tai osa siitä) tämänvuotisesta NCPC-ohjelmointikilpailusta: robotti lähtee ruudukon vasemmasta yläkulmasta ja osaa liikkua vain oikealle tai alas, muttei seinään # voiko se päästä oikeaan alakulmaan, ja montako eri reittiä sinne on? miten ratkaisisit tämän Pythonilla tai Schemellä? rajapinta esim. (numpaths f n), missä n on ruudukon koko (n n) ja (f x y) palauttaa 1 jos ruudussa (x, y) on seinä, muuten 0 (tai Pythonissa numpaths(f, n), ja f voisi toki olla funktion sijaan kaksiulotteinen taulukko) älä mieti tehokkuutta vielä

Ratkaisu rekursiolla Scheme-koodina (define (numpaths f n) (define (paths-from x y) (cond ((or (>= x n) ; reunan yli? (>= y n) (= (f x y) 1)) ; seinässä? 0) ((= x y (- n 1)) ; perillä? 1) ; maalista itseensä 1 polku (else (+ (paths-from (+ x 1) y) ; oikealle (paths-from x (+ y 1)))))) ; ja alas (paths-from 0 0)) tällainen rekursiivinen ratkaisu on nopea tehdä, muttei tässä esimerkissä kovin tehokas ei siksi että rekursio olisi sinänsä hidasta, vaan koska apufunktiota kutsutaan monta kertaa samoilla argumenteilla ohjelmointikilpailussa tätä piti optimoida tallentamalla jo laskettuja apufunktion arvoja (eli nk. dynaamisella ohjelmoinnilla)

Generatiivinen ja strukturaalinen rekursio lisäesimerkki rekursiosta kirjan kohdassa 1.2.2 (Counting change) edellisten esimerkkien kaltainen päättely on yksi rekursion käyttötarkoitus rekursiota voi ajatella olevan kahdenlaista: rakenteellinen (structural) rekursio: käydään jokin monimutkainen tietorakenne läpi pala kerrallaan rekursiivisesti (esim. edellisen esimerkin ruudukko parempia esimerkkejä SICP luvussa 2 listojen yhteydessä) generatiivinen (generative) rekursio: ohjelma tuottaa osaongelmia itse (kuten tekijöihinjakoesimerkissä) (nämä termit eivät ole kovin yleisessä käytössä)

Sisältö 1 Kurssijärjestelyitä 2 Perusteita Scheme-kielestä, häntärekursio 3 Rekursio 4 Lukuohjeita SICP-kirjaan

Lukuohjeita nopea tapa seurata oppikirjaa (SICP) on jättää väliin: tehtävät (tosin niitä on toki opettavaista miettiä... ) example-kohdat myöhempi teksti ei oleta, että ne olisi lukenut kurssisivuilla on luettelo kurssin kannalta oleellisista kohdista (muutakin voi toki lukea... ) tekstiä ja koodia lukiessa voi miettiä esimerkiksi miten tekisin tämän jollain muulla kielellä? (entä jollain muulla kuin Pythonilla?) olisinko keksinyt tällaista ratkaisua itse? kirjan alaviitteet ovat usein opettavaisia

Kirjassa on usein abstraktia koodia (SICP 1.1.8) Neliöjuuren laskeva esimerkki (define (square x) (* x x)) (define (average x y) (/ (+ x y) 2)) (define (sqrt x) (define (good-enough? guess) (< (abs (- (square guess) x)) 0.001)) (define (improve guess) (average guess (/ x guess))) (define (sqrt-iter guess) (if (good-enough? guess) guess (sqrt-iter (improve guess)))) (sqrt-iter 1.0)) kirjan koodissa on melko vähän kommentteja, sillä se yrittää olla itsedokumentoivaa Schemelläkin abstraktioita voisi toki tehdä vähemmänkin Sama Pythonilla def average(x, y): return (x+y)/2 def my_sqrt(x): def good_enough(guess): return abs(guess*guess-x) < 0.001 def improve(guess): return average(guess, x/guess) guess = 1.0 while not good_enough(guess): guess = improve(guess) return guess Tyypillisemmin Pythonilla def my_sqrt(x): guess = 1.0 # while guess isn't good enough while (abs(guess*guess - x) >= 0.001): # improve the guess guess = (guess+x/guess)/2 return guess

Vähän terminologiaa lauseke (expression) tai joskus lause (statement): 3 (+ x 4) (f 12) (if (> x 0) 3 (- x 4)) (let ((x (f 3))) (display x) (newline)) cond-lausekkeen ehtoseuraus-pari (clause): (cond ((= x 0) 99) ((> x 0) (fact x)) (else -1)) (muuttuja)sidonta (binding): (define z 3) (let ((x 3) (y (f 3)))...) proseduuri (procedure) eli funktio joissain muissa ohjelmointikielissä on erikseen lauseke ja lause sekä proseduuri ja funktio