#+TITLE: Zapiski #1 srečanja programerskega bralnega krožka SICP #+AUTHOR: Jurij #+OPTIONS: toc:nil num:nil author tex:dvisvgm * Zanimivi izseki ** str. 9 #+BEGIN_QUOTE Every reader should ask himself periodically "Toward what end, toward what end?" — but do not ask it too often lest you pass up the fun of programming for the constipation of bittersweet philosophy. #+END_QUOTE #+begin_quote Lisp is a survivor, having been in use for about a quarter of a century. #+end_quote ** str. 11 #+begin_quote It is better to have 100 functions operate on one data structure than to have 10 functions operate on 10 data structures. #+end_quote ** str. 18 #+begin_quote Thus, programs must be written for people to read, and only incidentally for machines to execute. #+end_quote ** str. 19 #+begin_quote Underlying our approach to this subject is our conviction that "computer science" is not a science and that its significance has little to do with computers. #+end_quote ** str. 27 #+begin_quote Finally, we would like to acknowledge the support of the organizations that have encouraged this work over the years, including support from Hewlett-Packard, made possible by Ira Goldstein and Joel Birnbaum, and support from DARPA, made possible by Bob Kahn. #+end_quote Bob Kahn je mdr. soavtor protokolov TCP in IP, pionir omreževanja. V DARPA postal kasneje direktor IPTO (Informational Processing Techniques Office), kjer je ustanovil milijardo-dolarski projekt Strategic Copmuting Initiative, največjo investicijo ameriške federalne vlade v računalništvo ever ('83 do '93) - razvijali so proizvodnjo čipov in umetne inteligence. Ustrašili so se japoncev, podobno kot v 50ih sovjetov. Po DARPA ustanovil CNRI (corporation for national research initiatives), neprofitno organizacijo kjer je delal tudi guido van rossum (avtor pythona). Tam so izdali python verzije 1.3 do 1.6 ter GNU mailman. Preko očeta v sorodu s fizikom Hermanom Kahnom, ki je napisal knjigo o tem kako bi amerika lahko zmagala nuklearno vojno in postal inspiracija za dr. Strangelove-a v znanem Kubrickovem filmu. Ustanovil je Hudson institut, konzervativni think tank ki je začel pri premišljevanju hladnovojnih scenarijev in se razširil na polja ekonomije, zdravstva, šolstva in gemblanja. Delal je tudi v RAND korporaciji, močnem hladnovojnem inštitutu, vpletenem v vietnamsko vojno, iraško vojno, danes pa kuri "AI apokaliptični" scenarij. ** str. 77 Stoy 1977 * Vaje ** 1.1 Kaj vrnejo izrazi? #+begin_src scheme (+ 5 3 4) #+end_src 10 #+begin_src scheme (- 9 1) #+end_src 8 #+begin_src scheme (/ 6 2) #+end_src 3 #+begin_src scheme (+ (* 2 4) (- 4 6)) #+end_src 6 #+begin_src scheme (define a 3) #+end_src #nil #+begin_src scheme (define b (+ a 1)) #+end_src #nil #+begin_src scheme (+ a b (* a b)) #+end_src 19 #+begin_src scheme (= a b) #+end_src #f #+begin_src scheme (if (and (> b a) (< b (* a b))) b a) #+end_src 4 #+begin_src scheme (cond ((= a 4) 6) ((= b 4) (+ 6 7 a)) (else 25)) #+end_src 16 #+begin_src scheme (+ 2 (if (> b a) b a)) #+end_src 6 #+begin_src scheme (* (cond ((> a b) a) ((< a b) b) (else -1)) (+ a 1)) #+end_src 16 ** 1.2 Pretvori izraz v prefix obliko \begin{equation} \frac{5+4+(2-(3-(6+\frac{4}{5}))) }{3(6-2)(2-7)} \end{equation} #+begin_src scheme :exports both (/ (+ 5 4 (- 2 (- 3 (+ 6 4/5)))) (* 3 (- 6 2) (- 2 7))) #+end_src #+RESULTS: : -43/180 ** 1.3 določi postopek, ki prejme 3 števila kot argumente in vrne vsoto kvadratov večjih dveh #+begin_src scheme :exports both :results table (define (vsota-vecjih-kvadratov a b c) (cond ((<= a b c) (+ (* b b) (* c c))) ((<= b a c) (+ (* a a) (* c c))) (else (+ (* b b) (* a a))))) ;; ^ NAROBE! <= primerja vse tri stevilke, ne prvo z drugima dvema oz. ostalimi (define (+kvadrat a b) (+ (* a a) (* b b))) (define (vsota-vecjih-kvadratov2 a b c) (if (>= a b) (if (>= b c) (+kvadrat a b) (+kvadrat a c)) (if (>= a c) (+kvadrat a b) (+kvadrat b c)))) (list '("Pričakovano" 85 41 164 89) (list "Funkcija1" (vsota-vecjih-kvadratov 6 1 7) (vsota-vecjih-kvadratov 3 4 5) (vsota-vecjih-kvadratov 8 10 2) (vsota-vecjih-kvadratov 3 8 5)) (list "Funkcija2" (vsota-vecjih-kvadratov2 6 1 7) (vsota-vecjih-kvadratov2 3 4 5) (vsota-vecjih-kvadratov2 8 10 2) (vsota-vecjih-kvadratov2 3 8 5))) #+end_src #+RESULTS: | Pricakovano | 85 | 41 | 164 | 89 | | Funkcija1 | 85 | 41 | 164 | 73 | | Funkcija2 | 85 | 41 | 164 | 89 | ** 1.4 Opis procedure #+begin_src scheme (define (a-plus-abs-b a b) ((if (> b 0) + -) a b)) #+end_src Izraz ~if~ vrne funkcijo ~+~ ali ~-~ , glede na to, ali je argument ~b~ večji ali manjši od 0. Če je ~b~ manjši od 0, ga odšteje od ~a~, sicer pa ga prišeje. Zato je rezultat funkcije ekvivalenten vsoti ~a~ in absolutnega ~b~. ** 1.5 Aplikativni red in normalni red evalvacije #+begin_src scheme (define (p) (p)) (define (test x y) (if (= x 0) 0 y)) ;; Evalvira: (test 0 (p)) #+end_src Če interpreter deluje po aplikativnem zaporedju, bo najprej evalviral argumente. Ker je drugi argument postopek, ki v neskončnost vrača vrednost klica samega sebe, se bo program zaciklal oz. zmrznil. Če pa interpreter deluje po normalnem zaporedju, bo pa začel izvajat postopek pred evalvacijo argumentov, le-te pa šele ko jih potrebuje. Tako bo, ~if~ stavek prepoznal ekvivalenco ~x~ in ~0~ ter vrnil ~0~. Klic takšne funkcije torej preveri ali interpreter deluje po aplikativnem ali normalnem zaporedju. Guile scheme deluje po aplikativnem redu (in se zacikla). Normalni red pa lahko "simuliramo", če proceduro definiramo kot macro, z ~define-case~. Klic macroja se ne zacikla. #+begin_src scheme :exports both (define-macro (test-m x y) (if (= x 0) 0 y)) (test-m 0 (p)) #+end_src #+RESULTS: : 0 ** 1.6 Novi if Imamo nov ~if~, ~new-if~. #+begin_src scheme (define (new-if predicate then-clause else-clause) (cond (predicate then-clause) (else else-clause))) #+end_src Kaj se zgodi, če ga uporabimo za računanje kvadratnih korenov? #+begin_src scheme (define (sqrt-iter guess x) (new-if (good-enough? guess x) guess (sqrt-iter (improve guess x) x))) #+end_src Navaden ~if~ je v bistvu makro in deluje po normalnem zaporedju. Ker je ~new-if~ definiran kot procedura, mora zaradi aplikativnega zaporedja najprej evalvirati argumente. Zato se zacikla oz. zamrzne. ** 1.7 good-enough? ni dovolj dober? #+begin_src scheme (define (average x y) (/ (+ x y) 2)) (define (improve guess x) (average guess (/ x guess))) (define (good-enough? guess x) (< (abs (- (square guess) x)) 0.001)) (define (sqrt-iter guess x) (if (good-enough? guess x) guess (sqrt-iter (improve guess x) x))) (define (sqrt x) (sqrt-iter 1.0 x)) #+end_src Pri premajhnih številih ~good-enough?~ prehitro "odneha" in dobimo slab približek, pri prevelikih številih pa "predolgo vztraja", saj ne potrebujemo tako natančnega približka. Boljša rešitev s precej elegance je, recimo, primerjava s promilom ~x~ namesto 0.001. #+begin_src scheme (define (good-enough? guess x) (< (abs (- (square guess) x)) (* 0.001 x))) #+end_src ** 1.8 kubični koren Formula za izboljšanje približka ~y~ kubičnemu korenu ~x~ je \begin{equation} \frac{x/y^{2}+2y}{3} \end{equation} Postopek: TODO ** 1.10 Ackermannov postopek Sledeči postopek je Ackermannov: #+begin_src scheme (define (A x y) (cond ((= y 0) 0) ((= x 0) (* 2 y)) ((= y 1) 2) (else (A (- x 1) (A x (- y 1)))))) #+end_src Kakšni so rezultati sledečih izrazov? - ~(A 1 10)~ #+begin_src scheme (A 1 10) (A 0 (A 1 9)) (A 0 (A 0 (A 1 8))) (A 0 (A 0 (A 0 (A 1 7)))) (A 0 (A 0 (A 0 (A 0 (A 1 6))))) (A 0 (A 0 (A 0 (A 0 (A 0 (A 1 5)))))) (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 1 4))))))) (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 1 3)))))))) (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 1 2))))))))) (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 1 1)))))))))) (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 2))))))))) (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 4)))))))) (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 8))))))) (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 16)))))) (A 0 (A 0 (A 0 (A 0 (A 0 32))))) (A 0 (A 0 (A 0 (A 0 64)))) (A 0 (A 0 (A 0 128))) (A 0 (A 0 256)) (A 0 512) 1024 #+end_src - ~(A 2 4)~ #+begin_src scheme (A 2 4) (A 1 (A 2 3)) (A 1 (A 1 (A 2 2))) (A 1 (A 1 (A 1 (A 2 1))) (A 1 (A 1 (A 1 2))) (A 1 (A 1 (A 1 2))) (A 1 (A 1 (A 0 (A 1 1))) (A 1 (A 1 (A 0 2))) (A 1 (A 1 (A 0 2))) (A 1 (A 1 4)) (A 1 (A 0 (A 1 3))) (A 1 (A 0 (A 0 (A 1 2)))) (A 1 (A 0 (A 0 (A 0 (A 1 1))))) (A 1 (A 0 (A 0 (A 0 2)))) (A 1 (A 0 (A 0 4))) (A 1 (A 0 8)) (A 1 16) (A 0 (A 1 15)) (A 0 (A 0 (A 1 14)) ... (A 0 (A 0 (A 1 14)) (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 1)))))))))))))))) (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 2))))))))))))))) (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 4)))))))))))))) (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 8))))))))))))) (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 16)))))))))))) (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 32))))))))))) (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 64)))))))))) (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 128))))))))) (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 256)))))))) (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 512))))))) (A 0 (A 0 (A 0 (A 0 (A 0 (A 0 1024)))))) (A 0 (A 0 (A 0 (A 0 (A 0 2048))))) (A 0 (A 0 (A 0 (A 0 4096)))) (A 0 (A 0 (A 0 8192))) (A 0 (A 0 16384)) (A 0 32768) 65536 #+end_src - ~(A 3 3)~ #+begin_src scheme (A 3 3) (A 2 (A 3 2)) (A 2 (A 2 (A 3 1))) (A 2 (A 2 2)) (A 2 (A 1 (A 2 1))) (A 2 (A 1 2)) (A 2 (A 0 (A 1 1))) (A 2 (A 0 2)) (A 2 4) (A 1 (A 2 3)) (A 1 (A 1 (A 2 2))) (A 1 (A 1 (A 1 (A 2 1)))) (A 1 (A 1 (A 1 2))) (A 1 (A 1 (A 0 (A 1 1)))) (A 1 (A 1 (A 0 2))) (A 1 (A 1 4)) (A 1 (A 0 (A 1 3))) (A 1 (A 0 (A 0 (A 1 2)))) (A 1 (A 0 (A 0 (A 0 (A 1 1))))) (A 1 (A 0 (A 0 (A 0 2)))) (A 1 (A 0 (A 0 4))) (A 1 (A 0 8)) (A 1 16) 65536 #+end_src Če imamo še sledeče postopke: #+begin_src scheme (define (f n) (A 0 n)) (define (g n) (A 1 n)) (define (h n ) (A 2 n)) (define (k n) (* 5 n n)) #+end_src Jedrnato opredeli matematične funkcije izračuna postopkov ~f~, ~g~ in ~h~. ~k~, recimo izračuna ~5n^2~. #+begin_quote ~f~: 2n #+end_quote #+begin_quote ~g~: 2^n #+end_quote #+begin_quote ~h~: 2^{2^n} #+end_quote