Structure and Interpretation of Computer Programs
Table of Contents
- 1. Foreword and Preface
- 2. 1. Grajenje abstrakcij s procedurami
- 2.1. Elementi programiranja
- 2.2. Izvajanje kombinacij(e)
- 2.3. 1.1.4 Sestavljene procedure
- 2.4. 1.1.5 Substitucijski model za izvajanje procedur
- 2.5. meta
- 2.6. vaje
- 2.7. 1.1.8 Procedure kot crne skatle abstrakcij
- 2.8. 1.2.2 Drevesna rekurzija
- 2.9. 1.2.3 Redi rasti
- 2.10. 1.2.4 Eksponentna funkcija
- 2.11. 1.2.5 Najvecji skupni deljitel
- 2.12. 1.2.6 Primer: Iskanje prastevil
- 2.13. 1.3 Sestavljanje abstrakcij s procedurami visjega reda
- 2.14. 1.3.1 Procedure kot argumenti
- 2.15. 1.3.2 Sestavljanje procedur z
Lambda
- 2.16. 1.3.3 Procedure kot splosne metode
- 2.17. 1.3.4 Procedure kot vrnjene vrednosti
1. Foreword and Preface
Lisp je preživeli, v uporabi je že "polovico stoletja".
The discretionary exportable functionality entrusted to the individual Lisp programmer is more than an order of magniture greater than that to be found within Pascal enterprises.
Želimo vzpostaviti idejo, da programski jezik ni samo način, da računalnik izvaja operacije, ampak da je predvsem nov formalni medij za izražanje idej o metodologiji. Zato morajo biti programi napisani predvsem zato, da jih ljudje berejo, in slučajno, da jih izvajajo računalniki.
Bistvena tema ni sintaksa določenih struktur v programskem jeziku, niti …, temveč tehnike nadzora intelektualne kompleksnosti veliki programskih sistemov.
Naš pristop k temi izvira iz prepričanja, da "computer science" ni znanost in da ima njen pomen bolj malo opraviti z računalniki. Računalniška revolucija je revolucija v načinu mišljenja in izražanju idej. Bistvo teh sprememb najbolše opiše pojem proceduralne epistemologije, ki se ukvarja s strukturo vednosti z imperativnega stališča za razliko od klasične matematike, ki je bolj deklerativna. Matematika postavi okvir za natančno spoprijemanje s pojmovanjem "kaj je". Računanje pa ponudi okvir za natančno ukvarjanje s pojmovanjem "kako".
2. 1. Grajenje abstrakcij s procedurami
2.1. Elementi programiranja
- Primitivni izrazi
- predstavtljajo najpreprostejše gradnike (entitete) programskega jezika
- Načini kombinacije,
- s katerimi so sestavljeni elementi zgrajeni iz preprostejših
- Načini abstrakcije,
- s katerimi so lahko sestavljeni elementi poimenovani in omogočajo upravljanje z njimii kot enotami
2.2. Izvajanje kombinacij(e)
Postopek za izvajanje kombinacij:
- Izvedi podizraz kombinacije.
- Uporabi/uveljavi proceduro, ki je najbolje levi podizraz (operator) z argumenti, ki so vrednosti drugih podizrazov (operandi).
Postopek evalvacije je rekurziven, saj drugi korak v sebi vključuje prvega, oziroma vključuje svojo definicijo.
Tako se zgradi akumulacijsko drevo. Na koncu vedno prideš do točke, ko izvajaš primitivne izraze, ki so:
- vrednosti numeričnih števk, ki jo označujejo.
- vrednosti vgrajenih operatorjev so strojni ukazi sekvenc, ki izvedejo te operacije.
- vrednosti drugih imen so objekti asociirani s temi imeni v okolju.
Drugo pravilo je poseben primer tretjega pravila. Simboli + in * so tudi vključeni v globalno okolje in so asociirani s strojnimi ukazi, ki so njihove vrednosti. Pomembno je prepoznati vlogo okolja pri določanju pomena simbolov v izrazih.
To pravilo se ne nanaša na posebne oblike (special forms). define
je posebna
oblika.
2.3. 1.1.4 Sestavljene procedure
- Številke in aritmetične operacije so primitivni podatki in procedure.
- Gnezdenje kombinacij omogoča način za združevanje operacij.
- Definicije, ki asociirajo imena z vrednostmi omogočajo omejene načine abstrakcije.
(define (square x) (* x x))
(define square (lambda (x) (* x x)))
2.4. 1.1.5 Substitucijski model za izvajanje procedur
Za izvajanje sestavljenih procedur z argumenti, izvedeš telo procedure z vsakim formalnim parametrom, ki ga nadomestiš s pripadajočim argumentom.
ergh, tukaj se zapletam s slovenskimi prevodi
kaj je application in kaj evaluation?
Načini, na katere deluje interpreter (prevajalnik):
- Aplikativni vrstni red
- Najprej evalviraj operator in operande, potem pa izvedi proizvedeno proceduro s pridobljenimi argumenti.
- Normalni vrstni red
- Ne izvajaj operandov dokler njihove vrednost niso potrebne. Najprej zamenjaj izraze operandov s parametri, dokler ne pride do izraza, ki vsebuje zgolj primitivne izraze in potem izvedi (vso) evalvacijo.
2.5. meta
Linki: https://develop.spacemacs.org/layers/+lang/scheme/README.html https://www.nongnu.org/geiser/ https://www.gnu.org/software/guile/learn/ https://spritely.institute/static/papers/scheme-primer.html#introduction
Kako nastavit spacemacs, in malo o guile-u.
2.5.1. video lekcije
https://yewtu.be/channel/UCEBb1b_L6zDS3xTUrIALZOw (6.001 SICP: Structure and Interpretation of Computer Programs (2004)) https://yewtu.be/playlist?list=PL7BcsI5ueSNFPCEisbaoQ0kXIDX9rR5FF (MIT 6.001 Structure and Interpretation, 1986)
2.6. vaje
2.6.1. 1.3
- najprej narobe
Define a procedure that takes three numbers as arguments and returns the sum of the squares of the two larger numbers.
(define (sum-of-large x y z) (+ (if (> x y) (* x x) (* y y)) (if (> y z) (* y y) (* z z)) ) ) (sum-of-large 3 8 5)
(define (sum-of-larger x y z) (let* ((s (lambda (a) (* a a))) (sl (lambda (b c) (if (> b c) (s b) (s c)))) ) (+ (sl x y) (sl y z)) )) (sum-of-larger 3 8 5)
- pravilno
(define (sum-squares-of-larger x y z) (if (> x y) (if (> y z) (+ (* x x) (* y y)) (+ (* x x) (* z z)) ) (if (> x z) (+ (* y y) (* x x)) (+ (* y y) (* z z)) ) ) ) (sum-squares-of-larger 9 10 8)
2.6.2. 1.5
Aplikativni vrstni red: pade takoj v neskoncno zanko. Normalni vrstni red: izvrsi test in pride v if, ki ne izvrsi drugega dela.
2.6.3. 1.6
2.6.4. 1.7
good-enough?
ni vredu za iskanje korenov majhnih stevil.- pravtako za zelo velika stevila
- napisi alternativno
good-enough?
proceduro, ki bo gledala, kdaj so spremembe dovolj majhne in takrat prekini funkcijo.
// Poglej v sqrt-newton.scm
2.6.5. 1.8
// Glej v sqrt-newton.sqm
2.7. 1.1.8 Procedure kot crne skatle abstrakcij
- block structure
- lexical scoping
2.8. 1.2.2 Drevesna rekurzija
2.9. 1.2.3 Redi rasti
2.10. 1.2.4 Eksponentna funkcija
#name: exponent
;; O(n) korakov in O(n) prostora (define (expt b n) (if (= n 0) 1 (* b (expt b (- n 1))) ) ) (define (expt-i b n) (expt-iter b n 1) ) ;; O(n) korakov O(1) prostor (define (expt-iter b cnt prod) (if (= cnt 0) prod (expt-iter b (- cnt 1) (* b prod)) ) ) (define (fast-expt b n) (cond ((= n 0) 1) ((even? n) (square (fast-expt b (/ n 2)))) (else (* b (fast-expt b (- n 1)))) ) ) (define (even? n) (= (remainder n 2) 0)) (define (square x) (* x x)) ;; 1.16 ;; successive squaring (fast-expt) but with iteration. ;; transformation (* a (expt b n)) constant (define (fast-expt-i b n) (fast-expt-iter b n 1) ) (define (fast-expt-iter b n a) (cond ((= n 0) a) ((even? n) (fast-expt-iter (square b) (/ n 2) a)) (else (fast-expt-iter b (- n 1) (* a b))) ) ) ;; I'm not sure why this works. I was just guessing. ;; excersize 1.17 (define (slow-multi a b) (if (= b 0) 0 (+ a (* a (- b 1))) ) ) (define (halve x) (/ x 2)) (define (double x) (* x 2)) (define (fast-multi a b) (cond ((= b 0) 0) ((even? b) (double (fast-multi a (halve b)))) (else (+ a (fast-multi a (- b 1)))) ) ) ;; excersize 1.18 (define (fast-multi-i a b) (fast-multi-iter a b 0) ) (define (fast-multi-iter a b s) (cond ((= b 0) s) ((even? b) (fast-multi-iter (double a) (halve b) s)) (else (fast-multi-iter a (- b 1) (+ s a))) ) )
2.11. 1.2.5 Najvecji skupni deljitel
2.12. 1.2.6 Primer: Iskanje prastevil
2.13. 1.3 Sestavljanje abstrakcij s procedurami visjega reda
Procedure, ki spreminjajo druge procedure se imenujejo procedure višjega reda.
2.14. 1.3.1 Procedure kot argumenti
Primer vsote.
//exercise 1.29 #name: simpson
(define (sum term a next b) (if (> a b) 0 (+ (term a) (sum term (next a) next b) ) ) ) (define (integral f a b dx) (define (add-dx x) (+ x dx)) (* (sum f (+ a (/ dx 2.0)) add-dx b) dx) ) (define (sum-s term a next b fact) ;; fact is altering between 4 and 2 (define (check-fact fact) (if (= fact 4) 2 4)) (if (> a b) 0 (+ (* fact (term a)) (sum-s term (next a) next b (check-fact fact)) ) ) ) (define (simpson f a b dx) (define (add-dx x) (+ x dx)) (* (+ (f a) (f b) (sum-s f (add-dx a) add-dx (- b dx) 4) ) (/ dx 3.0)) ) (define (simpson-gizmo f a b dx) (define (add-dxdx x) (+ x dx dx)) (* (+ (* 4 (sum f (+ a dx) add-dxdx b)) (* 2 (sum f a add-dxdx b)) (- (f a)) (- (f b)) ) (/ dx 3.0)) ) (define (cube x) (* x x x)) (list (integral cube 1 2 0.01) (integral cube 1 2 0.001) (simpson cube 1 2 0.01) (simpson cube 1 2 0.001) (simpson cube 1 2 (/ 1 1000)) (simpson-gizmo cube 1 2 0.01) (simpson-gizmo cube 1 2 (/ 1 10000)) (simpson-gizmo cube 1 2 0.00001) )
// exercise 1.30
(define (sum-i term a next b) (define (iter a result) (if (> a b) result (iter (next a) (+ result (term a))) ) ) (iter a 0) )
// excercise 1.30, 1.31. 1.32
;; Analogno napisi produkt kot vsoto. ;; Pokazi kako izgleda fakulteta. ;; Aproksimacija pi/4 = 2/3*4/3*4/5*6/5*6/7*8/7... (define (produkt-r term a next b) ;; a, b sta spodnja in zgornja meja (if (> a b) 1 (* (term a) (produkt-r term (next a) next b)) ) ) (define (fakulteta-p n) (produkt-r (lambda (x) x) 1 (lambda (x) (+ x 1)) n) ) (define (pribl-pi n) (produkt-r (lambda (a) (/ (* (- a 1.0) (+ a 1.0)) (* a a))) 3.0 (lambda (x) (+ x 2.0)) n ) ) ;; gizmo se je spomnil resitve - dva produkta (zgornji in spodnji) ;; iterativni produkt-i (define (produkt-i term a next b) (define (iter-p a result) (if (> a b) result (iter-p (next a) (* result (term a))) ) ) (iter-p a 1) ) (define (pribl-pi-term a) (/ (* (- a 1.0) (+ a 1)) (* a a))) (define (pribl-pi-next a) (+ a 2.0)) (define (pribl-pii n) (produkt-i pribl-pi-term 3.0 pribl-pi-next n ))
2.15. 1.3.2 Sestavljanje procedur z Lambda
Splosna forma let
izraza
(let ((<var1> <exp1>) (<var2> <exp2>) ... (<varn> <expn>)) <body>)
To je okrajsava za
((lambda (<var1> ... <varn>) <body>) <exp1> ... <exp2> )
2.16. 1.3.3 Procedure kot splosne metode
Ce pogledamo proceduro za integral, vidimo mocnejse abstrakcije: procedure, ki izrazajo splosne racunske metode, neodvisne od posameznih vkljucenih funkcij.
2.17. 1.3.4 Procedure kot vrnjene vrednosti
V splošnem programski jeziki omejujo, kateri komputacijski elemente lahko (koda) spreminja. Elementi z najmanj omejitvami imajo prvorazredni status. Pravice in privilegiji prvorazrednih elementov so:
- lahko so poimenovani s spremenljivkami
- lahko so podani kot argumenti procedur
- lahko so vrnjeni kot rezultati procedur
- lahko so vključeni v podatkovne strukture
V Lispu imajo, za razliko od drugih programskih jezikov, procedure prvorazredni status. To predstavlja težave za implementacijo, ampak nudi višjo ekspresivno moč programskega jezika. Najvišja cena pri implementaciji procedur s prvorazrednim statusom je, da je potrebno rezervirati prostor za procedurine proste spremenljivke tudi, ko se procedura ne izvaja. V scheme-u so te spremenljivke shranjene v procedurino okolje (poglavje 4.1).