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ä

Scheme-kesäkurssi luento 3

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 5

Ohjelmoinnin peruskurssien laaja oppimäärä

Scheme-kesäkurssi luento 4

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

Scheme-kesäkurssi luento 2

Scheme-kesäkurssi luento 1

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin perusteet Y Python

Makrojen mystinen maailma lyhyt oppimäärä

Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Ohjelmoinnin peruskurssien laaja oppimäärä

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

Scheme-kesäkurssi luento 6

Ohjelmoinnin perusteet Y Python

1.3Lohkorakenne muodostetaan käyttämällä a) puolipistettä b) aaltosulkeita c) BEGIN ja END lausekkeita d) sisennystä

Ohjelmoinnin peruskurssien laaja oppimäärä

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

ICS-C2000 Tietojenkäsittelyteoria Kevät 2016

Ohjelmointi 1 C#, kevät 2013, 2. tentti

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

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

Ohjelmoinnin perusteet Y Python

Sisällys. 17. Ohjelmoinnin tekniikkaa. Aritmetiikkaa toisin merkiten. for-lause lyhemmin

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Tieto- ja tallennusrakenteet

Tutoriaaliläsnäoloista

Ohjelmoinnin perusteet Y Python

Tietorakenteet ja algoritmit - syksy

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

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

Hohde Consulting 2004

Loppukurssin järjestelyt

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

815338A Ohjelmointikielten periaatteet

Sisällys. 16. Ohjelmoinnin tekniikkaa. Aritmetiikkaa toisin merkiten. Aritmetiikkaa toisin merkiten

811120P Diskreetit rakenteet

815338A Ohjelmointikielten periaatteet

16. Ohjelmoinnin tekniikkaa 16.1

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen

Ohjelmointiharjoituksia Arduino-ympäristössä

A TIETORAKENTEET JA ALGORITMIT

11/20: Konepelti auki

16. Ohjelmoinnin tekniikkaa 16.1

Loppukurssin järjestelyt C:n edistyneet piirteet

Ohjelmoinnin perusteet Y Python

JReleaser Yksikkötestaus ja JUnit. Mikko Mäkelä

Jatkeet. TIES341 Funktio ohjelmointi 2 Kevät 2006

Racket ohjelmointia osa 2. Tiina Partanen Lielahden koulu 2014

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

Javascript 2: Ohjelmointikielen ominaisuudet. Jaana Holvikivi Metropolia

Olio-ohjelmointi Syntaksikokoelma

Ohjelmoinnin perusteet Y Python

13. Loogiset operaatiot 13.1

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin peruskurssi Y1

Taas laskin. TIES341 Funktio ohjelmointi 2 Kevät 2006

Ohjelmoinnin perusteet Y Python

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Tietueet. Tietueiden määrittely

Luku 3. Listankäsittelyä. 3.1 Listat

Ohjelmoinnin peruskurssi Y1

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

Ohjelmoinnin perusteet Y Python

TIEP114 Tietokoneen rakenne ja arkkitehtuuri, 3 op. Assembly ja konekieli

Ohjelmoinnin peruskurssi Y1

812347A Olio-ohjelmointi, 2015 syksy 2. vsk. X Poikkeusten käsittelystä

1.3 Lohkorakenne muodostetaan käyttämällä a) puolipistettä b) aaltosulkeita c) BEGIN ja END lausekkeita d) sisennystä

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin peruskurssi Y1

Transkriptio:

Ohjelmoinnin peruskurssien laaja oppimäärä Luento 9: cond, paikalliset muuttujat, kirjan tulkki kokonaisuutena (mm. SICP 3.2, 4.1.24.1.6) Riku Saikkonen 21. 11. 2011

Sisältö 1 Syntaksimuunnos: cond->if 2 Ympäristöt: miten paikalliset muuttujat toimivat (SICP 3.2) 3 Paikallisten muuttujien toteuttaminen tulkkiin 4 Kirjan tulkki valmiina kokonaisuutena 5 Kirjan tulkin muokkaaminen 6 Yksityiskohta: sisäiset määrittelyt (SICP 3.2.4 ja 4.1.6)

