815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

Samankaltaiset tiedostot
815338A Ohjelmointikielten periaatteet Harjoitus 7 Vastaukset

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

815338A Ohjelmointikielten periaatteet

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ä

811120P Diskreetit rakenteet

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

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

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Luku 3. Listankäsittelyä. 3.1 Listat

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin perusteet Y Python

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

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Ohjelmoinnin peruskurssi Y1

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

Tyyppejä ja vähän muutakin. TIEA341 Funktio ohjelmointi 1 Syksy 2005

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssien laaja oppimäärä

Harjoitus 4 -- Ratkaisut

Jatkeet. TIES341 Funktio ohjelmointi 2 Kevät 2006

Johdatus diskreettiin matematiikkaan Harjoitus 5, Ratkaise rekursioyhtälö

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

58131 Tietorakenteet ja algoritmit (syksy 2015)

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Luento 5. Timo Savola. 28. huhtikuuta 2006

815338A Ohjelmointikielten periaatteet Harjoitus 4 vastaukset

Tietorakenteet ja algoritmit

811120P Diskreetit rakenteet

Tietorakenteet ja algoritmit syksy Laskuharjoitus 1

Ohjelmoinnin peruskurssien laaja oppimäärä

Algoritmit 1. Demot Timo Männikkö

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin perusteet Y Python

TAMPEREEN TEKNILLINEN YLIOPISTO

Lisää pysähtymisaiheisia ongelmia

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

Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005

T Syksy 2004 Logiikka tietotekniikassa: perusteet Laskuharjoitus 7 (opetusmoniste, kappaleet )

Ohjelmoinnin peruskurssien laaja oppimäärä

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

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssi Y1

Makrojen mystinen maailma lyhyt oppimäärä

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssien laaja oppimäärä

811120P Diskreetit rakenteet

811312A Tietorakenteet ja algoritmit Kertausta kurssin alkuosasta

Mathematica Sekalaista asiaa

Tietorakenteet (syksy 2013)

Ohjelmoinnin peruskurssien laaja oppimäärä

Harjoitus 1 -- Ratkaisut

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

Ohjelmoinnin peruskurssi Y1

Scheme-kesäkurssi luento 3

Matematiikan tukikurssi, kurssikerta 3

Ohjelmoinnin perusteet Y Python

Funktionaalinen ohjelmointi

1. (a) Seuraava algoritmi tutkii, onko jokin luku taulukossa monta kertaa:

Pythonin Kertaus. Cse-a1130. Tietotekniikka Sovelluksissa. Versio 0.01b

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin perusteet Y Python

TIEA341 Funktio-ohjelmointi 1, kevät 2008

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

Harjoitus 2 (viikko 45)

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin perusteet Y Python

Tietorakenteet ja algoritmit - syksy

Ohjelmoinnin peruskurssien laaja oppimäärä

Algoritmit 1. Demot Timo Männikkö

Kokeellista matematiikkaa SAGE:lla

TAMPEREEN TEKNILLINEN YLIOPISTO

Tietorakenteet, laskuharjoitus 1,

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

A TIETORAKENTEET JA ALGORITMIT

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Transkriptio:

815338A Ohjelmointikielten periaatteet 2015-2016. Harjoitus 6 Vastaukset Harjoituksen aiheena on funktionaalinen ohjelmointi Scheme- ja Haskell-kielillä. Voit suorittaa ohjelmat osoitteessa https://ideone.com/ tai http://www.tutorialspoint.com/codingground.htm. Tehtävä 1. Suorita Schemellä seuraavat laskutoimitukset 5-6 1/5 + 3/10 1.5 * (21.2-11.0)/3.2 Tuloksen näyttäminen onnistuu funktiolla display, esimerkiksi 12*13 ja rivinvaihto voitaisiin kirjoittaa (display (* 12 13)) (newline) Vastaus. Schemessä operaatiot kirjoitetaan listojen muodossa samaan tapaan kuin funktiotkin. Ensimmäiseksi tulee operaatio ja sitten argumentit. Mainitut laskutoimitukset kirjoitettaisiin (tuloksen näyttämisen kera) seuraavasti: (display (- 6 5)) (newline) (display (+ (/ 1 5) (/ 3 10))) (newline) (display (* 1.5 (/ (- 21.2 11.0) 3.2))) Kun lausekkeet ajetaan tulkissa, saadaan vastaukset 1 1/2 4.781249999999999 Tehtävä 2. Tutki seuraavia funktioita: a) Scheme-funktio (define (a_fun x y) (cond ((null? x) y) (else (cons (car x) (a_fun (cdr x) y))))) b) Haskell-funktio b_fun(x,[]) = [] b_fun(x,(y:ys)) = if x==y then (y:ys) else b_fun(x,ys)

