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ä

Scheme-kesäkurssi luento 2

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ä

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ä

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Ohjelmoinnin peruskurssien laaja oppimäärä

Tämän vuoksi kannattaa ottaa käytännöksi aina kirjoittaa uuden funktion tyyppi näkyviin, ennen kuin alkaa sen määritemää kirjoittamaan.

Scheme-kesäkurssi luento 5

Ohjelmoinnin peruskurssien laaja oppimäärä

Scheme-kesäkurssi luento 3

Ohjelmoinnin peruskurssien laaja oppimäärä

Laiska laskenta, korekursio ja äärettömyys. TIEA341 Funktio ohjelmointi Syksy 2005

Scheme-kesäkurssi luento 1

Ohjelmoinnin peruskurssien laaja oppimäärä

Scheme-kesäkurssi luento 4

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

815338A Ohjelmointikielten periaatteet

Ohjelmoinnin peruskurssien laaja oppimäärä

Kokeellista matematiikkaa SAGE:lla

Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Ohjelmoinnin peruskurssi Y1

Jatkeet. TIES341 Funktio ohjelmointi 2 Kevät 2006

Ohjelmoinnin perusteet Y Python

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

TIES542 kevät 2009 Rekursiiviset tyypit

TIEA341 Funktio-ohjelmointi 1, kevät 2008

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin peruskurssi Y1

Funktionaalinen ohjelmointi

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

tään painetussa ja käsin kirjoitetussa materiaalissa usein pienillä kreikkalaisilla

TIEA341 Funktio-ohjelmointi 1, kevät 2008

14.1 Rekursio tyypitetyssä lambda-kielessä

Funktionaalinen ohjelmointi

Tietorakenteet ja algoritmit

Ohjelmoinnin peruskurssi Y1

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

ELM GROUP 04. Teemu Laakso Henrik Talarmo

ja λ 2 = 2x 1r 0 x 2 + 2x 1r 0 x 2

Ohjelmoinnin perusteet Y Python

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.

Ohjelmoinnin peruskurssien laaja oppimäärä

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

Ohjelmoinnin peruskurssien laaja oppimäärä

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

811120P Diskreetit rakenteet

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Bootstrap / HTDP2 / Realm of Racket. Vertailu

Lisää pysähtymisaiheisia ongelmia

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

Ohjelmoinnin perusteet Y Python

TIE Tietorakenteet ja algoritmit 1. TIE Tietorakenteet ja algoritmit

Ohjelmoinnin perusteet Y Python

11/20: Konepelti auki

Algoritmit 1. Luento 10 Ke Timo Männikkö

Algoritmit 1. Demot Timo Männikkö

Rekursiiviset tyypit

Geneeriset tyypit. TIES542 Ohjelmointikielten periaatteet, kevät Antti-Juhani Kaijanaho. Jyväskylän yliopisto Tietotekniikan laitos

Ohjelmoinnin perusteet Y Python

811312A Tietorakenteet ja algoritmit Kertausta kurssin alkuosasta

Ohjelmoinnin peruskurssi Y1

Racket ohjelmointia II. Tiina Partanen 2015

Rekursiiviset palautukset [HMU 9.3.1]

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

Ohjelmoinnin perusteet Y Python

Luku 6. Dynaaminen ohjelmointi. 6.1 Funktion muisti

Vaihtoehtoinen tapa määritellä funktioita f : N R on

Tämän lisäksi listataan ranskalaisin viivoin järjestelmän tarjoama toiminnallisuus:

ALGORITMIT 1 DEMOVASTAUKSET KEVÄT 2012

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset

Tietorakenteet ja algoritmit

58131 Tietorakenteet ja algoritmit (syksy 2015)

Rekursio. Funktio f : N R määritellään yleensä antamalla lauseke funktion arvolle f (n). Vaihtoehtoinen tapa määritellä funktioita f : N R on

Luku 3. Listankäsittelyä. 3.1 Listat

Ohjelmistojen mallintaminen viikon 4 laskareiden mallivastauksia