Syntaksimuunnos cond->if (SICP 4.1.2) mikä tahansa cond-lauseke voidaan muuttaa jonoksi if-lausekkeita koodista tulee hieman pidempää, mutta samalla tavalla toimivaa (samat ehdot pitäisi käydä läpi jos cond toteutettaisiin suoraan) muunnosta tehdessä ei tarvitse tietää muun tulkin toiminnasta vain osata muokata tulkattavia lausekkeita Esimerkki muunnoksesta (cond ((> x 0) x) ((= x 0) (display 'zero) 0) (else (- x))) muuttuu muotoon (if (> x 0) x (if (= x 0) (begin (display 'zero) 0) (- x)))

Toteutus cond->if:lle 1/2 (SICP 4.1.2) jotta muunnoksen voisi tehdä säilyttäen syntaksiabstraktiot (eikä suoraan listarakennetta tuottamalla), tarvitaan apuproseduurit if- ja begin-lausekkeiden tekemiseen evalissa vain evaluoidaan syntaksimuunnoksen lopputulos Apuproseduureja ja eval-lisäys (define (make-if predicate consequent alternative) (list 'if predicate consequent alternative)) nelilaskin10.scm (define (make-begin seq) (cons 'begin seq)) (define (sequence->exp seq) ; ''optimoitu'' make-begin (cond ((null? seq) seq) ((last-exp? seq) (first-exp seq)) (else (make-begin seq)))) (define (eval exp env) (cond... ((cond? exp) (eval (cond->if exp) env))... ))

