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ä

Ohjelmoinnin peruskurssien laaja oppimäärä

Scheme-kesäkurssi luento 1

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ä

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Tutoriaaliläsnäoloista

Scheme-kesäkurssi luento 3

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin peruskurssien laaja oppimäärä

ITKP102 Ohjelmointi 1 (6 op)

Scheme-kesäkurssi luento 5

Java kahdessa tunnissa. Jyry Suvilehto

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

ITKP102 Ohjelmointi 1 (6 op)

Algoritmit 1. Luento 3 Ti Timo Männikkö

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssi Y1

Tietueet. Tietueiden määrittely

Tietorakenteet ja algoritmit

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssi Y1

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

Luku 6. Dynaaminen ohjelmointi. 6.1 Funktion muisti

815338A Ohjelmointikielten periaatteet Harjoitus 5 Vastaukset

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

Ohjelmoinnin peruskurssien laaja oppimäärä

Aliohjelmatyypit (2) Jakso 4 Aliohjelmien toteutus

Jakso 4 Aliohjelmien toteutus

Luento 4 Aliohjelmien toteutus

11/20: Konepelti auki

Jakso 4 Aliohjelmien toteutus

Scheme-kesäkurssi luento 2

Ohjelmoinnin peruskurssi Y1

13. Loogiset operaatiot 13.1

ITKP102 Ohjelmointi 1 (6 op)

Ohjelmoinnin peruskurssi Y1

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

Ohjelmoinnin peruskurssien laaja oppimäärä

Tietorakenteet ja algoritmit

Algoritmit 2. Luento 8 To Timo Männikkö

TIE Tietorakenteet ja algoritmit 25

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssi Y1

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

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen

815338A Ohjelmointikielten periaatteet

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

Ohjelmoinnin peruskurssi Y1

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

Jatkeet. TIES341 Funktio ohjelmointi 2 Kevät 2006

Algoritmit 1. Luento 11 Ti Timo Männikkö

811120P Diskreetit rakenteet

Ohjelmoinnin perusteet Y Python

Ehto- ja toistolauseet

Ohjelmointiharjoituksia Arduino-ympäristössä

Bootstrap / HTDP2 / Realm of Racket. Vertailu

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin perusteet Y Python

Tietorakenteet ja algoritmit. Kertaus. Ari Korhonen

Tietorakenteet ja algoritmit - syksy

Luento 4 Aliohjelmien toteutus

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

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

1. Olio-ohjelmointi 1.1

useampi ns. avain (tai vertailuavain) esim. opiskelijaa kuvaavassa alkiossa vaikkapa opintopistemäärä tai opiskelijanumero

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssi Y1

1. Omat operaatiot 1.1

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Tietorakenteet ja algoritmit syksy Laskuharjoitus 1

58131 Tietorakenteet ja algoritmit (syksy 2015)

Aliohjelmatyypit (2) Jakso 4 Aliohjelmien toteutus

Transkriptio:

Ohjelmoinnin peruskurssien laaja oppimäärä Luento 1: SICP luku 1 Riku Saikkonen 1. 11. 2010

Sisältö 1 Kurssijärjestelyitä 2 SICP-kirjasta 3 Häntärekursio 4 Rekursio 5 Funktiot argumentteina 6 Funktiot paluuarvoina

Kurssijärjestelyitä kurssin sivuilla on nyt: SICP-kirjasta käsiteltävät kohdat ohjeita Schemen käytöstä ensimmäiset harjoitustehtävät (8 lyhyttä tehtävää, deadline 9.11.) harjoitustehtävien palautusjärjestelmä (Gobliniin) tulossa, toivottavasti jo huomenna opiskelijahuone tulossa, toivottavasti ensi viikolla hakekaa Niksulan tunnus (vaikka luennon jälkeen) pyyntö: seuratkaa ajankäyttöänne noin tunnin tarkkuudella kumpi tietokoneharjoitusaika? ke 1214 vai pe 1012?

Sisältö 1 Kurssijärjestelyitä 2 SICP-kirjasta 3 Häntärekursio 4 Rekursio 5 Funktiot argumentteina 6 Funktiot paluuarvoina

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 luota siihen, että ne olisi lukenut kurssisivuilla on luettelo kurssin kannalta oleellisista kohdista (muutakin voi toki lukea... ) kirjan alaviitteet ovat usein hyödyllisiä tekstiä ja koodia lukiessa voi miettiä esimerkiksi miten tekisin tämän jollain muulla kielellä? olisinko keksinyt tällaista ratkaisua itse?

Vähän terminologiaa lauseke (expression) tai joskus lause: 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 (expression) ja lause (statement) sekä proseduuri ja funktio