Yritä ensin päätellä koodista funktioiden toiminta. Kopioi koodi tulkkiin ja kutsu funktiota; tarkista oliko päätelmäsi oikea. Scheme-funktion kutsu voidaan kirjoittaa esimerkiksi (display (a_fun (aa bb cc) (bb aa)) ja Haskell-funktion kutsu main = do print(b_fun ("aa", ["bb","aa","cc"])) Vastaus. a) Scheme-funktio (define (a_fun x y) (cond ((null? x) y) (else (cons (car x) (a_fun (cdr x) y))))) ottaa siis kaksi parametria, joista ainakin ensimmäisen tulee olla lista, koska siihen sovelletaan listojen operaatioita. Schemessä cond määrittelee monivalintalauseen toteuttavan funktion. Kun kohdataan ensimmäinen lauseke, joka evaluoituu todeksi, palautetaan sitä vastaava arvo: Jos siis x on tyhjä lista, palautetaan y. Jos x ei ole tyhjä, sovelletaan ensin funktiota x:n häntään (cdr x) ja y:hyn. Sitten x:n päästä (car x) ja muodostuneesta listasta muodostetaan lista. Jos x:ssä on vain yksi alkio (häntä on tyhjä), niin tämä alkio liitetään listan y alkuun. Rekursiivisesti päättelemällä huomataan, että funktio liittää listan x listan y alkuun. Tämän voi varmistaa kokeilemalla funktiota eri syötteillä tulkissa. Esimerkiksi (display (a_fun '(1 2 3) '(a b))) tulostaa (1 2 3 a b). b) Haskell-funktio b_fun(x,[]) = [] b_fun(x,(y:ys)) = if x==y then (y:ys) else b_fun(x,ys) ottaa myös kaksi parametria, joista jälkimmäinen on lista. Haskellissa voidaan funktioita määritellä hahmontunnistuksen avulla. Edellä oleva funktio palauttaa tyhjän listan, jos jälkimmäinen parametri on tyhjä lista. Jos jälkimmäinen parametri ei ole tyhjä lista, se jaetaan päähän y ja häntään ys. Jos parametri x on sama kuin listan pää, palautetaan lista. Muuten kutsutaan funktiota

