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

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

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ä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Ohjelmoinnin peruskurssien laaja oppimäärä

Scheme-kesäkurssi luento 5

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

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.

Ohjelmoinnin peruskurssien laaja oppimäärä

815338A Ohjelmointikielten periaatteet

Scheme-kesäkurssi luento 3

Scheme-kesäkurssi luento 4

Scheme-kesäkurssi luento 1

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Kokeellista matematiikkaa SAGE:lla

Ohjelmoinnin peruskurssien laaja oppimäärä

Jatkeet. TIES341 Funktio ohjelmointi 2 Kevät 2006

Ohjelmoinnin peruskurssien laaja oppimäärä

Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Funktionaalinen ohjelmointi

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

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

TIEA341 Funktio-ohjelmointi 1, kevät 2008

ELM GROUP 04. Teemu Laakso Henrik Talarmo

Ohjelmoinnin peruskurssien laaja oppimäärä

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Funktionaalinen ohjelmointi

Ohjelmoinnin peruskurssien laaja oppimäärä

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

Ohjelmoinnin peruskurssien laaja oppimäärä

14.1 Rekursio tyypitetyssä lambda-kielessä

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

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

TIES542 kevät 2009 Rekursiiviset tyypit

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

Operaattoreiden ylikuormitus. Operaattoreiden kuormitus. Operaattoreiden kuormitus. Operaattoreista. Kuormituksesta

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin peruskurssi Y1

TIE Tietorakenteet ja algoritmit 1. TIE Tietorakenteet ja algoritmit

Ohjelmoinnin peruskurssien laaja oppimäärä

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

Tietorakenteet ja algoritmit - syksy

Abstraktit tietotyypit. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Racket ohjelmointia II. Tiina Partanen 2015

Ohjelmoinnin perusteet Y Python

Ohjelmistojen mallintaminen viikon 4 laskareiden mallivastauksia

11/20: Konepelti auki

Ohjelmointikieli TIE Principles of Programming Languages Syksy 2017 Ryhmä 19

Arttu Kaipiainen Funktionaalinen ohjelmointi web-ohjelmistokehityksessä. Diplomityö

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen

Ohjelmoinnin perusteet Y Python

Algoritmit 1. Luento 10 Ke Timo Männikkö

Luku 3. Listankäsittelyä. 3.1 Listat

Turmeleeko ohjelmointi nuorisomme?

Algoritmit 2. Luento 8 To Timo Männikkö

Ohjelmoinnin peruskurssien laaja oppimäärä

15. Ohjelmoinnin tekniikkaa 15.1

2 Sanoja järjestävän funktion ohjelmoiminen

Tutoriaaliläsnäoloista

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

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

58131 Tietorakenteet ja algoritmit (syksy 2015)

Insinöörimatematiikka A

Groovy. Niko Jäntti Jesper Haapalinna Group 31

815338A Ohjelmointikielten periaatteet

Tietorakenteet ja algoritmit

Clojure, funktionaalinen Lisp murre

Tyyppiluokat II konstruktoriluokat, funktionaaliset riippuvuudet. TIES341 Funktio-ohjelmointi 2 Kevät 2006

Ohjelmoinnin perusteet Y Python

LUKUTEORIA johdantoa

Matematiikan tukikurssi, kurssikerta 1

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

Ohjelmoinnin peruskurssien laaja oppimäärä

Transkriptio:

Ohjelmoinnin peruskurssien laaja oppimäärä Luento 6: Rajoite-esimerkki, funktionaalista ohjelmointia (mm. SICP 3.3.5, 3.5) Riku Saikkonen 8. 11. 2012

Sisältö 1 SICP 3.3.5 esimerkki: rajoitteiden vyörytysjärjestelmä 2 Vähän funktionaalisten ohjelmien todistamisesta 3 Funktionaalista ohjelmointia: virrat

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) siitä että 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-luokka (viiva): 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ää aina uuden arvon eteenpäin muille liitoksen rajoitteille rajapinta constraint (laatikko): 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 ovat luokkia, jotka 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? taustalla keksintö, että kaavoja (tai muita ratkaistavia ongelmia) voi esittää tällaisina rajoiteverkkoina tätä 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ä toteutuksen 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: miten arvojen unohtaminen toimii (vain arvon asettaja voi pyytää unohtamaan sen) kolmas: verkkojen esittämiseen ei tarvitse tehdä omaa kieltä