Globaalien ja paikallisten muuttujien määritteleminen Schemessä on monta tapaa määritellä muuttujia ja proseduureja; 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 em. säännöt riittävät käytännön ohjelmointiin

Kirjassa on usein abstraktia koodia (SICP 1.1.8) Neliöjuuren laskeva esimerkki (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)) Tyypillisesti Javalla double sqrt(double x) { double guess = 1.0; // while guess is not // good enough while (Math.abs(guess*guess - x) >= 0.001) // improve the guess guess = (guess + x/guess)/2; return guess; } varmaankin tästä syystä kirjan koodissa on melko vähän kommentteja: koodi yrittää olla itsedokumentoivaa Schemelläkin abstraktiot voisi tietysti kirjoittaa auki

Sisältö 1 Kurssijärjestelyitä 2 SICP-kirjasta 3 Häntärekursio 4 Rekursio 5 Funktiot argumentteina 6 Funktiot paluuarvoina

Silmukat ja häntärekursio (SICP 1.2.1) lausekielissä iteratiivista laskentaa tehdään usein silmukoilla (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 (esim. Javassa pino kasvaisi) Kertoma häntärekursiolla (define (factorial n) (define (iter p c) (if (> c n) p (iter (* c p) (+ c 1)))) (iter 1 1)) Javalla tai C:llä: int factorial(int n) { int p = 1, c = 1; while (c <= n) { p = c * p; c++; } 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 pino enemmän todellisuutta vastaavassa muodossa (tosin se riippuu toteutuksesta... ) Kutsupino: 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: 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 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)))

Sisältö 1 Kurssijärjestelyitä 2 SICP-kirjasta 3 Häntärekursio 4 Rekursio 5 Funktiot argumentteina 6 Funktiot paluuarvoina

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))

Generatiivinen rekursio kirjassa on toinen vastaava esimerkki kohdassa 1.2.2 (Counting change) tällainen päättely on yksi rekursion käyttötarkoitus variaatio siitä on algoritmien suunnittelussa yleinen hajoita ja hallitse -menetelmä (divide and conquer): ratkaistava ongelma jaetaan pienempiin osaongelmiin, joiden ratkaisut yhdistetään Merge sort -harjoitustehtävässä näkyy esimerkki tästä (osaongelma = puolet pienempi järjestettävä lista; yhdistäminen tehdään merge-proseduurilla)

Strukturaalinen rekursio toinen tapa käyttää rekursiota on kun jokin monimutkainen tietorakenne (esim. listarakenne) käydään läpi pala kerrallaan rekursiivisesti esimerkkejä seuraavalla luennolla ja SICP luvussa 2 myös esittelyluennon symbolinen derivoija oli esimerkki tästä tätä rekursion käyttötapaa sanotaan joskus rakenteelliseksi (structural) rekursioksi, ja edellistä generatiiviseksi (generative)

Sisältö 1 Kurssijärjestelyitä 2 SICP-kirjasta 3 Häntärekursio 4 Rekursio 5 Funktiot argumentteina 6 Funktiot paluuarvoina

