19 days after starting, I’m done with Chapter 1!
Exercise 1.36 in this chapter was pretty interesting - we have to find a solution to x^x = 1000 by finding a fixed point of x -> log(1000)/log(x). I modified fixed-point using the https://github.com/weavejester/hashp
#p data reader to print out intermediate values, which makes println-style debugging a lot better.
(def tolerance 1E-5) (defn fixed-point [f first-guess] (let [close-enough? (fn [v1 v2] (< (Math/abs ^float (- v1 v2)) tolerance)) try* (fn [guess steps] (let [next #p (f guess)] (if (close-enough? guess next) (do (print (str "took " steps " steps, guess=" guess)) next) (recur next (inc steps)))))] (try* first-guess 0))) (defn undampened-x-pow-x [x] (/ (Math/log 1000) (Math/log ^float x))) (float (fixed-point undampened-x-pow-x 2)) ;; took 28 steps ;; 4.5555634 (float (fixed-point #(/ (+ (undampened-x-pow-x %) %) 2) 2)) ;; took 7 steps ;; 4.5555468 ;; no oscillation at the start; nice!
The rest of the exercises really served to hammer home the point that it’s easy and fun to build higher-level abstractions using first-class functions and some thinking. Just contrast the initial and final implementations of sqrt below:
;; initial version (defn sqrt-iter [guess x] (letfn [(good-enough? [guess x] (< (Math/abs ^float (- (* guess guess) x)) 0.001)) (average [x y] (/ (+ x y) 2)) (improve [guess x] (average guess (/ x guess)))] (if (good-enough? guess x) guess (re cur (improve guess x) x)))) ;; final version (defn sqrt-final [num] (let [guesser (iterative-improver (fn [a b] (< (Math/abs ^float (- a b)) 0.001)) (fn [guess] (sicp.util/average guess (/ num guess))))] (guesser 1))) ;; Where iterative-improver is from Exercise 1.46: (defn iterative-improver [test-fn improve-fn] (fn [guess] (let [improved-guess (improve-fn guess) good-enough? (test-fn guess improved-guess)] (if good-enough? improved-guess (recur improved-guess)))))