Sisältö 1 SICP 3.3.5 esimerkki: rajoitteiden vyörytysjärjestelmä 2 Vähän funktionaalisten ohjelmien todistamisesta 3 Funktionaalista ohjelmointia: virrat

Ohjelmien oikeaksi todistamisesta eräs funktionaalisuuden etu on, että ohjelmista on helpompi todistaa ominaisuuksia, jos ne ovat puhtaasti funktionaalisia lausekkeita voi muuttaa toisiksi matemaattisesti eli välittämättä ympäröivästä kontekstista tai ohjelman tilasta suoritushetkellä imperatiivisen koodin todistamisessa mietitään yleensä ohjelman tilaa tietyillä hetkillä todistus on usein ketju ohjelman välitiloja alkutilasta (argumentit) lopputilaan, joka toteuttaa todistettavan ehdon suoritusjärjestyksellä on siis koko ajan väliä silmukoille pitää keksiä invariantti: ehto joka on voimassa esim. jokaisen kierroksen alussa ja lopussa toinen funktionaalisuuden etu on, että koodi ja todistus voi olla abstraktimpaa: voidaan tehdä enemmän yleiskäyttöisiä apufunktioita ja todistaa ensin niiden ominaisuuksia

Funktionaalinen todistusesimerkki 1/2 Todistetaan: kaikille listoille l: (accumulate cons nil l) l (lista = nil:iin päättyvä jono pareja) Ensin accumulate:n määritelmä (define (accumulate op initial sequence) (if (null? sequence) initial (op (car sequence) (accumulate op initial (cdr sequence))))) Tai sanallinen määritelmä (jolloin toteutuksen ei tarvitse olla täsmälleen ylläoleva): 1 (accumulate op i nil) i 2 (accumulate op i (cons h t ) ( op h (accumulate op i t ))

Funktionaalinen todistusesimerkki 2/2 Todistetaan: kaikille listoille l: (accumulate cons nil l) l (lista = nil:iin päättyvä jono pareja) Todistus 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 1/2 tässä muutamia vastaavalla tavalla todistettavia ominaisuuksia (kaikki listat ovat nil:iin päättyviä ja argumenttifunktiot päättyviä ja sivuvaikutuksettomia) tarkoittaa, että lausekkeiden arvot ovat samoja suoritusaika tai laskujärjestys voi olla eri reverse:stä: (reverse (reverse l)) l lähinnä map:iin liittyviä: (map f (reverse l)) (reverse (map f l)) (map f (append l1 l2)) (append (map f l1) (map f l2)) (map (compose f g) l) (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))

Listankäsittelyproseduurien ominaisuuksia 2/2 fold:eihin eli accumulate:en liittyviä: (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))) alla olevat kaksi reverse:n toteutusta toimivat eli (rev-1 l) (rev-2 l) (reverse l) Kaksi toteutusta reverse:stä (define (rev-1 l) (if (null? l) l (append (rev-1 (cdr l)) (list (car l))))) (define (rev-2 l) (fold-left (flip cons) nil l))

Sisältö 1 SICP 3.3.5 esimerkki: rajoitteiden vyörytysjärjestelmä 2 Vähän funktionaalisten ohjelmien todistamisesta 3 Funktionaalista ohjelmointia: virrat

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 cdr suoritetaan 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 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. äärettömän 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 primestream.scm (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 sqrtstream.scm (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 häntärekursiolla tässä ratkaisussa ei tarvita lopetusehtoa (haluttua tarkkuutta) kaikki lasketut arvot (eli laskennan välitilat) ovat virrassa tallessa ja virran seuraavan arvon laskemisessa voisi käyttää useampia aiemmista arvoista mutta häntärekursiivisessa tai silmukalla tehdyssä ratkaisussa käytettävissä on vain edellinen tila