Esimerkki funktioargumentista (SICP 1.31.3.2) Halutaan arvioida π:n arvoa kaavalla π 8 = 1 1 3 + 1 5 7 + 1 9 11 +. Ratkaisu oman summa-abstraktion avulla { b 0, jos a > b f (n) = f (a) + b n=next(a) f (n) muuten. n=a (define (sum f a next b) (if (> a b) 0 (+ (f a) (sum f (next a) next b)))) (define (pi-f x) (/ 1.0 (* x (+ x 2)))) (define (pi-next x) (+ x 4)) (define (pi-sum a b) (sum pi-f a pi-next b)) Testiajo: (* 8 (pi-sum 1 1000)) 3.139592655589783

Lambda on tapa tehdä nimettömiä funktioita Edelliseltä kalvolta (define (pi-f x) (/ 1.0 (* x (+ x 2)))) (define (pi-next x) (+ x 4)) (define (pi-sum a b) (sum pi-f a pi-next b)) lambda:n avulla (define (pi-sum a b) (sum (lambda (x) (/ 1.0 (* x (+ x 2)))) a (lambda (x) (+ x 4)) b)) apuproseduureja voi tehdä lambdalla keksimättä niille nimiä lambda on historiallinen nimi: loogisempi olisi ehkä make-procedure tms. lambdan vastine löytyy esim. Scalasta, Rubysta, Perlistä, JavaScriptistä, Luasta ja Pythonista (melkein) Schemessä lambda on myös primitiivisin tapa tehdä paikallisia muuttujia (ks. SICP 1.3.2)

Funktioargumentit Javassa 1/2 Java ei tue funktioiden (tai metodien) tallentamista muuttujiin tai antamista argumentiksi moni Javan rajapinta kiertää tätä rajoitusta yksimetodisilla rajapinnoilla; esimerkkejä: GUI-kirjastojen ActionListener (metodi actionperformed) järjestämisfunktioiden Comparator (metodi compare) monisäikeisyyden Runnable-rajapinta (metodi run) etu: luokan ja metodin nimestä saattaa nähdä, mihin tätä argumenttia tullaan käyttämään haittoja: argumenttina annettavan proseduurin koodi päätyy usein kauas kohdasta, jossa sitä käytetään proseduurin ulkopuolisia paikallisia muuttujia on työlästä käyttää proseduurin sisältä Schemessä nämä voisivat olla tavallisia proseduuriargumentteja

Funktioargumentit Javassa 2/2 toinen ongelma Javassa (myös esim. C:ssä) on, että on hankalaa tehdä sisäkkäisiä funktioita, jotka viittaavat ulompana oleviin muuttujiin tätä käytetään paljon hyväksi Schemessä ja funktionaalisessa ohjelmoinnissa rajoituksen syy liittyy siihen, miten funktio (Javassa sisäluokka) sekä paikalliset muuttujat ovat tallessa muistissa

Funktioargumentti vs. olio ja metodi 1/2 eräs funktionaalisen ja olio-ohjelmoinnin paradigmojen ero liittyy siihen, mitä asioita pidetään koodissa yhdessä olio-ohjelmoinnissa on tyypillistä yhdistää olion osien määrittely ja siihen liittyvät toiminnot esim. omaan luokkaan tehdään compare-metodi (implements Comparable), joka kertoo miten luokan alkioita verrataan funktionaalisessa ohjelmoinnissa on tyypillisempää yhdistää toiminto ja sen osatoiminnot esim. järjestämisfunktio ottaa argumentiksi funktion, jolla järjestettäviä alkioita verrataan etu: samat alkiot voi järjestää useaan eri järjestykseen (esim. eri kentän mukaan) antamalla eri funktioargumentin haitta: funktioargumentti tarvitsee tietoa järjestettävien alkioiden sisäisestä rakenteesta

Funktioargumentti vs. olio ja metodi 2/2 tapojen ero ei ole aina kovin selkeä, ja molempia tapoja voi osittain käyttää kummankin ohjelmointityylin seassa (merge-sort lst string<?) eli käytetään tietotyypin valmiiksi määrittelemää funktiota (tässä merkkijonojen vertailu) Javan Collections.sort-metodille voi antaa erillisen Comparator-olion molemmat ovat hiukan erilaisia tapoja abstrahoida koodia toinen vain sopii luontevammin yhteen funktionaalisen, toinen olio-ohjelmoinnin kanssa

Sisältö 1 Kurssijärjestelyitä 2 SICP-kirjasta 3 Häntärekursio 4 Rekursio 5 Funktiot argumentteina 6 Funktiot paluuarvoina

Esimerkki proseduurista paluuarvona (SICP 1.3.4) Yksinkertaista numeerista derivointia (define dx 0.00001) (define (deriv g) (lambda (x) (/ (- (g (+ x dx)) (g x)) dx))) ; Dg(x) = (g(x + dx) g(x))/dx Ajoesimerkkejä (define (cube x) (* x x x)) (define dcube (deriv cube)) (define (dcube x) ((deriv cube) x)) (dcube 5) 75.00014999664018 ((deriv cube) 5) 75.00014999664018 ; tai seuraava rivi:

Funktioiden käyttämisestä paluuarvoina funktioiden käyttö paluuarvoina on hieman harvinaisempaa kuin argumentteina yleisin käyttö lienee toisia funktioita muokkaavat funktiot (kuten deriv-esimerkki edellä) pidemmälle menevässä funktionaalisessa ohjelmoinnissa niitä näkee aina välillä esimerkiksi currying on tekniikka, jolla moniargumenttiset funktiot saa tehtyä yksiargumenttisten avulla samaa ideaa käytetään mm. Haskell-kielessä: jos funktiolle antaa vähemmän argumentteja kuin sen pitäisi saada, kutsu palauttaa funktion, joka ottaa loput argumentit ja kutsuu alkuperäistä esim. (< 0) olisi sama kuin (lambda (x) (< 0 x)), jos Scheme käyttäisi tätä ideaa argumentin ja paluuarvon lisäksi kolmas tapa kuljettaa funktioita on tallettaa niitä tietorakenteisiin myöhempää käyttöä varten