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ä

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

Scheme-kesäkurssi luento 1

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

815338A Ohjelmointikielten periaatteet Harjoitus 7 Vastaukset

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

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

Ohjelmoinnin peruskurssien laaja oppimäärä

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

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Tutoriaaliläsnäoloista

Scheme-kesäkurssi luento 3

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Luento 5. Timo Savola. 28. huhtikuuta 2006

Ohjelmoinnin perusteet Y Python

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

Ohjelmoinnin peruskurssien laaja oppimäärä

ELM GROUP 04. Teemu Laakso Henrik Talarmo

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin peruskurssi Y1

Scheme-kesäkurssi luento 5

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin perusteet Y Python

Zeon PDF Driver Trial

Scheme-kesäkurssi luento 2

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssi Y1

Chapel. TIE Ryhmä 91. Joonas Eloranta Lari Valtonen

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin peruskurssien laaja oppimäärä

11/20: Konepelti auki

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssi Y1

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

ITKP102 Ohjelmointi 1 (6 op)

Ohjelmoinnin peruskurssi Y1

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

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssi Y1

Concurrency - Rinnakkaisuus. Group: 9 Joni Laine Juho Vähätalo

Ohjelmoinnin perusteet Y Python

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

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssi Y1

ICS-C2000 Tietojenkäsittelyteoria Kevät 2016

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssi Y1

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

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin jatkokurssi, kurssikoe

Luento 4 Aliohjelmien toteutus

Ohjelmoinnin perusteet Y Python

Bootstrap / HTDP2 / Realm of Racket. Vertailu

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Harjoitustyö: virtuaalikone

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Transkriptio:

Ohjelmoinnin peruskurssien laaja oppimäärä Luento 2: Funktioiden käyttöä, lisää Schemestä (mm. SICP 1.31.3.4) Riku Saikkonen 18. 10. 2012

Sisältö 1 Lukuohjeita SICP-kirjaan 2 Scheme-ohjelmointikäytäntöjä 3 Funktiot argumentteina ja paluuarvoina 4 Funktio vai olio? 5 Gambit-C:n Scheme-debuggeri

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? onko koodin abstraktiotaso sopiva (liikaa / liian vähän apufunktioita)? olisinko itse käyttänyt samanlaista? 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 sqrt.py 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 kirjan käyttämää terminologiaa expression (lauseke) tai joskus statement (lause): 3 (+ x 4) (f 12) (if (> x 0) 3 (- x 4)) (let ((x (f 3))) (display x) (newline)) clause: cond-lausekkeen ehtoseuraus-pari (cond ((= x 0) 99) ((> x 0) (fact x)) (else -1)) binding: (muuttuja)sidonta (define z 3) (let ((x 3) (y (f 3)))...) procedure ja function: Schemessä sama asia joissain muissa ohjelmointikielissä on erikseen lauseke ja lause sekä proseduuri ja funktio

Sisältö 1 Lukuohjeita SICP-kirjaan 2 Scheme-ohjelmointikäytäntöjä 3 Funktiot argumentteina ja paluuarvoina 4 Funktio vai olio? 5 Gambit-C:n Scheme-debuggeri

Miten Schemeä käytännössä koodataan? pienten ohjelmien tekemiseen on kolme perustapaa: (näistä tarkemmin kurssisivulla Scheme-ohjeita) 1 pelkän Scheme-tulkin käyttäminen lähinnä kokeiluun (yksirivisille ohjelmille) 2 koodi tiedostossa editorissa ja erillinen Scheme-tulkki (esim. omassa ikkunassa) ohjelman kokeiluun tyypillinen tapa muissa kielissä, erityisesti käännetyissä kielissä samoin monimutkaisemmissa ohjelmissa varsinkin jos ohjelmalla on oma käyttöliittymä sen sijaan että vain kokeillaan proseduureja käsin tulkissa 3 Scheme-tulkki editorin sisällä tulkkiin voi helposti ladata editoitavana olevan koodin yleinen tapa Schemessä pienten ohjelmien ja apuproseduurien tekemisessä joskus käytetään muissakin kielissä (esim. Python-tulkin saa mm. Emacsin sisään)

Miten tulostetaan? jos haluaa tehdä itsenäisiä ohjelmia tai kokeilla niitä ilman että syöttää lausekkeita tulkkiin, ohjelman itsensä pitää tulostaa jotain Schemen tulostusprimitiivit: (display x ) tulostaa lausekkeen x arvon (osaa tulostaa melkein kaikkea paitsi proseduureja) (write x ) samoin, mutta koneluettavassa muodossa (jota read-primitiivi osaa lukea) vrt. Pythonin repr() (newline) tulostaa rivinvaihdon Gambit-C:ssä on myös mm. print ja println tulostaessa tarvitsee lisäksi usein merkkijonoja: "foo" on merkkijonovakio (esim. (display "foo") tulostaa foo) (string-append x y ) yhdistää kaksi merkkijonoa peräkkäin (number->string x ) muuttaa numeron merkkijonoksi muitakin on (ks. R 5 RS-standardin kohta 6.3.5), mutta niitä ei juuri kokeiluissa tarvitse