15. Ohjelmoinnin tekniikkaa 15.1

Turmeleeko ohjelmointi nuorisomme?

Transkriptio:

Ohjelmoinnin peruskurssien laaja oppimäärä Luento 4: SICP kohta 3.3.5 ja funktionaalista ohjelmointia Riku Saikkonen 15. 11. 2010

Sisältö 1 Ensimmäisen kierroksen tehtävistä 2 SICP 3.3.5: rajoitteiden vyörytysjärjestelmä 3 Funktionaalista ohjelmointia: virrat 4 Funktionaalista ohjelmointia: ohjelmien todistaminen

Ensimmäisen kierroksen tehtävistä melkein kaikki saivat tehtyä kaikki 8 tehtävää oikein (loistavaa!) tehtävistä 1.7 (merge-sort) ja 1.8 (deep-reverse): (append l1 l2) käy listan l1 läpi ja tekee siitä kopion, cons ei tehokkuusmielessä siis kannattaa käyttää consia silloin kun voi listasta voi tehdä kopion käymällä sen läpi rekursiivisesti (kuten esim. mapin toteutus), sen sijaan häntärekursiivinen lähestymistapa kääntää listan ympäri

Listan läpikäynti Rekursiivinen map (define (my-map-1 f l) (if (null? l) nil (cons (f (car l)) (my-map-1 f (cdr l))))) Häntärekursiivinen map (define (my-map-2 f l) (define (iter result left) (if (null? left) result (iter (cons (f (car left)) result) (cdr left)))) (iter nil l)) Testiajoja (define (square x) (* x x)) (my-map-1 square (list 1 2 3 4)) (1 4 9 16) (my-map-2 square (list 1 2 3 4)) (16 9 4 1) (reverse (my-map-2 square (list 1 2 3 4))) (1 4 9 16)

Sisältö 1 Ensimmäisen kierroksen tehtävistä 2 SICP 3.3.5: rajoitteiden vyörytysjärjestelmä 3 Funktionaalista ohjelmointia: virrat 4 Funktionaalista ohjelmointia: ohjelmien todistaminen

Rajoitteiden vyöyrytysjärjestelmä (SICP 3.3.5) Kirjan kohdan 3.3.5 isompi esimerkki: olioiden käytöstä viestien välitykseen (kutsu olion metodia lähetä oliolle viesti) oman kielen tekemisestä Schemen päälle (joukko proseduureja antaa ohjelmoijalle uuden tavan puhua) joskus laskentaa voi tehdä myös takaperin Perustoiminta järjestelmän käyttäjän näkökulmasta: 1 määritellään matemaattinen kaava, esim. 9C = 5(F 32), järjestelmän omalla kielellä 2 asetetaan osalle muuttujista (C tai F ) alkuarvot 3 kysytään haluttujen muuttujien arvoa (järjestelmä laskee kaavan perusteella kaikki muut arvot) 4 (voidaan käskeä myös unohtamaan annettuja arvoja ja seurata laskennan etenemistä)

Järjestelmän käyttö: rajoiteverkko matemaattinen kaava määritellään rajoiteverkkona, jossa on liitoksia (connector, viivat) ja rajoitteita (constraint, laatikot) liitoksessa on tallessa yksi arvo, jonka voi asettaa ja unohtaa rajoite pakottaa halutut liitokset noudattamaan tiettyjä ehtoja vakiorajoite liittyy yhteen liitokseen ja pakottaa sille tietyn arvon yhteenlaskurajoite liittyy kolmeen liitokseen a, b, c ja pakottaa niille ehdon a + b = c (jos kahdella on arvo, kolmas lasketaan) kertolaskurajoite samoin a b = c järjestelmä vyöryttää (propagate) automaattisesti arvojen muutokset kaikkiin suuntiin rajoiteverkkoa pitkin Esimerkki: Rajoiteverkko yhtälölle 9C = 5(F 32) C m1 * m2 p u p m1 * m2 v a1 + a2 F w 9 5 x y 32