Toteutus cond->if:lle 2/2 (SICP 4.1.2) Itse cond->if-muunnos (define (cond? exp) (tagged-list? exp 'cond)) (define (cond-clauses exp) (cdr exp)) (define (cond-else-clause? clause) (eq? (cond-predicate clause) 'else)) (define (cond-predicate clause) (car clause)) (define (cond-actions clause) (cdr clause)) nelilaskin10.scm (define (cond->if exp) (expand-clauses (cond-clauses exp))) (define (expand-clauses clauses) (if (null? clauses) 'false ; tulkattavaa koodia, joka suoritetaan kun else:ä ei ole (let ((first (car clauses)) (rest (cdr clauses))) (if (cond-else-clause? first) (if (null? rest) (sequence->exp (cond-actions first)) (error "ELSE clause isn't last -- COND->IF" clauses)) (make-if (cond-predicate first) (sequence->exp (cond-actions first)) (expand-clauses rest))))))

Sisältö 1 Syntaksimuunnos: cond->if 2 Ympäristöt: miten paikalliset muuttujat toimivat (SICP 3.2) 3 Paikallisten muuttujien toteuttaminen tulkkiin 4 Kirjan tulkki valmiina kokonaisuutena 5 Kirjan tulkin muokkaaminen 6 Yksityiskohta: sisäiset määrittelyt (SICP 3.2.4 ja 4.1.6)

Mitä tässä tehdään? ympäristö on tapa (tulkin tietorakenne), jolla paikalliset muuttujat toteutetaan niiden avulla voi myös ymmärtää kielen toimintaa tarkemmin, erityisesti miten toistensa sisällä määritellyt proseduurit toimivat ympäristöt toimivat samalla tavalla useimmissa ohjelmointikielissä tarkemmin sanoen ne kertovat, miten leksikaalinen sidonta toimii mutta monissa kielissä ympäristöjä ei voi käyttää yhtä monipuolisesti kuin Schemessä (esim. monissa kielissä proseduureja ei voi määritellä sisäkkäin) ympäristö on eri asia kuin kutsupino: ympäristö kertoo, mistä nyt näkyvien muuttujien arvot haetaan kutsupino kertoo, mitä tehdään tämän funktion jälkeen alempana kutsupinossa on usein viittauksia toisiin ympäristöihin (joissa on usein yhteisiä osia) monissa kielissä (mm. C) kutsupinossa on myös muuttujien arvoja (silloin usein esim. palautettuja funktioita ei tueta)

Mikä on ympäristö? (SICP 3.2) Esimerkkikoodi (let ((x 1) (y 2)) (let ((a (+ x y)) (b (+ y y))) (* y a))) lauseketta (* y a) evaluoidessa sen muuttujat haetaan ympäristöstä, jossa on (ainakin) kolme kehystä: sisin kehys: a = 3, b = 4 toinen kehys: x = 1, y = 2 globaali ympäristö: * = kertolaskuprimitiivi,... muuttujan arvoa haettaessa sen nimeä etsitään ympäristöstä sisimmästä kehyksestä ulospäin nämä kehykset tulevat lauseketta ympäröivästä koodista ei siis niistä proseduureista, joista koodia on tällä kertaa kutsuttu (se olisi dynaamista eikä leksikaalista sidontaa) let:llä määritellyt paikalliset muuttujat ja proseduurien argumentit ovat ympäristöjen kannalta samanlaisia

Proseduurit ja ympäristöt: tallennus (SICP 3.2.3) Koodiesimerkki (define (make-counter val) (define f (make-counter 1)) (lambda (add) (define g (make-counter 2)) (set! val (+ val add)) (f 3) 4 val)) (g 4) 6 mitä muuttujien f ja g arvoissa pitää olla tallessa? proseduurin koodi (molemmissa sama (lambda (add)...)) ja ympäristö, jossa proseduuri on määritelty f:ssä on tallessa ympäristö, jossa on kaksi kehystä: sisin kehys F 1 : val = 1 globaali ympäristö F 0 : +, make-counter jne. g:ssä on viittaus samaan F 0 :aan, mutta eri sisin kehys: sisin kehys F 2 : val = 2 globaali ympäristö F 0 : +, make-counter jne.

Proseduurit ja ympäristöt: kutsuminen (SICP 3.2.2, 3.2.3) Koodiesimerkki (define (make-counter val) (define f (make-counter 1)) (lambda (add) (define g (make-counter 2)) (set! val (+ val add)) (f 3) 4 val)) (g 4) 6 f:ää kutsuttaessa siihen talletetun ympäristön eteen (sisemmäksi) tulee vielä yksi kehys, jossa on argumentti add ja sen arvo; esim. uusi sisin kehys F 3 : add = 3 (f 3): toinen kehys F 1 : val = 1 globaali ympäristö F 0 : +, make-counter jne. huom. proseduurikutsu tehdään siis käyttäen proseduurissa tallessa olevaa ympäristöä (eli sen määrittely-ympäristöä), ei kutsun tehneen koodin ympäristöä f:n koodin set! muuttaa kehyksessä F 1 olevaa val-muuttujan arvoa (sama kehys säilyy tallessa f:ssä)

Sisältö 1 Syntaksimuunnos: cond->if 2 Ympäristöt: miten paikalliset muuttujat toimivat (SICP 3.2) 3 Paikallisten muuttujien toteuttaminen tulkkiin 4 Kirjan tulkki valmiina kokonaisuutena 5 Kirjan tulkin muokkaaminen 6 Yksityiskohta: sisäiset määrittelyt (SICP 3.2.4 ja 4.1.6)

Ympäristöt kirjan tulkeissa (SICP 4.1.3) ympäristö on toteutettu listana kehyksiä sisimmästä uloimpaan; kehys on (cons lista muuttujien nimistä lista arvoista ) kirjassa määritellään proseduurit ympäristöjen käsittelyyn: lookup-variable-value, set-variable-value! ja define-variable! (extend-environment vars vals base-env ) laajentaa base-env iä uudella kehyksellä (ei muuta alkuperäistä) ja kehysten käsittelyyn mm: (add-binding-to-frame! var val frame ) lisää kehykseen uuden muuttujan nämä vain käsittelevät ympäristö-tietorakennetta: (list (cons '(a b) '(3 4)) ; sisin kehys (cons '(x y) '(1 2)) ; toinen kehys (cons '(*...) '(<primitiivi>...))) ; globaali ympäristö joka voitaisiin tehdä tähän tapaan: (extend-environment (list 'a 'b) (list 3 4) (extend-environment (list 'x 'y) (list 1 2) the-global-environment))

Ympäristöjen toteutus 1/3 (SICP 4.1.3) Apuproseduurit kehysten ja ympäristöjen käsittelyyn (define (make-frame variables values) (cons variables values)) (define (frame-variables frame) (car frame)) (define (frame-values frame) (cdr frame)) (define (add-binding-to-frame! var val frame) (set-car! frame (cons var (car frame))) (set-cdr! frame (cons val (cdr frame)))) ;; ympäristön sisin kehys ja ''loput kehykset'' eli ympäröivä ympäristö (define (first-frame env) (car env)) (define (enclosing-environment env) (cdr env)) ;; tekee uuden kehyksen sisimmäksi kehykseksi (define (extend-environment vars vals base-env) (if (= (length vars) (length vals)) (cons (make-frame vars vals) base-env) (if (< (length vars) (length vals)) (error "Too many arguments supplied" vars vals) (error "Too few arguments supplied" vars vals)))) m-eval.scm

Ympäristöjen toteutus 2/3 (SICP 4.1.3) Uuden muuttujan määritteleminen (define (define-variable! var val env) (let ((frame (first-frame env))) (define (scan vars vals) (cond ((null? vars) ; normaali tapaus: tee uusi muuttuja (add-binding-to-frame! var val frame)) ((eq? var (car vars)) (set-car! vals val)) (else (scan (cdr vars) (cdr vals))))) (scan (frame-variables frame) (frame-values frame)))) m-eval.scm normaalisti define-variable! lisää uuden muuttujasidonnan env:n sisimpään kehykseen (ei katso ulompia kehyksiä) jos muuttuja on jo olemassa sisimmässä kehyksessä, define-variable! muuttaakin sen arvoa eikä määrittele uutta Schemen define toimii näin (tosin tätä harvoin käytetään) ilman tätä sen voisi määritellä yksinkertaisesti: (define (define-variable! var val env) (add-binding-to-frame! var val (first-frame env)))

Ympäristöjen toteutus 3/3 (SICP 4.1.3) Olemassaolevien muuttujien käsittely m-eval.scm (define (lookup-variable-value var env) (define (env-loop env) (define (scan vars vals) (cond ((null? vars) (env-loop (enclosing-environment env))) ((eq? var (car vars)) (car vals)) (else (scan (cdr vars) (cdr vals))))) (if (eq? env the-empty-environment) (error "Unbound variable" var) (let ((frame (first-frame env))) (scan (frame-variables frame) (frame-values frame))))) (env-loop env)) (define (set-variable-value! var val env) (define (env-loop env) (define (scan vars vals) (cond ((null? vars) (env-loop (enclosing-environment env))) ((eq? var (car vars)) (set-car! vals val)) (else (scan (cdr vars) (cdr vals))))) (if (eq? env the-empty-environment) (error "Unbound variable -- SET!" var) (let ((frame (first-frame env))) (scan (frame-variables frame) (frame-values frame))))) (env-loop env))

Ympäristön alustus (SICP 4.1.4) tehdään vielä globaalin ympäristön alustaminen abstraktimmin eli extend-environment:lla eikä suoraan consilla Lopullinen setup-environment m-eval.scm (define the-empty-environment '()) (define (setup-environment) (let ((initial-env ;; oli: (cons (primitive-procedure-names) ;; (primitive-procedure-objects)) (extend-environment (primitive-procedure-names) (primitive-procedure-objects) the-empty-environment))) (define-variable! 'true true initial-env) (define-variable! 'false false initial-env) initial-env)) (define the-global-environment (setup-environment))

Proseduurit ja lambda ympäristöillä (SICP 4.1.2, 4.1.3) Apufunktiot proseduurien ja lambdan käsittelyyn (define (lambda? exp) (tagged-list? exp 'lambda)) (define (lambda-parameters exp) (cadr exp)) (define (lambda-body exp) (cddr exp)) (define (make-lambda parameters body) (cons 'lambda (cons parameters body))) m-eval.scm (define (compound-procedure? p) (tagged-list? p 'procedure)) (define (procedure-parameters p) (cadr p)) (define (procedure-body p) (caddr p)) (define (procedure-environment p) (cadddr p)) (define (make-procedure parameters body env) (list 'procedure parameters body env)) lambda-lausekkeen argumentteihin pääsee nyt käsiksi tulkkiin määriteltyyn proseduuriin talletetaan argumenttien nimet ja proseduurin määrittely-ympäristö

Ympäristöt evaliin ja applyyn (SICP 4.1.1) Muutokset evalissa ja applyssä m-eval.scm (define (eval exp env) (cond... ((lambda? exp) (make-procedure (lambda-parameters exp) (lambda-body exp) env))... ((application? exp) (apply (eval (operator exp) env) (list-of-values (operands exp) env) ;; ei enää env-argumenttia applylle ))... )) (define apply-in-underlying-scheme apply) (define (apply procedure arguments) ; ei env-argumenttia (cond ((primitive-procedure? procedure) (apply-primitive-procedure procedure arguments)) ((compound-procedure? procedure) (eval-sequence (procedure-body procedure) (extend-environment (procedure-parameters procedure) arguments (procedure-environment procedure)))) (else (error "Unknown procedure type -- APPLY" procedure))))

Parannus proseduurien tulostamiseen (SICP 4.1.4) Lopulliset käyttöliittymäproseduurit (define input-prompt ";;; M-Eval input:") (define output-prompt ";;; M-Eval value:") (define (prompt-for-input string) (newline) (newline) (display string) (newline)) (define (announce-output string) (newline) (display string) (newline)) m-eval.scm (define (driver-loop) (prompt-for-input input-prompt) (let ((input (read))) (let ((output (eval input the-global-environment))) (announce-output output-prompt) (user-print output))) ; oli display (driver-loop)) (define (user-print object) (if (compound-procedure? object) (display (list 'compound-procedure (procedure-parameters object) (procedure-body object) '<procedure-env>)) (display object)))

Sisältö 1 Syntaksimuunnos: cond->if 2 Ympäristöt: miten paikalliset muuttujat toimivat (SICP 3.2) 3 Paikallisten muuttujien toteuttaminen tulkkiin 4 Kirjan tulkki valmiina kokonaisuutena 5 Kirjan tulkin muokkaaminen 6 Yksityiskohta: sisäiset määrittelyt (SICP 3.2.4 ja 4.1.6)

Mitä kirjan tulkki tukee? kirjan kohtien 4.14.1.6 tulkki tukee Schemestä: proseduureja, muuttujia, argumentteja (yhtä monta kuin alla oleva), rekursiota, häntärekursiota, jne. erikoismuotoja quote, set!, define, if, lambda, begin ja cond (ei condin erikoisempia syntakseja) primitiivejä car, cdr, cons, null?, +, -, *, /, =, display, newline (uusia on helppo lisätä primitive-procedures-listaan) yleisimmin käytetyistä Schemen erikoismuodoista puuttuu esim. let, and ja or (kirjassa harjoitustehtävinä) myös tulkin virheidenkäsittely on melko yksinkertaista kohdassa 4.1.7 tehdään tästä tulkista hieman optimoidumpi versio, joka analysoi suoritettavan lausekkeen rakennetta etukäteen (ei käsitellä kurssilla)

Miten kirjan tulkkia käytetään? kirjan tulkin koodi löytyy kurssilaajennuksesta m-eval koodia kannattanee pitää esillä myös kirjaa lukiessa käyttö joko käyttöliittymällä: (driver-loop) tai suoraan evalia kutsumalla: (eval '(+ 1 2) the-global-environment) tai: (eval '(+ 1 2) (setup-environment)) globaalin ympäristön voi resetoida: (myös set! kävisi) (define the-global-environment (setup-environment)) kurssilaajennuksessa m-eval-display on versio, joka näyttää evalin ja applyn kutsut lyhyesti

Kirjan tulkin ajoesimerkki: (fact 0) (define (fact n) (if (= n 0) 1 (* n (fact (- n 1))))) ;;; M-Eval input: (fact 0) eval (fact 0) ; evalin haara ((application? exp) (apply...)) eval fact ; siinä kutsuttu list-of-values aiheuttaa tämän eval 0 ; ja tämän apply <procedure fact> 0 ; tästä (eval-sequence (procedure-body...)...) eval (if (= n 0) 1 (* n (fact (- n 1)))) eval (= n 0) ; (if (true? (eval (if-predicate exp) env))...) eval = ; taas application?-haara, joka tulee (= n 0):sta eval n eval 0 apply <primitive => 0 0 eval 1 ;;; M-Eval value: 1 ; (eval (if-consequent exp) env) ; ja 1 on self-evaluating?

Kirjan tulkin ajoesimerkki: (fact 1) eval (fact 1) eval fact ; arvo eli proseduuri haetaan lookup-variable-valuella eval 1 ; tämä taas on self-evaluating? apply <procedure fact> 1 eval (if (= n 0) 1 (* n (fact (- n 1)))) eval (= n 0) ; if-predicate eval = eval n eval 0 apply <primitive => 1 0 ; tässä välissä true? katsoo paluuarvoa #f eval (* n (fact (- n 1))) ; joten (eval (if-alternative exp) env) eval * eval n eval (fact (- n 1)) ; application?-haara: eval fact ; list-of-values aiheuttaa tämän eval (- n 1) ; ja tämän, jossa uusi application? eval - ; joka aiheuttaa nämä kolme eval n eval 1 apply <primitive -> 1 1 apply <procedure fact> 0... samoin kuin edellisessä esimerkissä 1 apply <primitive *> 1 1 ;; ei enempää evalin eikä applyn kutsuja, paluuarvo 1

Sisältö 1 Syntaksimuunnos: cond->if 2 Ympäristöt: miten paikalliset muuttujat toimivat (SICP 3.2) 3 Paikallisten muuttujien toteuttaminen tulkkiin 4 Kirjan tulkki valmiina kokonaisuutena 5 Kirjan tulkin muokkaaminen 6 Yksityiskohta: sisäiset määrittelyt (SICP 3.2.4 ja 4.1.6)

Tulkin muokkaaminen tulkkiin lisätään ominaisuuksia yleensä muokkaamalla sitä jollain näistä tavoista: 1 lisätään uusia primitiiviproseduureja 2 lisätään uusia johdettuja lausekkeita (kuten cond tehtiin) 3 lisätään uusia erikoismuotoja (kuten esim. if tehtiin) tässä(kään) ei ole mitään erityisen Scheme-spesistä: samat kolme vaihtoehtoa olisi esim. Python-tulkin muokkaamisessa primitiiviproseduuri riittää, jos uusi lauseke voi evaluoida kaikki argumenttinsa ennen kuin proseduuriin päästään (esim. if ei voi) uusia johdettuja lausekkeita voi tehdä myös tulkkia muuttamatta, jos kieli tukee makroja (lähinnä Lisp-kielet tukevat) ihan kaikkia ominaisuuksia ei voi toteuttaa näin: joskus tulkin rakennetta pitää muuttaa enemmän esim. poikkeusten (try, catch ja throw) toteuttaminen vaatisi enemmän muutoksia, jos alla olevassa kielessä ei olisi vastaavaa ominaisuutta (Schemessä on)

Tulkin muokkaaminen: uusi primitiivi primitiiviproseduureja on helppo lisätä: lisätään vain niiden toteutus primitive-procedures-listaan hankalampaa, jos primiivi ottaa argumentiksi tai palauttaa proseduureja (kuten map) tai uuden primitiivin voisi määritellä tulkin sisällä: esim. kutsua setup-environmentista evalia omalla define-lausekkeella Esimerkki uusien primitiivien lisäämisestä (muutokset punaisella) (define (average x y) (/ (+ x y) 2)) (define primitive-procedures (list... (list 'length length) (list 'average average) (list 'print display)...)) ; Schemen primitiivi ; itse toteutettu primitiivi ; uudelleennimetty Schemen primitiivi

Tulkin muokkaaminen: uusi johdettu lauseke 1 tehdään apuproseduurit, jotka tunnistavat uuden lausekkeen ja jakavat sen osiin 2 tehdään muunnosproseduuri, joka muuntaa uuden lausekkeen koodiksi, jota tulkki ennestään tukee 3 lisätään evaliin haara, joka kutsuu muunnosproseduuria Esimerkki uuden johdetun lausekkeen lisäämisestä ;; käyttöesimerkki: (let ((a 2)) (unless (= a 0) (/ 1 a) 0)) 1/2 (define (unless? exp) (tagged-list? exp 'unless)) (define (unless-predicate exp) (cadr exp)) (define (unless-alternative exp) (caddr exp)) (define (unless-consequent exp) (cadddr exp)) (define (unless->if exp) ; muunnos (unless a b c) (if a c b) (make-if (unless-predicate exp) (unless-consequent exp) (unless-alternative exp))) (define (eval exp env) (cond... ((unless? exp) (eval (unless->if exp) env))... ))

(define (eval exp env) (cond... ((prog? exp) (eval-prog (prog-n exp) (prog-exps exp) env #f))... )) Tulkin muokkaaminen: uusi erikoismuoto 1 tehdään apuproseduurit, jotka tunnistavat uuden lausekkeen ja jakavat sen osiin 2 tehdään proseduuri, joka suorittaa (tulkitsee) uuden lausekkeen 3 lisätään evaliin haara uudelle lausekkeelle Esimerkki uuden erikoismuodon lisäämisestä m-eval-prog.scm ;; (prog n lauseke...): kuten begin, mutta saa valita minkä lausekkeen ;; arvo palautetaan; esim. (let ((x 5)) (prog 1 x (set! x (+ x 1))) 5 (define (prog? exp) (tagged-list? exp 'prog)) (define (prog-n exp) (cadr exp)) (define (prog-exps exp) (cddr exp)) (define (eval-prog n exps env saved) ; ei säilytä häntärekursiota! (if (null? exps) saved (let ((result (eval (car exps) env))) (eval-prog (- n 1) (cdr exps) env (if (= n 1) result saved)))))

Sisältö 1 Syntaksimuunnos: cond->if 2 Ympäristöt: miten paikalliset muuttujat toimivat (SICP 3.2) 3 Paikallisten muuttujien toteuttaminen tulkkiin 4 Kirjan tulkki valmiina kokonaisuutena 5 Kirjan tulkin muokkaaminen 6 Yksityiskohta: sisäiset määrittelyt (SICP 3.2.4 ja 4.1.6)

Sisäiset määrittelyt (SICP 3.2.4, 4.1.6) tulkkien ja ympäristöjen yhteydessä ei vielä käsitelty pientä yksityiskohtaa: paikallisten (eli toisen proseduurin sisäisten) proseduurien määrittelyä miten paikallisten proseduurien määrittely definellä vaikuttaa ympäristöihin? define lisää muuttujan sen evaluointiympäristön sisimpään kehykseen (ei siis tee uutta kehystä kuten let) joten sisäiset määrittelyt lisätään proseduuria kutsuttessa luotuun kehykseen (samaan kuin proseduurin argumentit) myös kohdan 4.1 tulkki toimii näin (define-variablessa) entä jos paikalliset proseduurit viittaavat toisiinsa? define lisää ne samaan kehykseen, joten kaikki samalla tasolla määritellyt näkevät toisensa kaikki siis toimii loogisesti, jos defineä käyttää kuten kirjassa on tapana (ensin definet, sitten muu koodi)

Sisäiset määrittelyt: define ja letrec (SICP 3.2.4, 4.1.6) sisäisellä definellä määriteltyjen muuttujien arvoja saa käyttää vasta kun kaikki definet on suoritettu käytännössä proseduurin rungossa on ensin definet paikallisille proseduureille ja sitten vasta muu koodi definellä ei pitäisi määritellä tavallisia muuttujia (vaan letillä) toinen tapa paikallisten proseduurien tekemiseen on letrec kuten let, mutta määritelmien sisällä voi viitata samassa letrecissä määriteltäviin muuttujiin käsitteellisesti siistimpi kuin sisäinen define: paikalliset määrittelyt ja proseduurin varsinainen koodi erottuvat toisistaan define- ja letrec-esimerkki (define (my-odd-1? x) (define (even? n) (if (= n 0) true (odd? (- n 1)))) (define (odd? n) (if (= n 0) false (even? (- n 1)))) (odd? x)) (define (my-odd-2? x) ; sama letrecillä (letrec ((even? (lambda (n) (if (= n 0) true (odd? (- n 1))))) (odd? (lambda (n) (if (= n 0) false (even? (- n 1)))))) (odd? x)))