Esimerkki koodia testaavasta pääohjelmasta Kokonainen ohjelma ;; Testattava koodi (define (fact n) (if (= n 1) ; bugi! 1 (* n (fact (- n 1))))) fact.scm ;; Pääohjelma (nimi main voisi olla joku muukin) (define (main) (define (test i) (display "fact ") (display i) (display " => ") (display (fact i)) (newline)) (test 1) (test 10) (test 5) (test 0)) ;; Ajetaan pääohjelma tiedostoa ladattaessa (main)

Esimerkki tulostamisesta Edellisen luennon robottiesimerkki tulostuksella robotpaths-show.scm (define (numpaths-show f n show-all) ; muutokset punaisella (define (paths-from x y prefix) (cond ((or (>= x n) (>= y n) (= (f x y) 1)) (if show-all (begin (display prefix) (display "#") (newline))) 0) ((= x y (- n 1)) (display prefix) (display "!") (newline) 1) (else (+ (paths-from (+ x 1) y (string-append prefix ">")) (paths-from x (+ y 1) (string-append prefix "v")))))) (paths-from 0 0 "")) cond:ssa voi siis ehdon jälkeen olla monta lauseketta if:n haarassa tarvitaan begin: (begin x 1 x 2 x n ) ajaa kaikki lausekkeet ja palauttaa viimeisen arvon

Sisältö 1 Lukuohjeita SICP-kirjaan 2 Scheme-ohjelmointikäytäntöjä 3 Funktiot argumentteina ja paluuarvoina 4 Funktio vai olio? 5 Gambit-C:n Scheme-debuggeri

Esimerkki funktioargumenteista (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 sum.scm (define (sum f a next b) def sum(f, a, next, b): (if (> a b) if a > b: 0 return 0 (+ (f a) else: (sum f (next a) next b)))) return f(a) + sum(f, next(a), next, b) (define (pi-f x) def pi_f(x): (/ 1.0 (* x (+ x 2)))) return 1.0 / (x*(x+2)) (define (pi-next x) def pi_next(x): (+ x 4)) return x + 4 (define (pi-sum a b) def pi_sum(a, b): (sum pi-f a pi-next b)) return 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)) lambdan 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 tosin Pythonissa lambdan sisältöä on rajoitettu: vain yksi lauseke, jonka eteen tulee automaattisesti return Schemessä lambda on teoriassa myös primitiivisin tapa tehdä paikallisia muuttujia (ks. SICP 1.3.2)

Esimerkki funktiosta 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 nderiv.scm Ajoesimerkki (define (cube x) (* x x x)) (define dcube (deriv cube)) ;; tai seuraavat rivit: (define (dcube x) ((deriv cube) x)) (dcube 5) 75.00014999664018 ((deriv cube) 5) 75.00014999664018 Sama Pythonilla nderiv.py dx = 0.00001 def deriv(g): return lambda x: (g(x+dx)-g(x))/dx # tai sama ilman lambdaa: def deriv(g): def dg(x): return (g(x+dx) - g(x)) / dx return dg def cube(x): return x*x*x dcube1 = deriv(cube) def dcube2(x): return deriv(cube)(x)

Esimerkki abstrahoinnista funktioargumenteilla Abstraktimpi versio robottiesimerkistä robotpaths-abs.scm (define (search-right-and-down start-x start-y invalid-position? at-wall? at-goal?) (define (paths-from x y) (cond ((invalid-position? x y) 0) ((at-wall? x y) 0) ((at-goal? x y) 1) (else (+ (paths-from (+ x 1) y) (paths-from x (+ y 1)))))) (paths-from start-x start-y)) (define (numpaths f n) (search-right-and-down 0 0 (lambda (x y) (or (>= x n) (>= y n))) (lambda (x y) (= (f x y) 1)) (lambda (x y) (= x y (- n 1))))) (listojen avulla voisi abstrahoida myös robotin liikevaihtoehdot) mitä etua tästä abstraktiosta on? entä haittaa?

Sisältö 1 Lukuohjeita SICP-kirjaan 2 Scheme-ohjelmointikäytäntöjä 3 Funktiot argumentteina ja paluuarvoina 4 Funktio vai olio? 5 Gambit-C:n Scheme-debuggeri

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 datan rakenne (esim. luokan kentät) ja olioon liittyvät toiminnot esim. uuteen luokkaan tehdään metodi, joka kertoo miten sen luokan alkioita verrataan (Pythonissa esim. lt -metodi, Javassa Comparable-rajapinnan compare-metodi) 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 siis kaksi tapaa: liitetään toiminto (esim. alkioiden vertailu) dataan (olion metodi) tai operaatioon jossa sitä tarvitaan (järjestämisfunktion funktioargumentti) monessa ohjelmointikielessä käytetään molempia: ero näkyy lähinnä siinä, kumpi tapa on tyypillisempi joskus rajapinta voi tukea kumpaakin tapaa, esim: Javan Collections.sort-metodille voi antaa erillisen Comparator-olion Pythonin sorted()-funktio käyttää lt -metodia, tai sille voi antaa funktioargumentin, joka muuntaa olion toiseksi vertailua varten, tai vertailufunktion nämä kaksi ovat hiukan erilaisia tapoja abstrahoida koodia toinen vain sopii luontevammin yhteen funktionaalisen, toinen olio-ohjelmoinnin kanssa