Järjestelmän käyttö: proseduurit järjestelmää käytetään Schemeproseduureilla (kuten kirjastoa tai Schemen päälle rakennettua kieltä) (make-connector) luo liitoksen (multiplier a b c) luo rajoitteen, joka yhdistää liitokset a, b ja c niin että a b = c Lyhyt käyttöesimerkki (define a (make-connector)) (define b (make-connector)) (define c (make-connector)) (adder a b c) (set-value! a 11 'user) (set-value! c 25 'user) (get-value b) 14 (adder a b c) luo rajoitteen, joka yhdistää liitokset a, b ja c niin että a + b = c (constant 3.14 a) luo rajoitteen, joka pakottaa liitokselle a arvon 3.14 (probe nimi a) luo rajoitteen, joka ei vaikuta arvoihin, mutta kertoo aina kun liitoksen a arvo muuttuu (set-value! a 123 'user) asettaa liitoksen a arvoksi 123 (forget-value! a 'user) käskee liitosta a unohtamaan arvonsa (get-value a) kertoo liitoksen a nykyisen arvon

Käyttöesimerkki: CelsiusFahrenheit-muunnos Rajoiteverkko yhtälölle 9C = 5(F 32) C m1 * m2 p u p m1 * m2 v a1 + a2 F w 9 5 x y 32 Rajoiteverkkoa vastaava koodi (define (celsius-fahrenheit-converter c f) (let ((u (make-connector)) (v (make-connector)) (w (make-connector)) (x (make-connector)) (y (make-connector))) (multiplier c w u) (multiplier v x u) (adder v y f) (constant 9 w) (constant 5 x) (constant 32 y) 'ok)) Lyhyempi syntaksi (harjoitustehtävänä) ;; palauttaa f:n (define (c-f-conv c) (c+ (c* (c/ (cv 9) (cv 5)) c) (cv 32)))

Rajoiteverkon käyttäminen Käyttöesimerkki celsius-fahrenheit-converterille (define C (make-connector)) (define F (make-connector)) (celsius-fahrenheit-converter C F) (probe "Celsius temp" C) (probe "Fahrenheit temp" F) (set-value! C 25 'user) Probe: Celsius temp = 25 Probe: Fahrenheit temp = 77 done (set-value! F 212 'user) Error! Contradiction (77 212) (forget-value! C 'user) Probe: Celsius temp =? Probe: Fahrenheit temp =? done (set-value! F 212 'user) Probe: Fahrenheit temp = 212 Probe: Celsius temp = 100 done

Järjestelmän toteutus kaksi oliorajapintaa: connector: viestit has-value?, value, set-value!, forget, connect vain arvon alkuperäinen asettaja (kerrotaan set-value!:ssa) voi saada liitoksen unohtamaan (forget) arvon kaksi set-value!:ta eri arvoilla aiheuttaa koniktin (virheen) levittää uuden arvon eteenpäin muille liitoksen rajoitteille rajapinta constraint: viesti I-have-a-value levittää kaikki arvot uudelleen viesti I-lost-my-value lisäksi käskee ensin unohtamaan tämän rajoitteen asettamat arvot adder, multiplier, constant ja probe toteuttavat constraint-rajapinnan arvojen laskemiseen ja levittämiseen liittyvä logiikka esim. adderissa eri koodit kolmeen suuntaan laskemiseen (c = a + b, b = c a, a = c b) helpomman Scheme-syntaksin saamiseksi myös metodeja vastaavat proseduurit, esim. (has-value? connector )

Miten tämä on keksitty? taustalle tarvitaan ajatus siitä, että kaavoja (tai muita ratkaistavia ongelmia) voi esittää tällaisina rajoiteverkkoina ideaa on laajennettu (harvinaiseksi) ohjelmointiparadigmaksi nimeltä rajoiteohjelmointi (constraint programming), jota käytetään erityisesti logiikkaohjelmoinnin yhteydessä idea lienee peräisin tekoälytutkimuksesta 19601970-luvulta toteutuksessa olioajattelu (minulla on arvo, jonka levitän eteenpäin) toimii hyvin, koska rajoitteet ja liitokset ovat itsenäisiä olennaisin idea lienee se, että liitoksissa on logiikkaa ei siis niin että rajoitteissa olisi suoraan listoja muista rajoitteista, ja ne itse kävisivät listojaan läpi etsien esim. konikteja eikä niin että ulkopuolinen proseduuri tutkisi tietorakenteena esitettyä verkkoa ja päättelisi, minne arvoja pitää levittää toinen olennainen kohta lienee se, miten arvojen unohtaminen toimii (vain arvon asettaja voi pyytää unohtamaan sen) ja ettei tarvitse tehdä ensin omaa kieltä verkkojen esittämiseen

Piirisimulaattoriesimerkki (SICP 3.3.4) kirjan kohdan 3.3.4 digitaalisten piirien simulaattori on samankaltainen kuin rajoitejärjestelmä: eroja: käytetään hyvin samaan tapaan (rajoitteen tilalla esim. or-portti) myös tässä piirien muodostama verkko tehdään suoraan tulkissa Scheme-proseduureja kutsumalla arvot etenevät vain yhteen suuntaan (piireillä on input- ja output-signaaleja) järjestelmä simuloi aikaa eli etenemisviivettä (output-signaali muuttuu vasta vähän sen jälkeen kun input-signaali muuttui)

Sisältö 1 Ensimmäisen kierroksen tehtävistä 2 SICP 3.3.5: rajoitteiden vyörytysjärjestelmä 3 Funktionaalista ohjelmointia: virrat 4 Funktionaalista ohjelmointia: ohjelmien todistaminen

Virrat eli mahdollisesti äärettömät listat (SICP 3.5) virta (stream) on lista, josta mahdollisesti vain osa on valmiina samoin kuin lista, virta muodostuu tyhjästä virrasta the-empty-stream (sama kuin nil) pareista, joita tehdään cons-stream:lla parin osat ovat stream-car ja stream-cdr virta on jono pareja joka päättyy tyhjään virtaan virtojen erikoisuus on se, että virtaparin cdr:ää ei evaluoida paria tehdessä, vaan vasta kun koodi menee sinne joten voi määritellä myös äärettömän virran, jonka cdr:istä löytyy lisää alkioita niin paljon kun niitä jaksaa hakea virrat ovat käytössä muuallakin funktionaalisessa ohjelmoinnissa: Haskell-kielessä kaikki listat toimivat näin virtojen vastine löytyy mm. Scalasta joissain toteutuksissa myös car lasketaan vasta tarvittaessa

Miksi virtoja? (SICP 3.5.1) listankäsittelyoperaatioissa on se ongelma, että (ainakin periaatteessa) niissä tehdään usein pitkiä välituloslistoja ennen lopullisen tuloksen laskemista virrat auttavat tässä: välituloslistoista lasketaan vain niin paljon alkioita kuin jatkoa varten on tarpeen toinen virtojen etu on, että äärettömiä virtoja määrittelemällä ja käyttämällä voi saada aikaan siistimpää koodia kolmas virtojen käyttötarkoitus on muuttuvan tilan mallinnuksessa tallennetaan virtaan peräkkäisiä tiloja sen sijaan että esim. olio muuttaisi omia tilamuuttujiaan ei-funktionaalisesti virroilla voi tehdä myös I/O:ta funktionaalisesti (lisää tästä myöhemmällä luennolla) huono puoli: virtoja käytettäessä on vaikea ennustaa, milloin tietty koodi suoritetaan tästä syystä virtoja käytetään yleensä vain puhtaasti funktionaalisessa koodissa (ei sijoituslauseiden kanssa)

Äärettömät virrat (SICP 3.5.2) rekursion avulla voi määritellä äärettömiä virtoja virta voi myös viitata itseensä cdr:ssä useimmat listojenkäsittelyoperaatiot toimivat samaan tyyliin myös äärettömillä virroilla esim. (stream-map f s) palauttaa uuden äärettömän virran kaikki eivät toimi: esim. virran reverse jäisi etsimään viimeistä alkiota Esimerkkejä (define ones (cons-stream 1 ones)) ; (1 1 1 1 1 1...) (define (integers-starting-from n) (cons-stream n (integers-starting-from (+ n 1)))) (define integers (integers-starting-from 1)) ; (1 2 3...) (define (fibgen a b) (cons-stream a (fibgen b (+ a b)))) (define fibs (fibgen 0 1)) ; (0 1 1 2 3 5 8 13 21...)

Esimerkki: kaikki alkuluvut sisältävä virta (SICP 3.5.2) Esimerkkikoodi (define (divisible? x y) (= (remainder x y) 0)) (define (integers-starting-from n) (cons-stream n (integers-starting-from (+ n 1)))) (define (sieve stream) (cons-stream (stream-car stream) (sieve (stream-filter (lambda (x) (not (divisible? x (stream-car stream)))) (stream-cdr stream))))) (define primes (sieve (integers-starting-from 2))) stream-filter on samanlainen kuin filter, mutta virroille (kirjassa on samoin stream-map jne.)

Esimerkki: neliöjuuren laskenta (SICP 3.5.3) Esimerkkikoodi (define (sqrt-improve guess x) (average guess (/ x guess))) (define (sqrt-stream x) (define guesses (cons-stream 1.0 (stream-map (lambda (guess) (sqrt-improve guess x)) guesses))) guesses) Testiajo: (sqrt-stream 2) (1. 1.5 1.416667 1.414216...) kirjan alussa (luku 1.1) laskettiin samaa perinteisellä tavalla, ohjelman tilaa häntärekursiolla muuttaen tässä ratkaisussa ei tarvitse miettiä edellistä ja seuraavaa tilaa eikä miten niiden välillä siirrytään: kaikki tilat ovat virrassa tallessa

Sisältö 1 Ensimmäisen kierroksen tehtävistä 2 SICP 3.3.5: rajoitteiden vyörytysjärjestelmä 3 Funktionaalista ohjelmointia: virrat 4 Funktionaalista ohjelmointia: ohjelmien todistaminen

Ohjelmien oikeaksi todistamisesta eräs funktionaalisuuden etu on, että ohjelmista on helpompi todistaa ominaisuuksia, jos ne ovat puhtaasti funktionaalisia imperatiivisen koodin todistamisessa mietitään yleensä ohjelman tilaa tietyillä hetkillä; todistus on usein ketju välitiloja alkutilasta (argumentit) lopputilaan, joka toteuttaa todistettavan ehdon Todistus: kaikille listoille l: (accumulate cons nil l) l (lista = nil:iin päättyvä jono pareja) 1 Jos l = nil: (accumulate cons nil nil) nil (accumulate:n määritelmästä) 2 Jos l = pari (h,t) eli ((car l), (cdr l)): (accumulate cons nil (cons h t)) (cons h (accumulate cons nil t)) (taas määritelmästä, op = cons) Koska t on lyhyempi kuin (cons h t), tämä riittää induktioon.

Listankäsittelyproseduurien ominaisuuksia muutamia vastaavalla tavalla todistettavia ominaisuuksia (kaikki listat ovat nil:iin päättyviä ja argumenttifunktiot päättyviä): (reverse (reverse l)) l (map f (reverse l)) (reverse (map f l)) (map f (append l1 l2)) (append (map f l1) (map f l2)) (map (lambda (x) (f (g x))) l) (map f (map g l)) (filter p (map f l)) (map f (filter (lambda (x) (p (f x))) l)) (fold-right op i l) (fold-left op i l), jos op on assosiatiivinen ja kaikille x: (op x i) x ja (op i x) x (fold-right op i l) (fold-left (flip op) i (reverse l)), missä (define (flip f) (lambda (x y) (f y x))) (rev-1 l) (rev-2 l) (reverse l), missä (define (rev-1 l) (if (null? l) l (append (rev-1 (cdr l)) (list (car l))))) ja (define (rev-2 l) (fold-left (flip cons) nil l))