rekursiivisesti parametreilla x ja listan häntä. Näin edetään, kunnes alkio x löytyy listasta ja palautetaan x:llä alkava listan osa, tai lista tyhjenee, jolloin palautetaan tyhjä lista. Funktio siis etsii listasta y loppuosan joka alkaa x:llä. Tämän voi myös tarkistaa tulkilla, esimerkiksi syötteellä main = do print (b_fun(3,[1,2,3,4,5])) tulostuu [3,4,5]. Tehtävä 3. Kirjoita Scheme-funktio kaanna, joka kääntää argumenttinaan saamansa listan. Listan syvärakennetta ei tarvitse kääntää, ts. syötteellä (a b c d) funktio palauttaa listan (d c b a) ja syötteellä (a (b c) (d e) (f g)) listan ((f g) (d e) (b c) a). Voit käyttää hyväksi Schemen varusfunktiota append, joka yhdistää parametrina annettavat kaksi listaa. Kannattanee kirjoittaa funktio tekstitiedostoon, josta kopioi Scheme-tulkkiin. Testaa funktiotasi. Vastaus. Lista voidaan kääntää rekursiivisesti siten, että tyhjän listan kääntäminen palauttaa tyhjän listan. Muuten lista käännetään niin, että ensin käännetään listan häntä ja käännetyn hännän perään liitetään listan pää. Näin saadaan rekursiivinen funktio (define (kaanna x) (cond ((null? x) '()) ((not (list? x)) x) (else (append (kaanna (cdr x)) (list (car x)))))) Yllä on otettu vielä huomioon, että funktiolle voidaan syöttää myös parametri joka ei ole lista. Tällöin palautetaan parametri sellaisenaan. Huomaa vielä, että listan pää ei välttämättä ole lista, joten siitä muodostetaan lista ennen sen lisäämistä käännetyn hännän perään.

Tehtävä 4. Kirjoita Scheme-funktio rullaa, joka tuottaa argumenttinaan saamastaan listasta sen kaikki kierrot eli rotaatiot ja esittää ne yhdessä listassa. Syötteellä (a b c d) funktio palauttaa siis listan ((a b c d) (b c d a) (c d a b) (d a b c)). Vihje: Toteutus tulee helpommaksi, jos kirjoittaa apufunktioita. Vastaus. Kirjoitetaan ensin apufunktio turn, joka tekee yhden rotaation, ts. siirtää listan pään sen viimeiseksi alkioksi: (define (turn x) (append (cdr x) (list (car x)))) Tämä funktio palauttaa esimerkiksi parametrilistalla (1 2 3 4) listan (2 3 4 1). Tätä funktiota toistuvasti soveltamalla saadaan kaikki rotaatiot. Pitää vain pystyä kontrolloimaan sitä, että saadaan täsmälleen oikea määrä rotaatioita. Rotaatioita on yhtä monta kuin listassa on alkioita, joten kirjoitetaan apufunktio roll, joka ottaa parametrinaan kaksi listaa. Ensimmäistä kierretään ja toista lyhennetään jokaisella kutsulla. Parametrilista lisätään palautettavan listan alkioksi. Rekursio päättyy, kun toinen lista tyhjenee: (define (roll x y) (cond ((null? x) '() ) ((null? y) '() ) (else (append (list x) (roll (turn x) (cdr y)) )))) Näin saadaan listan x kaikki rotaatiot yhteen listaan, kun kirjoitetaan funktio, joka kutsuu edellistä funktiota sama lista kumpanakin parametrina: (define (rullaa x) (if (list? x) (roll x x) '())) Tällöin kutsu (rullaa (1 2 3 4)) palauttaa listan ((1 2 3 4) (2 3 4 1) (3 4 1 2) (4 1 2 3))

Tehtävä 5. Kirjoita Haskellilla tehtävien 3 ja 4 funktiot. Vastaus. Käytetään samaa logiikkaa kuin Scheme-funktioissa. Tehtävän 3 funktio voidaan kirjoittaa seuraavasti: kaanna [] = [] kaanna (x:xs) = kaanna(xs) ++ [x] Huomaa, että Haskellissa listat kirjoitetaan hakasulkeisiin ja alkiot erotetaan pilkuilla. Haskellissa listan pää ja häntä voidaan käsitellä hahmontunnistuksella (x:xs) kuten yllä. Listoja yhdistellään operaattorilla ++. Tehtävän 4 funktio laaditaan samalla periaatteella kuin Scheme-funktio kahden apufunktion avulla. turn [] = [] turn (x:xs) = xs ++ [x] roll (x,[]) = [] roll (x,(y:ys)) = [x] ++ roll(turn(x),ys) rullaa x = roll(x,x) Haskell-koodi lienee kieliä tuntemattomalle luettavampaa kuin Scheme. Tehtävä 6. Fibonaccin lukujono määritellään seuraavasti: f0 = 0, f1 = 1,, fn = fn-1+fn-2. Jono on siis 0,1,1,2,3,5,8,13,21, jne. Lukujonon n:nnen termin palauttava funktio voidaan kirjoittaa seuraavasti: a) Schemellä (define (fibonacci n) (cond ((= n 0) 0) ((= n 1) 1) (else (+ (fibonacci (- n 1)) (fibonacci (- n 2)))))) b) Haskellilla fibonacci 0 = 0 fibonacci 1 = 1 fibonacci n = fibonacci(n-1) + fibonacci(n-2) Nämä funktiot sisältävät kaksinkertaisen rekursion, joten niillä ei voi laskea kovin suuria Fibonaccin lukuja (todennäköisesti jossain indeksien 30 ja 40 välillä laskenta alkaa kestää selvästi havaittavan ajan). Kirjoita funktioista tehokkaammat versiot ja laske niillä sadas Fibonaccin luku. Vihje: Tarkastele jonon peräkkäisten lukujen pareja.

Vastaus. Koska Fibonacci-lukuparin laskemiseksi tarvitsee tietää ainoastaan edellinen pari, laskenta saadaan käyttämään yksinkertaista rekursiota, kun lasketaan lukuparista (fn,fn-1) pari (fn+1,fn). Siten voidaan funktiot kirjoittaa seuraavasti: Scheme: (define (seuraava pari) (list (+ (car pari) (car (cdr pari))) (car pari))) (define (fibo_pari n) (if (= n 0) '(0 1) (seuraava (fibo_pari (- n 1)) ))) (define (fibo_fast n) (car (fibo_pari n))) Haskell: fibo_pari 0 = [0,1] fibo_pari n = [head pari + last pari,head pari] where pari = fibo_pari (n-1) fibo_fast n = head (fibo_pari n) Nämä funktiot selviävät helposti sadannen Fibonacci-luvun laskemisesta ja antavat arvoksi luvun 354224848179261915075. Harjoituksen Scheme-funktiot on koottu tiedostoon H6.scm ja Haskell-funktiot tiedostoon H6.hs, jossa on myös funktioita testaava pääohjelma.