Funktioiden käyttämisestä paluuarvoina funktioiden käyttö paluuarvoina on hieman harvinaisempaa kuin argumentteina käyttökohteita esimerkiksi: toisia funktioita muokkaavat funktiot (kuten deriv edellä) laskennan viivästäminen: jätetään jokin (mahdollisesti tarpeeton) toiminto kesken ja palautetaan funktio, jolla voi tarvittaessa tehdä sen loppuun teoreettisempi esimerkki: currying on tekniikka, jolla moniargumenttiset funktiot saa tehtyä yksiargumenttisten avulla 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

Funktioiden käyttö Javassa Java-kieli ei suoraan tue funktioiden (tai metodien) tallentamista muuttujiin, palauttamista 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 funktion koodi päätyy usein kauas kohdasta, jossa sitä käytetään tälle funktiolle on hankala antaa käyttöön paikallisia muuttujia siitä kohdasta, jossa se annettiin argumentiksi Schemessä ja Pythonissa nämä voisivat olla funktioargumentteja Pythonissa tosin sisäisesti funktiotkin ovat yksimetodisia olioita

C:n ja Javan rajoituksia funktioiden käyttämiseen C-kieli tukee funktioargumentteja ja -paluuarvoja rajoituksin: C:ssä funktio on vain sen koodi; Schemessä ja Pythonissa siihen kuuluvat myös määrittelykohdan paikallisten muuttujien arvot joten C:ssä funktio ei voi aina käyttää ulompana olevia paikallisia muuttujia (itse asiassa standardi-c ei edes tue sisäkkäisiä funktiomäärittelyjä) Javassa funktioargumenttia ja -paluuarvoa vastaa yksimetodinen sisäluokka, mutta siinäkin on rajoituksia ympäröivän koodin paikallisia muuttujia ei voi kaikissa tilanteissa käyttää molempien rajoitusten syynä on muistinhallinta: C ja Java tallettavat paikalliset muuttujat kutsupinoon, josta ne katoavat kun funktio palaa tästä lisää myöhemmin tulkkien yhteydessä...

Sisältö 1 Lukuohjeita SICP-kirjaan 2 Scheme-ohjelmointikäytäntöjä 3 Funktiot argumentteina ja paluuarvoina 4 Funktio vai olio? 5 Gambit-C:n Scheme-debuggeri

Helppo debuggaustyökalu kurssin Scheme-toteutuksessa on yksinkertainen työkalu koodin etenemisen seurantaan: (trace f) muuttaa proseduurin f määritelmää siten, että se tulostaa argumenttinsa ja paluuarvonsa aina kun sitä kutsutaan toimii myös Schemen primitiiveille, esim. (trace *) Trace-esimerkki (oikealla tulkin tulostus) (define (fact n) > (fact 3) (if (= n 0) > (fact 3) 1 > (fact 2) (* n (fact (- n 1))))) > (fact 1) > (fact 0) (trace fact) 1 1 2 6 6 >

Debuggeriin pääseminen Scheme-tulkista Scheme-lauseke (begin (step) (foo)) pysähtyy debuggeriin juuri ennen lausekkeen (foo) suoritusta Ctrl-C (Emacs: C-c C-c) kesken pitkän suorituksen pysähtyy myös debuggeriin samoin virheilmoitus, esim. (/ 1 0) keskellä koodia (break foo) muokkaa päätason proseduuria foo niin että juuri ennen sen kutsua pysähdytään debuggeriin; (unbreak foo) kumoaa debuggeritilan tunnistaa tulkin kehotteesta: > ei debuggeria, 1>, 2> jne. debuggerissa numero kertoo monennessako sisäkkäisessä (!) debuggerissa ollaan

Debuggerikomentoja Ctrl-D tai,d poistuu päällimmäisestä debuggerista,t poistuu kokonaan debuggerista takaisin tulkkiin,? näyttää komentolistauksen,b näyttää kutsupinon,be näyttää kutsupinon muuttujineen, numero menee kutsupinon tiettyyn kohtaan,c jatkaa suoritusta normaalisti,(c x ) jatkaa suoritusta virheen jälkeen: virheen aiheuttanut lauseke palauttaa x,s jatkaa lyhyen askelen eteenpäin,l tekee funktiokutsun ja pysähtyy debuggeriin sen palattua ja debuggerissa voi suorittaa Scheme-lausekkeita normaalisti (esim. katsoa muuttujan arvoa kirjoittamalla sen nimi)