sicp

0.1.0


SICP in Clojure

These are my solutions to the exercises from Structure and Interpretation of Computer Programs

All feedback welcome especially if you see something I could have made clearer.

I hope you find this useful and have as much fun working through these as I did

dependencies

org.clojure/clojure
1.4.0
org.clojure/tools.trace
0.7.3
seesaw
1.4.2



(this space intentionally left almost blank)

namespaces

 
(ns sicp.chpt1.ex1-01)

The Clojure REPL works like any other Lisp REPL

When using def, the actual output would be the fully qualified var name for example #'user/a, instead of just 'a

(comment 10
         12
         8
         3
         6
         'a
         'b
         19
         false
         4
         16
         6
         16)
 
(ns sicp.chpt1.ex1-02)

Using prefix notation has 2 advantages

First, your operators aren't treated differently from other functions and so you have consistency

Second, precedence is obvious

(/ (+ 5
      4
      (- 2
         (- 3
            (+ 6
               (/ 4 5)))))
   (* 3
      (- 6 2)
      (- 2 7)))
 
(ns sicp.chpt1.ex1-03)
(defn sqr
  [x]
  (* x x))
(defn sum-of-squares
  [x y]
  (+ (sqr x) (+ sqr y)))

Each conditional step adds more information until we can make a decision

  1. \(x < y,z\)
  2. \(z < x < y\)
  3. \(y < x < z\)
  4. \(y < z < x\)
  5. \(z < y < x\)
(defn sum-of-greater-squares
  [x y z]
  (cond
   (and (< x y) (< x z))
   (sum-of-squares y z)
   (< x y)
   (sum-of-squares x y)
   (< x z)
   (sum-of-squares x z)
   (< y z)
   (sum-of-squares z x)
   :else
   (sum-of-squares y x)))
 
(ns sicp.chpt1.ex1-04)

if \(b>0\) then the conditional resolves to + returning (+ a b)

if \(b \leq 0\) then the conditional resolves to - returning (- a b)

(defn a-plus-abs-b
  [a b]
  ((if (> b 0) + -) a b))
 
(ns sicp.chpt1.ex1-05)

In applicative order, the arguments are evaluated before being passed into the function. The argument y resolves to (p) which causes an infinite loop or a stack overflow

Normal order, resolves x since its used first and terminates, returning 0 without ever resolving y

 
(ns sicp.chpt1.ex1-06)

(sqrt-iter (improve guess x) x) is evaluated whether (good-enough? guess x) was true or not, this would result in an infinite call to sqrt-iter

This is only in the case of applicative order evaluation

 
(ns sicp.chpt1.ex1-07
  (:use [sicp.chpt1.ex1-03 :only [sqr]]))

good-enough? is set to restrict the number of steps in evaluating an answer

Using a delta (even a small one) to check good-enough? works ok for numbers in a small range but very large numbers take a long time to converge (with much higher precision) while very small numbers take a small time to converge (with loss of precision).

The suggested implementation of good-enough? is much better at limiting to an equal precision for both very large and very small numbers

(defn abs
  [x]
  (if (> x 0) x (- x)))
(defn good-enough?
  [guess x]
  (< (abs (- (sqr guess) x))
     1/1000))
(defn improve
  [guess x]
  (/ (+ (/ x guess)
        guess)
     2))
(defn sqrt-iter
  [guess x]
  (if (good-enough? guess x)
    guess
    (recur (improve guess x) x)))
(defn sqrt
  [x]
  (sqrt-iter 1.0 x))
(defn good-enough2?
  [last-guess guess]
  (< (/ (abs (- guess last-guess))
        last-guess)
     1/10000000))
(defn sqrt-iter2
  [guess x]
  (if (good-enough2? guess (improve guess x))
    guess
    (recur (improve guess x) x)))
(defn sqrt2
  [x]
  (sqrt-iter2 1.0 x))
 
(ns sicp.chpt1.ex1-08
  (:use [sicp.chpt1.ex1-03 :only [sqr]]
        [sicp.chpt1.ex1-07 :only [abs]]))

Almost exactly like the sqrt implementation, the major change being in the implementation of improve

(defn good-enough?
  [last-guess guess]
  (< (/ (abs (- guess last-guess))
        last-guess)
     1/10000000))
(defn improve
  [guess x]
  (/ (+ (/ x (sqr guess))
        (* 2 guess))
     3))
(defn cbrt-iter
  [guess x]
  (if (good-enough? guess (improve guess x))
    guess
    (recur (improve guess x) x)))
(defn cbrt
  [x]
  (cbrt-iter 1.0 x))
 
(ns sicp.chpt1.ex1-09
  (:refer-clojure :exclude [+]))

Expanding both implementations

This version is recursive

(+ 4 5)
(inc (+ 3 5))
(inc (inc (+ 2 5)))
(inc (inc (inc (+ 1 5))))
(inc (inc (inc (inc (+ 0 5)))))
(inc (inc (inc (inc 5))))
(inc (inc (inc 6)))
(inc (inc 7))
(inc 8)
9
(defn +
  [a b]
  (if (= a 0)
    b
    (inc (+ (dec a) b))))

This version is iterative

(+ 4 5)
(+ 3 6)
(+ 2 7)
(+ 1 8)
(+ 0 9)
9
(defn +
  [a b]
  (if (= a 0)
    b
    (recur (dec a) (inc b))))
 
(ns sicp.chpt1.ex1-10)

The Ackermann function grows very quickly for larger values of x

(defn A
  [x y]
  (cond (= y 0)
        0
        (= x 0)
        (* 2 y)
        (= y 1)
        2
        :else
        (recur (- x 1)
               (A x (- y 1)))))
(comment (A 1 10))
=> 1024
(comment (A 2 4))
=> 65536
(comment (A 3 3))
=> 65536
(defn f [n] (A 0 n))

\(A(0,n) = 2n\)

(defn g [n] (A 1 n))

\(A(1,n) = 2^n\)

(defn h [n] (A 2 n))

\(A(2,n) = 2^{2^{2^{2...}}} n\) times

\(A(2,n)\) is called tetration, this is the next hyper operator after exponentiation

 
(ns sicp.chpt1.ex1-11)

Iterative functions store state explicitly while recursive ones use the function stack

(defn f-recursive
  [n]
  (if (< n 3)
    n
    (+ (f-recursive (- n 1))
       (* 2 (f-recursive (- n 2)))
       (* 3 (f-recursive (- n 3))))))
(defn f-iterative
  [n]
  (loop [a 0 b 1 c 2 i n]
    (if (zero? i)
      a
      (recur b c (+ c (* 2 b) (* 3 a)) (dec i)))))
 
(ns sicp.chpt1.ex1-12)

The recursion can be expressed as

  • \(pascal(row,1) = 1\)
  • \(pascal(row,column) = 1, row = column\)
  • \(pascal(row,column) = pascal(row-1,column-1) + pascal(row-1,column)\)

where row is the row number and column the column number

Returns the entry in Pascal's triangle given by the coordinates (row, column)

(defn pascal
  [row column]
  (if (or (= 1 column)
          (= row column))
    1
    (+ (pascal (dec row) (dec column)) (pascal (dec row) column))))
(comment
  (for [x (range 1 5) y (range 1 (inc x))]
    (pascal x y)))
=> (1 1 1 1 2 1 1 3 3 1)
 
(ns sicp.chpt1.ex1-13)

The fibonacci recursion can be expressed as

  • \(fib(1) = 1\)
  • \(fib(2) = 2\)
  • \(fib(n) = fib(n-1) + fib(n-2)\)

To prove:

\(fib(n) = \frac{\phi^n - \psi^n}{\sqrt{5}}\)

where

  • \(\phi = \frac{1 + \sqrt{5}}{2}\)
  • \(\psi = \frac{1 - \sqrt{5}}{2}\)

Base conditions:

  • \(fib(1) = 1, true\)
  • \(fib(2) = 2, true\)

Assume \(fib(k-1), fib(k)\) is true

To prove

\(fib(k+1) = fib(k) + fib(k-1)\)

Substituting

\(fib(k+1) = \frac{\phi^k - \psi^k}{\sqrt{5}} + \frac{\phi^(k-1) - \psi^(k-1)}{\sqrt{5}}\)

Rearranging

\(fib(k+1) = \frac{\phi^k(1+\frac{1}{\phi}) - \psi^k(1+\frac{1}{\psi})}{\sqrt{5}}\)

This resolves to

\(fib(k+1) = \frac{\phi^(k+1) - \psi^(k+1)}{\sqrt{5}}\)

if and only if

  • \(1 + \frac{1}{\phi} = \phi\)
  • \(1 + \frac{1}{\psi} = \psi\)

Which can be represented as the solution to the equation

\(x^2 - x - 1 = 0\)

This equation has the roots

  • \(\frac{1 + \sqrt{5}}{2}\)
  • \(\frac{1 - \sqrt{5}}{2}\)

The different possible values which \(\phi\) and \(\psi\) can take

\(\phi = \frac{1 - \sqrt{5}}{2}, \psi = \frac{1 - \sqrt{5}}{2}\)

Invalid, \(fib(n) = 0\), \(\forall\) \(n>0\)

\(\phi = \frac{1 + \sqrt{5}}{2}, \psi = \frac{1 + \sqrt{5}}{2}\)

Invalid, \(fib(n) = 0\), \(\forall\) \(n>0\)

\(\phi = \frac{1 - \sqrt{5}}{2}, \psi = \frac{1 + \sqrt{5}}{2}\)

Invalid, \(fib(n) < 0\), \(\forall\) \(n>0\)

\(\phi = \frac{1 + \sqrt{5}}{2}, \psi = \frac{1 - \sqrt{5}}{2}\)

Valid, \(\forall\) \(n>0\)

For larger values of \(n\), \(\psi\) becomes negligible

Therefore \(fib(n)\) is approximately \(\frac{\phi^n}{\sqrt{5}}\)

 
(ns sicp.chpt1.ex1-14
  (:require [clojure.tools.trace :as t]))

Each call to cc results in 2 more calls to cc, also amount decrements by 1 when kinds of coins is 1. Therefore, the upper bound time complexity is \(O(2^{amount})\).

Since the maximum recursive depth is when kinds-of-coins is 1. the space complexity is \(O(amount)\)

(defn first-denomination
  [kinds-of-coins]
  (cond (= kinds-of-coins 1) 1
        (= kinds-of-coins 2) 5
        (= kinds-of-coins 3) 10
        (= kinds-of-coins 4) 25
        (= kinds-of-coins 5) 50))
(t/deftrace cc
  [amount kinds-of-coins]
  (cond (= amount 0) 1
        (or (< amount 0) (= kinds-of-coins 0)) 0
        :else
        (+ (cc amount
               (- kinds-of-coins 1))
           (cc (- amount
                  (first-denomination kinds-of-coins))
               kinds-of-coins))))
(defn count-change
  [amount]
  (cc amount 5))

Using clojure.tools.trace to trace the call path of cc

(count-change 11)
(cc 11 5)
| (cc 11 4)
| | (cc 11 3)
| | | (cc 11 2)
| | | | (cc 11 1)
| | | | | (cc 11 0)
| | | | | => 0
| | | | | (cc 10 1)
| | | | | | (cc 10 0)
| | | | | | => 0
| | | | | | (cc 9 1)
| | | | | | | (cc 9 0)
| | | | | | | => 0
| | | | | | | (cc 8 1)
| | | | | | | | (cc 8 0)
| | | | | | | | => 0
| | | | | | | | (cc 7 1)
| | | | | | | | | (cc 7 0)
| | | | | | | | | => 0
| | | | | | | | | (cc 6 1)
| | | | | | | | | | (cc 6 0)
| | | | | | | | | | => 0
| | | | | | | | | | (cc 5 1)
| | | | | | | | | | | (cc 5 0)
| | | | | | | | | | | => 0
| | | | | | | | | | | (cc 4 1)
| | | | | | | | | | | | (cc 4 0)
| | | | | | | | | | | | => 0
| | | | | | | | | | | | (cc 3 1)
| | | | | | | | | | | | | (cc 3 0)
| | | | | | | | | | | | | => 0
| | | | | | | | | | | | | (cc 2 1)
| | | | | | | | | | | | | | (cc 2 0)
| | | | | | | | | | | | | | => 0
| | | | | | | | | | | | | | (cc 1 1)
| | | | | | | | | | | | | | | (cc 1 0)
| | | | | | | | | | | | | | | => 0
| | | | | | | | | | | | | | | (cc 0 1)
| | | | | | | | | | | | | | | => 1
| | | | | | | | | | | | | | => 1
| | | | | | | | | | | | | => 1
| | | | | | | | | | | | => 1
| | | | | | | | | | | => 1
| | | | | | | | | | => 1
| | | | | | | | | => 1
| | | | | | | | => 1
| | | | | | | => 1
| | | | | | => 1
| | | | | => 1
| | | | => 1
| | | | (cc 6 2)
| | | | | (cc 6 1)
| | | | | | (cc 6 0)
| | | | | | => 0
| | | | | | (cc 5 1)
| | | | | | | (cc 5 0)
| | | | | | | => 0
| | | | | | | (cc 4 1)
| | | | | | | | (cc 4 0)
| | | | | | | | => 0
| | | | | | | | (cc 3 1)
| | | | | | | | | (cc 3 0)
| | | | | | | | | => 0
| | | | | | | | | (cc 2 1)
| | | | | | | | | | (cc 2 0)
| | | | | | | | | | => 0
| | | | | | | | | | (cc 1 1)
| | | | | | | | | | | (cc 1 0)
| | | | | | | | | | | => 0
| | | | | | | | | | | (cc 0 1)
| | | | | | | | | | | => 1
| | | | | | | | | | => 1
| | | | | | | | | => 1
| | | | | | | | => 1
| | | | | | | => 1
| | | | | | => 1
| | | | | => 1
| | | | | (cc 1 2)
| | | | | | (cc 1 1)
| | | | | | | (cc 1 0)
| | | | | | | => 0
| | | | | | | (cc 0 1)
| | | | | | | => 1
| | | | | | => 1
| | | | | | (cc -4 2)
| | | | | | => 0
| | | | | => 1
| | | | => 2
| | | => 3
| | | (cc 1 3)
| | | | (cc 1 2)
| | | | | (cc 1 1)
| | | | | | (cc 1 0)
| | | | | | => 0
| | | | | | (cc 0 1)
| | | | | | => 1
| | | | | => 1
| | | | | (cc -4 2)
| | | | | => 0
| | | | => 1
| | | | (cc -9 3)
| | | | => 0
| | | => 1
| | => 4
| | (cc -14 4)
| | => 0
| => 4
| (cc -39 5)
| => 0
=> 4
 
(ns sicp.chpt1.ex1-15)

When (sine 12.15) is called, p is applied 5 times

(sine 12.15)
(p (sine 4.05))
(p (p (sine 1.35)))
(p (p (p (sine 0.45))))
(p (p (p (p (sine 0.15)))))
(p (p (p (p (p (sine 0.05))))))

Assuming p is \(O(1)\), the time and space complexity are directly proportional to the number of times p is applied

(sine a) will make at most \(n\) calls to p where \(n\) satisfies the equation

\(\frac{a}{3^n} \leq 0.1\)

Solving for \(n\)

\(\log _3 a \leq n\)

Therefore the \(O(sine)\) is approximately \(\log _3 a\), with a as input

 
(ns sicp.chpt1.ex1-16)

Keeping \(b^na\) constant in every iteration

(defn fast-expt
  ([b n]
     (fast-expt b n 1))
  ([b n a]
     (cond (zero? n)
           a
           (even? n)
           (recur (* b b) (/ n 2) a)
           :else
           (recur b (dec n) (* a b)))))
 
(ns sicp.chpt1.ex1-17
  (:refer-clojure :exclude [double]))

For readability, double and halve

(def double #(bit-shift-left % 1))
(def halve #(bit-shift-right % 1))

Recursive version of fast-*

(defn fast-*
  [a b]
  (cond (zero? b)
        0
        (even? b)
        (recur (double a) (halve b))
        :else
        (+ a (fast-* a (dec b)))))
 
(ns sicp.chpt1.ex1-18
  (:refer-clojure :exclude [double])
  (:use [sicp.chpt1.ex1-17 :only [double halve]]))

Iterative version of fast-*

Keeping \(ba+n\) constant in every iteration

(defn fast-*
  ([a b]
     (fast-* a b 0))
  ([a b n]
     (cond (zero? b)
           n
           (even? b)
           (recur (double a) (halve b) n)
           :else
           (recur a (dec b) (+ a n)))))
 
(ns sicp.chpt1.ex1-19)

The transformation \(T _{pq}(p,q)\) is defined as

  • \(a \leftarrow bq + aq + ap\)
  • \(b \leftarrow bp + aq\)

Applying \(T _{pq}\) twice,

\(T _{pq}(T _{pq}(a,b))\)

which expands to

\(T _{pq}(bq + aq + ap, bp + aq)\)

finally giving us the transforms

  • \(a \leftarrow bpq +aq^2 + bq^2 + aq^2 + apq + bpq + apq + ap^2\)
  • \(b \leftarrow bp^2 + apq + bq^2 + aq^2 + apq\)

Grouping to reveal \(T _{pq}\) form, we get the new transforms

  • \(a \leftarrow b(2pq + q^2) + a(2pq + q^2) + a(p^2 + q^2)\)
  • \(b \leftarrow b(p^2 + q^2) + a(2pq + q^2)\)

So the new \(T _{p'q'}\), which is the same as applying \(T _{pq}\) twice is

  • \(p' \leftarrow p^2 + q^2\)
  • \(q' \leftarrow 2pq + q^2\)

Filling in the gaps, here's fib with \(O(log _2 n)\)

(defn fib
  ([n]
     (fib 1 0 0 1 n))
  ([a b p q n]
     (cond (zero? n)
           b
           (even? n)
           (recur a
                  b
                  (+ (* p p) (* q q))
                  (+ (* 2 p q) (* q q))
                  (/ n 2))
           :else
           (recur (+ (* b q) (* a q) (* a p))
                  (+ (* b p) (* a q))
                  p
                  q
                  (dec n)))))
 
(ns sicp.chpt1.ex1-20)
(defn gcd
  [a b]
  (if (zero? a)
    b
    (recur (rem b a) a)))

Normal Order

Evaluating gcd with normal order (gcd 206 40)

each call to (= b 0) evaluates b

initial number of calls to rem is 0

 (gcd 40
      (rem 206 40))

+1 call to rem

 (gcd (rem 206 40)
      (rem 40 (rem 206 40)))

+2 calls to rem

 (gcd (rem 40 (rem 206 40))
      (rem (rem 206 40) (rem 40 (rem 206 40))))

+4 calls to rem

 (gcd (rem (rem 206 40) (rem 40 (rem 206 40)))
      (rem (rem 40 (rem 206 40)) (rem (rem 206 40) (rem 40 (rem 206 40)))))

+7 calls to rem

Finally +4 calls to rem when returning a

Total number of calls to rem with normal order

\(0 + 1 + 2 + 4 + 7 + 4 \rightarrow 18\)

Applicative Order

Evaluating gcd with applicative order (gcd 206 40)

Each call to gcd evaluates both arguments immediately

initial number of calls to rem is 0

 (gcd 40
      6)

+1 call to rem

 (gcd 6
      4)

+1 call to rem

 (gcd 4
      2)

+1 call to rem

 (gcd 2
      0)

Finally a is already evaluated so no additional calls to rem required

Total number of calls to rem with applicative order

\(0 + 1 + 1 + 1 + 1 \rightarrow 4\)

 
(ns sicp.chpt1.ex1-21)
(defn divides?
  [a b]
  (zero? (rem a b)))
(defn find-smallest-divisor
  ([n]
     (find-smallest-divisor n 2))
  ([n test-divisor]
     (cond (> (* test-divisor test-divisor) n)
           n
           (divides? n test-divisor)
           test-divisor
           :else
           (recur n (inc test-divisor)))))
(find-smallest-divisor 199)
=> 199

(find-smallest-divisor 1999)
=> 1999

(find-smallest-divisor 19999)
=> 7
 
(ns sicp.chpt1.ex1-22
  (:use [sicp.chpt1.ex1-21 :only [divides?
                                  find-smallest-divisor]]))
(defn prime?
  [n]
  (= n (find-smallest-divisor n)))
(defn timed-prime-test
  [n & {:keys [prime-fn] :or {prime-fn prime?}}]
  (let [start (. System (nanoTime))
        is-prime (prime-fn n)]
    [is-prime (/ (double (- (. System (nanoTime)) start)) 1000000.0)]))
(defn find-timed-primes-between
  [a b & {:keys [timed-prime-test-fn]
          :or {timed-prime-test-fn timed-prime-test}}]
  (letfn [(mapper [n]
            (let [[is-prime time-taken] (timed-prime-test-fn n)]
              [is-prime n time-taken]))]
    (for [[is-prime n time-taken]
          (map mapper (range (if (odd? a) a (inc a))
                             b
                             2))
          :when is-prime]
      [n time-taken])))

Each test was run 100,000 times before the time was recorded to account for HotSpot optimization

(take 3 (find-timed-primes-between 1000 1000000000))

  • 1009, 0.002619 msec
  • 1013, 0.002167 msec
  • 1019, 0.002177 msec

average time taken, 0.00232

(take 3 (find-timed-primes-between 10000 1000000000))

  • 10007, 0.006244 msec
  • 10009, 0.005459 msec
  • 10037, 0.005579 msec

average time taken, 0.00576

(take 3 (find-timed-primes-between 100000 1000000000))

  • 100003, 0.018717 msec
  • 100019, 0.017477 msec
  • 100043, 0.016873 msec

average time taken, 0.01769

(take 3 (find-timed-primes-between 1000000 1000000000))

  • 1000003, 0.05348 msec
  • 1000033, 0.053039 msec
  • 1000037, 0.052869 msec

average time taken, 0.05313

Taking the average ratios of each order of magnitude increase

\(\frac{\frac{0.00576}{0.00232} + \frac{0.01769}{0.00576} + \frac{0.05313}{0.01769}}{3} \rightarrow 2.85244\)

Which is roughly equal to \(\sqrt{10}\)

This supports the \(\sqrt{n}\) prediction and shows that runtime is proportional to number of steps

 
(ns sicp.chpt1.ex1-23
  (:use [sicp.chpt1.ex1-21 :only [divides?]])
  (:require [sicp.chpt1.ex1-22 :as c1e22]))
(defn find-smallest-divisor
  ([n]
     (if (divides? n 2)
       2
       (find-smallest-divisor n 3)))
  ([n test-divisor]
     (cond (> (* test-divisor test-divisor) n)
           n
           (divides? n test-divisor)
           test-divisor
           :else
           (recur n (inc (inc test-divisor))))))
(defn prime?
  [n]
  (= n (find-smallest-divisor n)))
(def timed-prime-test
  #(c1e22/timed-prime-test % :prime-fn prime?))
(def find-timed-primes-between
  #(c1e22/find-timed-primes-between %1 %2 :timed-prime-test-fn timed-prime-test))

Each test was run 100,000 times before the time was recorded to account for HotSpot optimization

(take 3 (find-timed-primes-between 1000 1000000000))

  • 1009, 0.0207 msec
  • 1013, 0.01748 msec
  • 1019, 0.017589 msec

average time taken, 0.01859

(take 3 (find-timed-primes-between 10000 1000000000))

  • 10007, 0.053858 msec
  • 10009, 0.05361 msec
  • 10037, 0.053845 msec

average time taken, 0.05377

(take 3 (find-timed-primes-between 100000 1000000000))

  • 100003, 0.251168 msec
  • 100019, 0.239663 msec
  • 100043, 0.241405 msec

average time taken, 0.24408

(take 3 (find-timed-primes-between 1000000 1000000000))

  • 1000003, 0.526431 msec
  • 1000033, 0.525764 msec
  • 1000037, 0.515357 msec

average time taken, 0.52252

Taking the average ratios of each order of magnitude increase

\(\frac{\frac{0.05377}{0.01859} + \frac{0.24408}{0.05377} + \frac{0.52252}{0.24408}}{3} \rightarrow 3.19084\)

Which is roughly equal to \(\sqrt{10}\)

Ratio of without-even-integers to with-all-integers

for \(n > 1000\)

\(\frac{0.01859}{0.00232} \rightarrow 8.01293\)

for \(n > 10000\)

\(\frac{0.05377}{0.00576} \rightarrow 9.33506\)

for \( n > 100000\)

\(\frac{0.24408}{0.01769} \rightarrow 13.79763\)

for \(n > 1000000\)

\(\frac{0.52252}{0.05313} \rightarrow 9.83474\)

The average is 10.24509, which is an order of magnitude worse than the original version

I think this is because inc corresponds directly to a register increment which is a very fast operation compared to +. Even though the number of steps is halved, this difference shows by making this version an order of magnitude slower.

This is only for smaller numbers though, as the input gets larger and larger, the halving of the number of steps will dominate. Asymptotically, this algorithm should complete in half the time as the previous one

 
(ns sicp.chpt1.ex1-24
  (:use [sicp.chpt1.ex1-03 :only [sqr]])
  (:require [sicp.chpt1.ex1-22 :as c1e22]))
(defn expmod
  [base exp m]
  (cond (zero? exp)
        1
        (even? exp)
        (rem (sqr (expmod base (/ exp 2) m)) m)
        :else
        (rem (* base (expmod base (dec exp) m)) m)))
(defn fermat-test
  [n]
  (letfn [(try-it [a]
            (= (expmod a n n) a))]
    (try-it (+ 1 (int (rand n))))))
(defn prime?
  ([n]
     (prime? n (int (Math/log n))))
  ([n times]
     (if (zero? times)
       true
       (and (fermat-test n) (prime? n (dec times))))))
(def timed-prime-test
  #(c1e22/timed-prime-test % :prime-fn prime?))
(def find-timed-primes-between
  #(c1e22/find-timed-primes-between %1 %2 :timed-prime-test-fn timed-prime-test))

Each test was run 100,000 times before the time was recorded to account for HotSpot optimization

(take 3 (find-timed-primes-between 1000 1000000000))

  • 1009, 0.043298 msec
  • 1013, 0.044814 msec
  • 1019, 0.042874 msec

average time taken, 0.04366 msec

(take 3 (find-timed-primes-between 10000 1000000000))

  • 10007, 0.062862 msec
  • 10009, 0.064997 msec
  • 10037, 0.06907 msec

average time taken, 0.065654 msec

(take 3 (find-timed-primes-between 100000 1000000000))

  • 100003, 0.084971 msec
  • 100019, 0.083323 msec
  • 100043, 0.083917 msec

average time taken, 0.08407 msec

(take 3 (find-timed-primes-between 1000000 1000000000))

  • 1000003, 0.116445 msec
  • 1000033, 0.119691 msec
  • 1000037, 0.108891 msec

average time taken, 0.11501 msec

Since the growth is \(\log _2 n\), I would have expected the time to test primes near \(10^6\) was roughly \(\log _2 1000\) times greater that testing primes near \(10^3\), roughly 10 times larger

It was closer to 2.5 times larger

This discrepancy is probably due to the stochastic nature of this algorithm, which can terminate earlier if the primality test fails

 
(ns sicp.chpt1.ex1-25)

Alyssa's code would work for smaller numbers but even \(10^{100}\) would overflow in most languages and would need slower, arbitrary precision arithmetic in Clojure.

The expmod function works with primitive arithmetic operations, even on very large numbers.

 
(ns sicp.chpt1.ex1-26)

The original expmod function has a runtime of \(O(\log _2 n\) because it halves the number of remaining steps each time we find an even exp

by calling expmod twice, Louis loses this advantage, calculating half the number of steps twice, thus making \(O(expmod) \rightarrow n\)

 
(ns sicp.chpt1.ex1-27
  (:use [sicp.chpt1.ex1-22 :only [prime?]]
        [sicp.chpt1.ex1-24 :only [expmod]]))
(defn fermat-test
  [n a]
  (= (expmod a n n) a))
(defn fermat-prime?
  [n]
  (->> (range 2 n)
       (map (partial fermat-test n))
       (every? true?)))

known primes and non primes

(fermat-prime? 1009)
=> true

(prime? 1009)
=> true

(fermat-prime? 1011)
=> false

(prime? 1011)
=> false

(fermat-prime? 10007)
=> true

(prime? 10007)
=> true

(fermat-prime? 10011)
=> false

(prime? 10011)
=> false

Carmichael numbers

(fermat-prime? 561)
=> true

(prime? 561)
=> false

(fermat-prime? 1105)
=> true

(prime? 1105)
=> false

(fermat-prime? 1729)
=> true

(prime? 1729)
=> false

(fermat-prime? 2465)
=> true

(prime? 2465)
=> false

(fermat-prime? 2821)
=> true

(prime? 2821)
=> false

(fermat-prime? 6601)
=> true

(prime? 6601)
=> false

All the Carmichael numbers in the footnote fool the fermat-prime test

 
(ns sicp.chpt1.ex1-28
  (:use [sicp.chpt1.ex1-03 :only [sqr]]
        [sicp.chpt1.ex1-21 :only [divides?]]
        [sicp.chpt1.ex1-24 :only [expmod]]))

With lots of help from Miller Rabin primality test

Returns the tuple [s d] which is n in the form (2^s)*d

(defn factor-2s
  [n]
  (loop [t 0 d n]
    (if (divides? d 2)
      (recur (inc t) (/ d 2))
      [t d])))
(defn sqrmod
  [x m]
  (rem (sqr x) m))
(defn miller-rabin-test
  [n a]
  (let [[s d] (factor-2s (dec n))
        x (expmod a d n)]
    (if (or (= 1 x) (= (dec n) x))
      true
      (let [sqrs (take s (iterate #(sqrmod % n) x))]
        (cond (some #(= 1 %) sqrs)
              false
              (some #(= (dec n) %) sqrs)
              true
              :else
              false)))))
(defn miller-rabin-prime?
  [n]
  (->> (range 3 (- n 2) 2)
       (map (partial miller-rabin-test n))
       (every? true?)))

known primes and non primes

(miller-rabin-prime? 1009)
=> false (Not sure why the test fails here, 1009 is prime)
(miller-rabin-prime? 1011)
=> false
(miller-rabin-prime? 10007)
=> true
(miller-rabin-prime? 10011)
=> false
(miller-rabin-prime? 1000003)
=> true
(miller-rabin-prime? 1000007)
=> false

Carmichael numbers

(miller-rabin-prime? 561)
=> false
(miller-rabin-prime? 1105)
=> false
(miller-rabin-prime? 1729)
=> false
(miller-rabin-prime? 2465)
=> false
(miller-rabin-prime? 2821)
=> false
(miller-rabin-prime? 6601)
=> false

None of the Carmichael numbers in the footnote fool the miller-rabin-prime test

 
(ns sicp.chpt1.ex1-29)
(defn cube
  [x]
  (* x x x))
(defn integral
  [f a b dx]
  (* dx (reduce + (map f (range a b dx)))))
(defn simpson-integral
  [f a b n]
  (let [h (float (/ (- b a) n))]
    (* (/ h 3)
       (apply +
              (f a)
              (f b)
              (map *
                   (map f (range (+ a h) b h))
                   (cycle [4 2]))))))

Simpson's integral is more accurate than the basic integral from earlier, it approximates a better result in the same number of iterations

(integral cube 0 1 0.01)
=> 0.2450250000000004

(integral cube 0 1 0.001)
=> 0.24950025000000053

(simpson-integral cube 0 1 100)
=> 0.25666664394239663

(simpson-integral cube 0 1 1000)
=> 0.25000004744995713
 
(ns sicp.chpt1.ex1-30)
(defn sum
  [term a next b]
  (letfn [(iter [a result]
            (if (> a b)
              result
              (recur (next a) (+ (term a) result))))]
    (iter a 0)))
(sum identity 1 inc 10)
=> 55
 
(ns sicp.chpt1.ex1-31)
(defn product
  [term a next b]
  (letfn [(iter [a result]
            (if (> a b)
              result
              (recur (next a) (* (term a) result))))]
    (iter a 1)))
(defn factorial
  [n]
  (product identity 1 inc n))
(factorial 10)
=> 3628800
(defn pi
  [n]
  (letfn [(term [i]
            (if (odd? i)
              (/ (inc i) (+ i 2))
              (/ (+ i 2) (inc i))))]
    (* 4 (product term 1 inc n))))
(float (pi 1000))
=> 3.1431608
(defn product-rec
  [term a next b]
  (if (> a b)
    1
    (* (term a)
       (product-rec term (next a) next b))))
(defn factorial-rec
  [n]
  (product-rec identity 1 inc n))
(factorial-rec 10)
=> 3628800
 
(ns sicp.chpt1.ex1-32)
(defn accumulate
  [combiner null-value term a next b]
  (letfn [(iter [a result]
            (if (> a b)
              result
              (recur (next a) (combiner (term a) result))))]
    (iter a null-value)))
(defn sum
  [term a next b]
  (accumulate + 0 term a next b))
(sum identity 1 inc 10)
=> 55
(defn product
  [term a next b]
  (accumulate * 1 term a next b))
(product identity 1 inc 10)
=> 3628800
(defn accumulate-rec
  [combiner null-value term a next b]
  (if (> a b)
    null-value
    (combiner (term a)
              (accumulate combiner null-value term (next a) next b))))
(defn sum-rec
  [term a next b]
  (accumulate-rec + 0 term a next b))
(defn product-rec
  [term a next b]
  (accumulate-rec * 1 term a next b))
 
(ns sicp.chpt1.ex1-33
  (:use [sicp.chpt1.ex1-20 :only [gcd]]
        [sicp.chpt1.ex1-22 :only [prime?]]))
(defn filtered-accumulate
  [combiner null-value term a next b filter]
  (letfn [(iter [a result]
            (cond (> a b)
                  result
                  (filter a)
                  (recur (next a) (combiner (term a) result))
                  :else
                  (recur (next a) result)))]
    (iter a null-value)))
(defn sum-squares-of-primes
  [a b]
  (letfn [(square [x]
            (* x x))]
    (filtered-accumulate + 0 square a inc b prime?)))
(sum-squares-of-primes 1 10)
=> 88
(defn prod-coprime
  [n]
  (letfn [(coprime? [x]
            (= 1 (gcd x n)))]
    (filtered-accumulate * 1 identity 2 inc (dec n) coprime?)))
(prod-coprime 10)
=> 189
 
(ns sicp.chpt1.ex1-34)

Evaluating (f f), we'd get an error since 2 is not a function

(defn f
  [g]
  (g 2))
(f f)
|
(f 2)
|
(2 2)
=> java.lang.Long cannot be cast to clojure.lang.IFn
 
(ns sicp.chpt1.ex1-35
  (:use [sicp.chpt1.ex1-07 :only [abs]]))

\(x \rightarrow 1 + \frac{1}{x}\)

is a transformation whose fixed point is the solution to the equation

\(x = 1 + \frac{1}{x}\)

\(\Rightarrow x = \frac{x + 1}{x}\)

\(\Rightarrow x^2 = x + 1\)

which is also the definition for the golden ratio, \(\phi\)

(def tolerance 1/100000)
(defn fixed-point
  [f first-guess]
  (letfn [(close-enough? [v1 v2]
            (< (abs (- v1 v2)) tolerance))
          (try-it [guess]
            (let [next (f guess)]
              (if (close-enough? guess next)
                next
                (recur next))))]
    (try-it first-guess)))
(def phi
  (fixed-point (fn [x] (+ 1 (/ x))) 1))
(float phi)
=> 1.6180328
 
(ns sicp.chpt1.ex1-36
  (:use [sicp.chpt1.ex1-07 :only [abs]]))
(def tolerance 1/100000)
(defn fixed-point
  [f first-guess]
  (letfn [(close-enough? [v1 v2]
            (< (abs (- v1 v2)) tolerance))
          (try-it [guess i]
            (println guess i)
            (let [next (f guess)]
              (if (close-enough? guess next)
                next
                (recur next (inc i)))))]
    (try-it first-guess 0)))

Solutions to \(x^x = 1000\)

\(x \rightarrow \frac{\log 1000}{\log x}\)

(defn without-damping
  []
  (fixed-point (fn [x]
                 (/ (Math/log 1000)
                    (Math/log x)))
               10))

without damping takes 32 steps to converge

(without-damping)
# 10 0
# 2.9999999999999996 1
# 6.2877098228681545 2
# 3.7570797902002955 3
# 5.218748919675316 4
# 4.1807977460633134 5
# 4.828902657081293 6
# 4.386936895811029 7
# 4.671722808746095 8
# 4.481109436117821 9
# 4.605567315585735 10
# 4.522955348093164 11
# 4.577201597629606 12
# 4.541325786357399 13
# 4.564940905198754 14
# 4.549347961475409 15
# 4.5596228442307565 16
# 4.552843114094703 17
# 4.55731263660315 18
# 4.554364381825887 19
# 4.556308401465587 20
# 4.555026226620339 21
# 4.55587174038325 22
# 4.555314115211184 23
# 4.555681847896976 24
# 4.555439330395129 25
# 4.555599264136406 26
# 4.555493789937456 27
# 4.555563347820309 28
# 4.555517475527901 29
# 4.555547727376273 30
# 4.555527776815261 31
# 4.555540933824255 32
=> 4.555532257016376

with damping

\(2x \rightarrow x + \frac{\log 1000}{\log x}\)

\(\Rightarrow x \rightarrow \frac{x\log x + \log 1000}{2\log x}\)

(defn with-damping
  []
  (fixed-point (fn [x]
                 (let [logx (Math/log x)]
                   (/ (+ (* x logx) (Math/log 1000))
                      (* 2 logx))))
               10))

with damping takes 9 steps to converge

(with-damping)
# 10 0
# 6.5 1
# 5.095215099176933 2
# 4.668760681281611 3
# 4.57585730576714 4
# 4.559030116711325 5
# 4.55613168520593 6
# 4.555637206157649 7
# 4.5555529875456395 8
# 4.555538647701617 9
=> 4.555536206185039
 
(ns sicp.chpt1.ex1-37)

Recursive

(defn cont-frac
  ([n d k]
     (cont-frac n d k 1))
  ([n d k i]
     (if (> i k)
       0
       (/ (n i) (+ (d i) (cont-frac n d k (inc i)))))))

\(\phi \approx 1.61803399\)

\(\frac{1}{\phi} \approx 0.61803398\)

(defn phi-inverse
  [k]
  (cont-frac (constantly 1)
             (constantly 1)
             k))
(float (phi-inverse 11))
=> 0.6180556

when k is 11, we get 4 digits after the decimal point of accuracy

Iterative

(defn cont-frac
  ([n d k]
     (cont-frac n d k 0))
  ([n d k acc]
     (if (zero? k)
       acc
       (recur n d (dec k) (/ (n k)
                             (+ (d k) acc))))))
 
(ns sicp.chpt1.ex1-38
  (:use [sicp.chpt1.ex1-37 :only [cont-frac]]))

\(e \approx 2.71828183\)

(defn e
  [k]
  (float (+ (cont-frac (constantly 1)
                       (fn [x]
                         (if (= (rem x 3) 2)
                           (* 2 (inc (quot x 3)))
                           1))
                       k)
            2)))
(e 9)
=> 2.71828
 
(ns sicp.chpt1.ex1-39
  (:use [sicp.chpt1.ex1-37 :only [cont-frac]]))
(defn tan-cf
  [x k]
  (letfn [(numerator [i]
            (if (= 1 i)
              x
              (- (* x x))))
          (denominator [i]
            (dec (* 2 i)))]
    (float (cont-frac numerator denominator k))))

\(\tan 0 = 0\)

(tan-cf (* Math/PI 0) 11)
=> 0.0

\(\tan \frac{\pi}{4} = 1\)

(tan-cf (* Math/PI 1/4) 11)
=> 1.0

\(\tan \frac{\pi}{2} = \infty\)

(tan-cf (* Math/PI 1/2) 11)
=> *Divide By Zero*

\(\tan \frac{3\pi}{4} = -1\)

(tan-cf (* Math/PI 3/4) 11)
=> -1.0
 
(ns sicp.chpt1.ex1-40
  (:use [sicp.chpt1.ex1-35 :only [fixed-point]]))
(def dx 1/100000)
(defn deriv
  [g]
  (fn [x]
    (/ (- (g (+ x dx)) (g x))
       dx)))
(defn newton-transform
  [g]
  (fn [x]
    (- x (/ (g x) ((deriv g) x)))))
(defn newton-method
  [g guess]
  (fixed-point (newton-transform g) guess))
(defn cubic
  [a b c]
  (fn [x]
    (+ (* x x x)
       (* a x x)
       (* b x)
       c)))
((cubic 1 2 3) 1)
=> 7
(float (newton-method (cubic 1 1 1) 1))
=> -1.0
 
(ns sicp.chpt1.ex1-41
  (:refer-clojure :exclude [double]))
(defn double
  [f]
  (fn [x]
    (f (f x))))
(((double (double double)) inc) 5)
=> 21
 
(ns sicp.chpt1.ex1-42)
(defn compose
  [f g]
  (fn [x]
    (f (g x))))
((compose #(* % %) inc) 6)
=> 49
 
(ns sicp.chpt1.ex1-43)
(defn repeated
  [f n]
  (loop [g f i n]
    (cond (= 1 i)
          g
          (even? i)
          (recur (comp g g) (/ i 2))
          :else
          (recur (comp f g) (dec i)))))
((repeated #(* % %) 2) 5)
=> 625
 
(ns sicp.chpt1.ex1-44
  (:use [sicp.chpt1.ex1-43 :only [repeated]]))
(def dx 1/100000)
(defn smooth
  [f]
  (fn [x]
    (/ (+ (f (- x dx))
          (f x)
          (f (+ x dx)))
       3)))
(defn n-fold-smooth
  [f n]
  ((repeated smooth n) f))
 
(ns sicp.chpt1.ex1-45
  (:use [sicp.chpt1.ex1-07 :only [abs]]
        [sicp.chpt1.ex1-16 :only [fast-expt]]
        [sicp.chpt1.ex1-35 :only [fixed-point]]
        [sicp.chpt1.ex1-43 :only [repeated]]))
(def tolerance 1/100000)
(defn fixed-point-limit
  [f first-guess limit]
  (letfn [(close-enough? [v1 v2]
            (< (abs (- v1 v2)) tolerance))
          (try-it [guess i]
            (let [next (f guess)]
              (if (or (zero? i) (close-enough? guess next))
                [next (- limit i)]
                (recur next (dec i)))))]
    (try-it first-guess limit)))
(defn fixed-point-of-transform-limit
  [g transform guess limit]
  (fixed-point-limit (transform g) guess limit))
(defn fixed-point-of-transform
  [g transform guess]
  (fixed-point (transform g) guess))
(defn average-damp
  [f]
  (fn [x]
    (/ (+ (f x) x) 2)))
(defn nth-root-fixed-point
  [y n]
  (fn [x]
    (/ y (fast-expt x (dec n)))))
(fixed-point-of-transform-limit
  (nth-root-fixed-point 100 2) identity 1.0 100)

Steps Reached [100]

(fixed-point-of-transform-limit
  (nth-root-fixed-point 100 2) average-damp 1.0 100)

Steps Reached [7]

(fixed-point-of-transform-limit
  (nth-root-fixed-point 100 4) average-damp 1.0 100)

Steps Reached [100]

(fixed-point-of-transform-limit
  (nth-root-fixed-point 100 4)
  (repeated average-damp 2)
  1.0
  100)

Steps Reached [12]

(fixed-point-of-transform-limit
  (nth-root-fixed-point 100 8)
  (repeated average-damp 2)
  1.0
  100)

Steps Reached [100]

(fixed-point-of-transform-limit
  (nth-root-fixed-point 100 8)
  (repeated average-damp 3)
  1.0
  100)

Steps Reached [37]

In conculusion, average damping of at least \(\log _2 n\) is needed to converge the fixed point for the nth root

(defn nth-root
  [x n]
  (fixed-point-of-transform (nth-root-fixed-point x n)
                            (repeated average-damp (int (/ (Math/log n)
                                                           (Math/log 2))))
                            1.0))
 
(ns sicp.chpt1.ex1-46)
(defn iterative-improve
  [good-enough? improve-guess]
  (fn [guess]
    (if (good-enough? guess)
      guess
      (recur (improve-guess guess)))))
(def tolerance 1/10000)
(defn sqrt
  [x]
  (letfn [(good-enough?
            [guess]
            (< (Math/abs (- (* guess guess) x)) tolerance))
          (improve-guess
            [guess]
            (/ (+ (/ x guess) guess) 2))]
    ((iterative-improve good-enough? improve-guess) 1.0)))
(defn fixed-point
  [f]
  (letfn [(good-enough?
            [guess]
            (< (Math/abs (- (f guess) guess)) tolerance))
          (improve-guess
            [guess]
            (f guess))]
    (iterative-improve good-enough? improve-guess)))
(sqrt 10)
=> 3.162277665175675
((fixed-point (fn [x] (+ 1 (/ x)))) 1.0)
=> 1.6179775280898876
 
(ns sicp.chpt2.ex2-01
  (:use [sicp.chpt1.ex1-20 :only [gcd]]))

Using Clojure's records instead of cons cells as a means of combination

(defrecord Rational [n d])
(defn make-rat
  [n d]
  (let [div (Math/abs (gcd n d))
        n-div (if (or (and (pos? n) (neg? d))
                      (and (neg? n) (neg? d)))
                    (- div)
                    div)]
    (Rational. (/ n n-div) (/ d n-div))))
(make-rat 10 20)
=> #sicp.chpt2.ex2_01.Rational{:n 1, :d 2}
 
(ns sicp.chpt2.ex2-02)
(defrecord Point [x y])
(defn make-point
  [x y]
  (Point. x y))
(defn x-point
  [p]
  (.x p))
(defn y-point
  [p]
  (.y p))
(defrecord Segment [p1 p2])
(defn make-segment
  [p1 p2]
  (Segment. p1 p2))
(defn start-segment
  [s]
  (.p1 s))
(defn end-segment
  [s]
  (.p2 s))
(defn midpoint
  [s]
  (let [p1 (start-segment s)
        p2 (end-segment s)
        x1 (x-point p1)
        y1 (y-point p1)
        x2 (x-point p2)
        y2 (y-point p2)]
    (make-point (/ (+ x1 x2) 2)
                (/ (+ y1 y2) 2))))
(midpoint (make-segment (make-point 0 0)
                        (make-point 2 2)))
=> #sicp.chpt2.ex2_02.Point{:x 1, :y 1}
 
(ns sicp.chpt2.ex2-03
  (:use [sicp.chpt2.ex2-02 :only [make-point
                                  x-point
                                  y-point
                                  make-segment
                                  start-segment
                                  end-segment]]))

For the sake of simplicity, assume the sides of the rectangle are always perpendicular to the coordinate axes

Here we're storing only the diagonal, for a general rectangle definition, the angle between a side and an axis would also be needed.

(defrecord Rectangle [diag])
(defn make-rectangle
  [diag]
  (Rectangle. diag))

Calculate the other points whenever rectangle-points is called

(defn rectangle-points
  [rect]
  (let [diag (.diag rect)
        a (start-segment diag)
        c (end-segment diag)
        b (make-point (x-point a)
                      (y-point c))
        d (make-point (x-point c)
                      (y-point a))]
    [a b c d]))

distance returns the Euclidean distance between 2 points

(defn distance
  [p1 p2]
  (letfn [(sqr [x]
            (* x x))]
    (Math/sqrt (+ (sqr (- (y-point p2)
                          (y-point p1)))
                  (sqr (- (x-point p2)
                          (x-point p1)))))))
(defn perimeter
  [rect]
  (let [[a b c d] (rectangle-points rect)]
    (* 2 (+ (distance a b)
            (distance b c)))))
(defn area
  [rect]
  (let [[a b c] (rectangle-points rect)]
    (* (distance a b)
       (distance b c))))
(let [rect (make-rectangle (make-segment (make-point 1 1)
                                         (make-point 0 0)))]
  {:perimeter (perimeter rect)
   :area (area rect)})
=> {:perimeter 4.0, :area 1.0}

Changing how rectangles are stored to store all 4 points

(defrecord Rectangle [a b c d])
(defn make-rectangle
  [diag]
  (let [a (start-segment diag)
        c (end-segment diag)
        b (make-point (x-point a)
                      (y-point c))
        d (make-point (x-point c)
                      (y-point a))]
    (Rectangle. a b c d)))

All the points are already stored, they just need to be returned

(defn rectangle-points
  [rect]
  [(.a rect) (.b rect) (.c rect) (.d rect)])
(let [rect (make-rectangle (make-segment (make-point 1 1)
                                         (make-point 0 0)))]
  {:perimeter (perimeter rect)
   :area (area rect)})
=> {:perimeter 4.0, :area 1.0}

The trade off here is between memory and performance.

The diagonal rectangle stored the minimum required data but needed to calculate all 4 points everytime rectangle-points was called.

The point approach calculated all 4 points just once but needed to store twice the number of points.

 
(ns sicp.chpt2.ex2-04
  (:refer-clojure :exclude [cons]))
(defn cons
  [x y]
  (fn [m] (m x y)))
(defn car
  [z]
  (z (fn [x y] x)))

The corresponding definition of cdr

(defn cdr
  [z]
  (z (fn [x y] y)))
(car (cons 2 3))
=> 2
(cdr (cons 2 3))
=> 3

Using the substitution model

(car (cons 2 3))
# (car (fn [m] (m 2 3)))
# ((fn [m] (m 2 3)) (fn [x y] x))
# ((fn [x y] x) 2 3)
=> 2
(cdr (cons 2 3))
# (cdr (fn [m] (m 2 3)))
# ((fn [m] (m 2 3)) (fn [x y] y))
# ((fn [x y] y) 2 3)
=> 3
 
(ns sicp.chpt2.ex2-05
  (:refer-clojure :exclude [cons]))

Since both 2 and 3 are prime, \(2^{a}3^{b}\) is unique to the pair (a, b)

(defn cons
  [x y]
  (int (* (Math/pow 2 x)
          (Math/pow 3 y))))

d-component computes the largest integer value of x which satisfies \(d^x \leq n\)

(defn- d-component
  [n d]
  (loop [x n acc 0]
    (if (zero? (rem x d))
      (recur (/ x d) (inc acc))
      acc)))
(defn car
  [z]
  (d-component z 2))
(defn cdr
  [z]
  (d-component z 3))
(car (cons 2 3))
=> 2
(cdr (cons 2 3))
=> 3

Using the substitution model

(car (cons 2 3))
# (car 108)
=> 2
(cdr (cons 2 3))
# (cdr 108)
=> 3
 
(ns sicp.chpt2.ex2-06)

An integer \(n\) corresponds to n applications of a function f as a church numeral

(defn church->int
  [n]
  ((n inc) 0))
(def zero
  (fn [f]
    (fn [x]
      x)))
(defn add1
  [n]
  (fn [f]
    (fn [x]
      (f ((n f) x)))))
(def one
  (fn [f]
    (fn [x]
      (f x))))
(def two
  (fn [f]
    (fn [x]
      (f (f x)))))

Addition is simply function composition

(defn add
  [a b]
  (fn [f]
    (comp (a f) (b f))))
(church->int zero)
=> 0
(church->int one)
=> 1
(church->int two)
=> 2
(church->int (add one two))
=> 3
 
(ns sicp.chpt2.ex2-07)
(defrecord Interval [lb ub])
(defn make-interval
  [lb ub]
  (Interval. lb ub))
(defn lower-bound
  [i]
  (.lb i))
(defn upper-bound
  [i]
  (.ub i))
(lower-bound (make-interval 2 3))
=> 2
(upper-bound (make-interval 2 3))
=> 3
 
(ns sicp.chpt2.ex2-08
  (:use [sicp.chpt2.ex2-07 :only [make-interval
                                  lower-bound
                                  upper-bound]]))
(defn add-interval
  [x y]
  (make-interval (+ (lower-bound x)
                    (lower-bound y))
                 (+ (upper-bound x)
                    (upper-bound y))))
(add-interval (make-interval 4 5)
              (make-interval 2 3))
=> #sicp.chpt2.ex2_08.Interval{:lb 6, :ub 8}
(defn sub-interval
  [x y]
  (let [a (- (lower-bound x)
             (lower-bound y))
        b (- (upper-bound x)
             (upper-bound y))]
    (if (< a b)
      (make-interval a b)
      (make-interval b a))))
(sub-interval (make-interval 4 5)
              (make-interval 2 3))
=> #sicp.chpt2.ex2_08.Interval{:lb 2, :ub 2}
 
(ns sicp.chpt2.ex2-09
  (:use [sicp.chpt2.ex2-07 :only [make-interval
                                  lower-bound
                                  upper-bound]]
        [sicp.chpt2.ex2-08 :only [add-interval
                                  sub-interval]]))
(defn mul-interval
  [x y]
  (let [p1 (* (lower-bound x) (lower-bound y))
        p2 (* (lower-bound x) (upper-bound y))
        p3 (* (upper-bound x) (lower-bound y))
        p4 (* (upper-bound x) (upper-bound y))]
    (make-interval (min p1 p2 p3 p4)
                   (max p1 p2 p3 p4))))
(defn div-interval
  [x y]
  (mul-interval x
                (make-interval (/ (lower-bound y))
                               (/ (upper-bound y)))))
(defn width
  [x]
  (/ (- (upper-bound x)
        (lower-bound x))
     2))

Aliasing lower-bound as lb and upper-bound as ub

let x and y be two intervals

  • \(width(x) = \frac{ub(x) - lb(x)}{2}\)
  • \(width(y) = \frac{ub(y) - lb(y)}{2}\)

let z be (add-interval x y)

  • \(lb(z) = lb(x) + lb(y)\)
  • \(ub(z) = ub(x) + ub(y)\)

Expanding \(width(z)\)

\(\Rightarrow \frac{ub(z) - lb(z)}{2}\)

\(\Rightarrow \frac{(ub(x) + ub(y)) - (lb(x) + lb(y))}{2}\)

\(\Rightarrow \frac{ub(x) + ub(y) - lb(x) - lb(y)}{2}\)

\(\Rightarrow \frac{ub(x) - lb(x) + ub(y) - lb(y)}{2}\)

\(\Rightarrow \frac{ub(x) - lb(x)}{2} + \frac{ub(y) - lb(y)}{2}\)

\(\Rightarrow width(x) + width(y)\)

Therefore

\(width(x + y) \Rightarrow width(x) + width(y)\)

Similarly for subtraction

For multiplication or division, the max and min of the products of the bounds are taken, therefore the width of the multiplication or division of 2 intervals isn't a multiplication or division of the widths of the bounds of the intervals

 
(ns sicp.chpt2.ex2-10
  (:use [sicp.chpt2.ex2-07 :only [make-interval
                                  lower-bound
                                  upper-bound]]
        [sicp.chpt2.ex2-09 :only [mul-interval]]))
(defn div-interval
  [x y]
  (letfn [(spans-zero?
            [i]
            (and (<= (lower-bound i) 0)
                 (<= 0 (upper-bound i))))]
    (if (spans-zero? y)
      (throw (ArithmeticException. "Divide by zero"))
      (mul-interval x
                    (make-interval (/ (lower-bound y))
                                   (/ (upper-bound y)))))))
(div-interval (make-interval 2 3)
              (make-interval -1 1))
=> *Divide by zero*
 
(ns sicp.chpt2.ex2-11
  (:use [sicp.chpt2.ex2-07 :only [make-interval
                                  lower-bound
                                  upper-bound]]))
(defn mul-interval
  [x y]
  (let [lbx (lower-bound x)
        lby (lower-bound y)
        ubx (upper-bound x)
        uby (upper-bound y)]
    (cond (and (pos? lbx) (pos? lby))
          (make-interval (* lbx lby) (* ubx uby))
          (and (neg? lbx) (neg? lby) (neg? ubx) (neg? uby))
          (make-interval (* ubx uby) (* lbx lby))
          (and (pos? lbx) (neg? lby) (pos? ubx) (neg? uby))
          (make-interval (* ubx lby) (* lbx uby))
          (and (neg? lbx) (pos? lby) (neg? ubx) (pos? uby))
          (make-interval (* lbx uby) (* ubx lby))
          (and (pos? lbx) (neg? lby) (pos? ubx) (pos? uby))
          (make-interval (* ubx lby) (* ubx uby))
          (and (neg? lbx) (pos? lby) (pos? ubx) (pos? uby))
          (make-interval (* lbx uby) (* ubx uby))
          (and (neg? lbx) (neg? lby) (neg? ubx) (pos? uby))
          (make-interval (* lbx uby) (* lbx lby))
          (and (neg? lbx) (neg? lby) (pos? ubx) (neg? uby))
          (make-interval (* ubx lby) (* lbx uby))
          :else
          (let [l1 (* lbx uby)
                l2 (* ubx lby)
                u1 (* lbx lby)
                u2 (* ubx uby)]
            (make-interval (if (< l1 l2) l1 l2)
                           (if (< u1 u2) u2 u1))))))
 
(ns sicp.chpt2.ex2-12
  (:use [sicp.chpt2.ex2-07 :only [make-interval
                                  lower-bound
                                  upper-bound]]))
(defn make-center-percent
  [c p]
  (let [width (Math/abs (* (/ p 100.0) c))]
    (make-interval (- c width)
                   (+ c width))))
(defn center
  [i]
  (/ (+ (lower-bound i)
        (upper-bound i))
     2))
(defn percent
  [i]
  (let [c (center i)]
    (Math/abs (* (/ (- (upper-bound i) c)
                    c)
                 100.0))))
(defn print-interval
  [i]
  (format "(%1.2f, %1.2f%%)"
          (double (center i))
          (double (percent i))))
(center (make-center-percent 100 10))
=> 100
(percent (make-center-percent 100 10))
=> 10.0
 
(ns sicp.chpt2.ex2-13
  (:use [sicp.chpt2.ex2-12 :only [make-center-percent
                                  center
                                  percent]]))

Let \(x \pm a\) and \(y \pm b\) be 2 intervals

\((x \pm a) \times (y \pm b)\)

In [lower bound, upper bound] form

\(\Rightarrow [x (1 - \frac{a}{100}), x(1 + \frac{a}{100})] \times [y (1 - \frac{b}{100}), y(1 + \frac{b}{100})]\)

Assuming both have positive lower-bounds

\(\Rightarrow [xy(1 - \frac{a}{100})(1 - \frac{b}{100}), xy(1 + \frac{a}{100})(1 + \frac{b}{100})]\)

\(\Rightarrow [xy(1 - \frac{a}{100} - \frac{b}{100} + \frac{ab}{10000}), xy(1 + \frac{a}{100} + \frac{b}{100} + \frac{ab}{10000})]\)

For small percentage tolerances, \(\frac{ab}{10000} \rightarrow 0\)

\(\Rightarrow [xy(1 - \frac{a + b}{100}), xy(1 + \frac{a+b}{100})]\)

\(\Rightarrow xy \pm (a+b)\)

(defn mul-interval
  [i1 i2]
  (make-center-percent (* (center i1) (center i2))
                       (+ (percent i1) (percent i2))))
 
(ns sicp.chpt2.ex2-14
  (:use [sicp.chpt2.ex2-07 :only [make-interval]]
        [sicp.chpt2.ex2-08 :only [add-interval]]
        [sicp.chpt2.ex2-09 :only [mul-interval]]
        [sicp.chpt2.ex2-10 :only [div-interval]]
        [sicp.chpt2.ex2-12 :only [make-center-percent
                                  print-interval]]))
(defn par1
  [r1 r2]
  (div-interval (mul-interval r1 r2)
                (add-interval r1 r2)))
(defn par2
  [r1 r2]
  (let [one (make-interval 1 1)]
    (div-interval one
                  (add-interval (div-interval one r1)
                                (div-interval one r2)))))
(let [one (make-interval 1 1)
      i (make-center-percent 1000 1)]
  (letfn [(mapper [n]
            (->> (cycle [i (div-interval one i)])
                 (take (* 2 n))
                 (reduce mul-interval)
                 print-interval))]
    (map mapper (range 1 5))))
=> ("(1.00, 2.00%)"
    "(1.00, 4.00%)"
    "(1.00, 5.99%)"
    "(1.00, 7.98%)")

mapper returns \(\prod [1000, \frac{1}{1000}, 1000, \frac{1}{1000}, 1000, \frac{1}{1000}, ...]\), for \(2n\) terms

The error increases by 1% with every multiplication

(let [i1 (make-center-percent 1000 1)
      i2 (make-center-percent -1000 1)]
  (letfn [(mapper [n]
            (->> (cycle [i1 i2])
                 (concat [i1])
                 (take (* 2 n))
                 (reduce add-interval)
                 print-interval))]
    (map mapper (range 1 5))))
=> ("(2000.00, 1.00%)"
    "(2000.00, 2.00%)"
    "(2000.00, 3.00%)"
    "(2000.00, 4.00%)")

mapper returns \(\sum [(1000), 1000, -1000, 1000, -1000, ...]\), for \(2n\) terms

The error increases by 0.5% with every addition

(let [i1 (make-center-percent 1000 1)
      i2 (make-center-percent 2000 1)]
  [(print-interval (par1 i1 i2))
   (print-interval (par2 i1 i2))])
=> ["(666.93, 3.00%)"
    "(666.67, 1.00%)"]

The formula \(\frac{R1R2}{R1+R2}\) results in a higher error than \(\frac{1}{R1} + \frac{1}{R2}\)

Every operation with intervals, even if algebraicly a no-op increases the error

The problem here is that identical intervals don't cancel themselves, ie. \(\frac{x}{x} \neq 1\)

 
(ns sicp.chpt2.ex2-15)

The formula for calculating resitances in parallel is \(\frac{1}{R1} + \frac{1}{R2}\)

Simplifying the formula by one step we get \(\frac{1}{\frac{R2 + R1}{R1R2}}\)

This makes the assumption that \(\frac{R1}{R1}\) and \(\frac{R2}{R2}\) are 1

But with interval arithmetic, they aren't exactly 1

Therefore the simplification is not possible

par2 is the more accurate formula because it doesn't make this assumption

 
(ns sicp.chpt2.ex2-16)

Regular algebra assumes that identities always have a fixed value, that's why identical identites can cancel each other out perfectly

With intervals that's not the case. The value is not precise and so normal algebraic simplifications can't work.

I don't think it is possible to design an interval-arithmetic library that does not have this problem.

What we can do is to express our equations with no standard algebraic assumptions like \(\frac{n}{n}, n \neq 0 \rightarrow 1\).

This will minimize the error

 
(ns sicp.chpt2.ex2-17)
(defn last-pair
  [l]
  (if (empty? (rest l))
    l
    (recur (rest l))))

Other Implementations

(def last-pair
  (comp list last))
 
(ns sicp.chpt2.ex2-18
  (:refer-clojure :exclude [reverse]))

Recursive

(defn reverse
  [l]
  (if (empty? l)
    []
    (conj (reverse (rest l)) (first l))))

Iterative

(defn reverse
  ([l]
     (reverse l ()))
  ([l acc]
     (if (empty? l)
       acc
       (recur (rest l) (conj acc (first l))))))

Other Implementations

(def reverse clojure.core/reverse)
 
(ns sicp.chpt2.ex2-19)
(def no-more? empty?)
(def except-first-denomination rest)
(def first-denomination first)
(defn cc
  [amount coin-values]
  (cond (= amount 0)
        1
        (or (< amount 0) (no-more? coin-values))
        0
        :else
        (+ (cc amount
               (except-first-denomination coin-values))
           (cc (- amount
                  (first-denomination coin-values))
               coin-values))))
(def us-coins [50 25 10 5 1])
(def uk-coins [100 50 20 10 5 2 1 0.5])

No the initial ordering doesn't matter as long as the same ordering is maintained throughout subsequent calls

The problem is defined in terms of 2 sub problems

The first problem calculates the number of ways to count change without one of the denominations but the same amount

The second problem calculates the number of ways to count change with the same denomination list but with the amount reduced by the first value in the demoniation list

Both functions make the assumption that the initial order doesn't change and track the state of the system that way.

 
(ns sicp.chpt2.ex2-20)

Recursive

(defn same-parity
  [x & xs]
  (cond (empty? xs)
        ()
        (= (rem x 2) (rem (first xs) 2))
        (conj (apply same-parity x (rest xs))
              (first xs))
        :else
        (apply same-parity x (rest xs))))

Iterative

(defn- same-parity-iter
  [x xs acc]
  (cond (empty? xs)
        acc
        (= (rem x 2) (rem (first xs) 2))
        (recur x (rest xs) (conj acc (first xs)))
        :else
        (recur x (rest xs) acc)))
(defn same-parity
  [x & xs]
  (same-parity-iter x xs []))

Other Implementations

(defn same-parity
  [x & xs]
  (filter (if (even? x) even? odd?) xs))
 
(ns sicp.chpt2.ex2-21)

Recursive

(defn square-list
  [items]
  (if (empty? items)
    items
    (conj (square-list (rest items))
          (#(* % %) (first items)))))

Sequential

(defn square-list
  [items]
  (map #(* % %) items))

in Clojure, the sequence operators (like map and filter) return lazy sequences, these let us chain operators while only computing the values on realizing them

 
(ns sicp.chpt2.ex2-22)

using loop instead of an anonymous fn

(defn square-list
  [items]
  (loop [things items answer ()]
    (if (empty? things)
      answer
      (recur (rest things)
             (conj answer
                   (#(* % %) (first things)))))))

Clojure (and most lisps, append to the front of a list when consing, the list is processed in order but each successive result is appended to the start of answer reversing it

(defn square-list
  [items]
  (loop [things items answer ()]
    (if (empty? things)
      answer
      (recur (rest things)
             (conj (#(* % %) (first things))
                   answer)))))

Clojure doesn't have a concept of pairs, you can only cons onto a sequence so this throws an exception. Even if we had pairs, we'd end up with a deeply nested result, but it would be in the same order as the input.

Solutions

There are a few ways to get around this

Using reverse in the final step of the iteration solves this issue but it ends up traversing the input twice

Another solution is to use Clojure's vector datatype instead of the list, using conj on a vector appends to the end which maintains order

(conj [] 1 2 3)
=> [1 2 3]
(conj () 1 2 3)
=> (3 2 1)

initializing answer with [] instead of () will keep order

 
(ns sicp.chpt2.ex2-23)
(defn for-each
  ([f coll]
     (for-each f coll nil))
  ([f coll return]
     (loop [things coll]
       (if (empty? things)
         return
         (do (f (first things))
             (recur (rest things)))))))
(for-each println [1 2 3 4 5] true)
# 1
# 2
# 3
# 4
# 5
=> true

Other Implementations

(defn for-each
  ([f coll]
     (for-each f coll nil))
  ([f coll return]
     (doseq [x coll]
       (f x))
     return))
 
(ns sicp.chpt2.ex2-24)

Interpreter Output

(list 1 (list 2 (list 3 4)))
=> (1 (2 (3 4)))

Box and Pointer

[.][.] -> [.][x]
 |         |
[1]       [.][.] -> [.][x]
           |         |
          [2]       [.][.] -> [.][x]
                     |         |
                    [3]       [4]

Tree

(1         (2 (3 4)))
 |             |
 1      (2          (3 4))
         |            |
         2        (3     4)
                   |     |
                   3     4
 
(ns sicp.chpt2.ex2-25)

(1 3 (5 7) 9)

(let [s [1 3 [5 7] 9]]
  (first (rest (first (rest (rest s))))))

((7))

(let [s [[7]]]
  (first (first s)))

(1 (2 (3 (4 (5 (6 7))))))

(let [s [1 [2 [3 [4 [5 [6 7]]]]]]]
  (first (rest (first (rest (first (rest (first (rest (first (rest (first (rest s)))))))))))))
 
(ns sicp.chpt2.ex2-26)
(def x (list 1 2 3))
(def y (list 4 5 6))

concat is equivalent to append

(concat x y)
=> (1 2 3 4 5 6
(cons x y)
=> ((1 2 3) 4 5 6)
(list x y)
=> ((1 2 3) (4 5 6))
 
(ns sicp.chpt2.ex2-27)
(defn deep-reverse
  [x]
  (cond (empty? x)
        []
        (coll? (first x))
        (conj (deep-reverse (rest x))
              (deep-reverse (first x)))
        :else
        (conj (deep-reverse (rest x))
              (first x))))
(def x (list (list 1 2) (list 3 4)))
(reverse x)
=> ((3 4) (1 2))
(deep-reverse x)
=> [[4 3] [2 1]]
 
(ns sicp.chpt2.ex2-28)
(defn fringe
  [l]
  (cond (empty? l)
        ()
        (coll? (first l))
        (concat (fringe (first l))
                (fringe (rest l)))
        :else
        (conj (fringe (rest l)) (first l))))
(def x (list (list 1 2) (list 3 4)))
(fringe x)
=> (1 2 3 4)
(fringe (list x x))
=> (1 2 3 4 1 2 3 4)
 
(ns sicp.chpt2.ex2-29)
(defn make-mobile
  [left right]
  (list left right))
(defn make-branch
  [length structure]
  (list length structure))

a. selectors

(defn left-branch
  [mobile]
  (first mobile))
(defn right-branch
  [mobile]
  (second mobile))
(defn branch-length
  [branch]
  (first branch))
(defn branch-structure
  [branch]
  (second branch))

b. mobile weights

(defn mobile?
  [structure]
  (not (number? structure)))
(declare total-weight)
(defn branch-weight
  [branch]
  (if (mobile? (branch-structure branch))
    (total-weight (branch-structure branch))
    (branch-structure branch)))
(defn total-weight
  [mobile]
  (+ (branch-weight (left-branch mobile))
     (branch-weight (right-branch mobile))))
 (total-weight
  (make-mobile (make-branch 1
                            (make-mobile
                             (make-branch 1 10)
                             (make-branch 1 10)))
               (make-branch 1
                            (make-mobile
                             (make-branch 1 10)
                             (make-branch 2 20)))))
 => 50

c. balanced?

(defn torque
  [branch]
  (* (branch-length branch)
     (branch-weight branch)))
(declare balanced?)
(defn balanced-branch?
  [branch]
  (if (mobile? (branch-structure branch))
    (balanced? (branch-structure branch))
    true))
(defn balanced?
  [mobile]
  (and (= (torque (left-branch mobile))
          (torque (right-branch mobile)))
       (balanced-branch? (left-branch mobile))
       (balanced-branch? (right-branch mobile))))
 (balanced? (make-mobile (make-branch 3
                                      (make-mobile
                                       (make-branch 1 10)
                                       (make-branch 1 10)))
                         (make-branch 1 60)))
 => true
 (balanced? (make-mobile (make-branch 1 20)
                         (make-branch 1 (make-mobile
                                         (make-branch 2 10)
                                         (make-branch 1 10)))))
 => false

d. abstraction

since Clojure doesn't have pair (can't cons onto a non seq), using vector instead

(defn make-mobile
  [left right]
  (vector left right))
(defn make-branch
  [length structure]
  (vector length structure))

since a vector is a seq, nothing else needs to be changed, first and second just work

 
(ns sicp.chpt2.ex2-30)

directly

(defn square-tree
  [tree]
  (cond (not (coll? tree))
        (* tree tree)
        (empty? tree)
        ()
        :else
        (conj (square-tree (rest tree))
              (square-tree (first tree)))))

using map

(defn square-tree
  [tree]
  (map (fn [subtree]
         (if (coll? subtree)
           (square-tree subtree)
           (* subtree subtree)))
       tree))
 (square-tree (list 1
                    (list 2 (list 3 4) 5)
                    (list 6 7)))
 => (1 (4 (9 16) 25) (36 49))
 
(ns sicp.chpt2.ex2-31)
(defn tree-map
  [f tree]
  (map (fn [subtree]
         (if (coll? subtree)
           (tree-map f subtree)
           (f subtree)))
       tree))
(defn square-tree
  [tree]
  (tree-map #(* % %) tree))
 (square-tree (list 1
                    (list 2 (list 3 4) 5)
                    (list 6 7)))
 => (1 (4 (9 16) 25) (36 49))
 
(ns sicp.chpt2.ex2-32)
(defn subsets
  [s]
  (if (empty? s)
    [()]
    (let [rst (subsets (rest s))]
      (concat rst (map #(conj % (first s)) rst)))))
 (subsets [1 2 3])
 => (() (3) (2) (2 3) (1) (1 3) (1 2) (1 2 3))

subsets works because it can be defined recursively as the collection of all the subsets of the set with the first element removed (rst) and the same subsets with the first element added to each.

 
(ns sicp.chpt2.ex2-33
  (:refer-clojure :exclude [map]))

Clojure comes with a built in fold-left called reduce, there isn't an implementation of accumulate which is fold-right

accumulate

(defn accumulate
  [op initial sequence]
  (if (empty? sequence)
    initial
    (op (first sequence)
        (accumulate op initial (rest sequence)))))

map

(defn map
  [p sequence]
  (accumulate (fn [x y] (conj y (p x))) () sequence))
 (map inc [1 2 3 4 5])
 => (2 3 4 5 6)

append

(defn append
  [seq1 seq2]
  (accumulate cons seq2 seq1))
 (append [1 2 3] [4 5 6])
 => (1 2 3 4 5 6)

length

(defn length
  [sequence]
  (accumulate (fn [_ n] (inc n)) 0 sequence))
 (length [1 2 3 4 5])
 => 5
 
(ns sicp.chpt2.ex2-34
  (:use [sicp.chpt2.ex2-33 :only [accumulate]]))
(defn horner-eval
  [x coefficient-sequence]
  (accumulate (fn [this-coeff higher-terms] (+ this-coeff (* x higher-terms)))
              0
              coefficient-sequence))
 (horner-eval 2 (list 1 3 0 5 0 1))
 => 79
 
(ns sicp.chpt2.ex2-35
  (:use [sicp.chpt2.ex2-33 :only [accumulate]]))
(declare count-leaves)
(defn count-coll
  [x]
  (if (coll? x)
    (count-leaves x)
    1))
(defn count-leaves
  [t]
  (accumulate + 0 (map count-coll t)))
 (count-leaves (list (list (list 1 2) (list 3 4))
                     (list (list 5 6) (list 7 8))))
 => 8
 
(ns sicp.chpt2.ex2-36
  (:use [sicp.chpt2.ex2-33 :only [accumulate]]))
(defn accumulate-n
  [op init seqs]
  (if (empty? (first seqs))
    ()
    (cons (accumulate op init (map first seqs))
          (accumulate-n op init (map rest seqs)))))
 (accumulate-n + 0 [[1 2 3] [4 5 6] [7 8 9] [10 11 12]])
 => (22 26 30)
 
(ns sicp.chpt2.ex2-37
  (:use [sicp.chpt2.ex2-33 :only [accumulate]])
  (:use [sicp.chpt2.ex2-36 :only [accumulate-n]]))

dot-product

(defn dot-product
  [v w]
  (accumulate + 0 (map * v w)))
 (dot-product [1 2] [3 4])
 => 11

matrix-*-vector

(defn matrix-*-vector
  [m v]
  (map (fn [row]
         (dot-product v row))
       m))
 (matrix-*-vector [[1 2]
                   [3 4]]

                  [5 6])
 => (17 39)

transpose

(defn transpose
  [mat]
  (accumulate-n cons () mat))
 (transpose [[1 2]
             [3 4]])
 => ((1 3) (2 4))

matrix-*-matrix

(defn matrix-*-matrix
  [m n]
  (let [cols (transpose n)]
    (map (fn [row]
           (matrix-*-vector cols row))
         m)))
 (matrix-*-matrix [[1 2]
                   [3 4]]

                  [[5 6]
                   [7 8]])
 => ((19 22) (43 50))
 
(ns sicp.chpt2.ex2-38)

Clojure's reduce is equivalent to fold-left

(defn fold-left
  [op initial sequence]
  (loop [acc initial s sequence]
    (if (empty? s)
      acc
      (recur (op acc (first s)) (rest s)))))
(defn fold-right
  [op initial sequence]
  (if (empty? sequence)
    initial
    (op (first sequence)
        (fold-right op initial (rest sequence)))))
 (fold-right / 1 (list 1 2 3))
 => 3/2
 (fold-left / 1 (list 1 2 3))
 => 1/6
 (fold-right list nil (list 1 2 3))
 => (1 (2 (3 nil)))
 (fold-left list nil (list 1 2 3))
 => (((nil 1) 2) 3)

for fold-left and fold-right to produce the same values on any sequence, the operation performed should be associative, i.e. \(\lambda(x,\lambda(y, z)) = \lambda(\lambda(x, y), z)\)

 (fold-left + 0 (list 1 2 3))
 => 6
 (fold-right + 0 (list 1 2 3))
 => 6
 
(ns sicp.chpt2.ex2-39
  (:refer-clojure :exclude [reverse])
  (:use [sicp.chpt2.ex2-38 :only [fold-left fold-right]]))

with fold-left

(defn reverse
  [sequence]
  (fold-left (fn [x y] (cons y x)) () sequence))

with fold-right

(defn reverse
  [sequence]
  (fold-right (fn [x y] (concat y (list x))) () sequence))
 (reverse [1 2 3 4])
 => (4 3 2 1)
 
(ns sicp.chpt2.ex2-40
  (:use [sicp.chpt1.ex1-22 :only [prime?]]))

Clojure's mapcat is equivalent to flatmap

(defn unique-pairs
  [n]
  (mapcat (fn [i]
            (map (fn [j] [i j])
                 (range 1 i)))
          (range 2 (inc n))))
 (unique-pairs 3)
 => ([2 1] [3 1] [3 2])
(defn make-pair-sum
  [[i j]]
  [i j (+ i j)])
(defn prime-sum?
  [[_ _ sum]]
  (prime? sum))
(defn prime-sum-pairs
  [n]
  (->> (unique-pairs n)
       (map make-pair-sum)
       (filter prime-sum?)))
 (prime-sum-pairs 5)
 => ([2 1 3] [3 2 5] [4 1 5] [4 3 7] [5 2 7])

unique-pairs lends itself better to a list-comprehension which can be expressed in Clojure by for

(defn unique-pairs
  [n]
  (for [i (range 2 (inc n))
        j (range 1 i)]
    [i j]))

for can also take a predicate making it possible to define prime-sum-pairs in a single step

(defn prime-sum-pairs
  [n]
  (for [i (range 2 (inc n))
        j (range 1 i)
        :when (prime? (+ i j))]
    [i j (+ i j)]))
 
(ns sicp.chpt2.ex2-41)

using mapcat

(defn ordered-triples
  [n]
  (mapcat (fn [i]
            (mapcat (fn [j]
                      (map (fn [k]
                             [i j k])
                           (range 1 (inc n))))
                    (range 1 (inc n))))
          (range 1 (inc n))))
(defn filtered-triples
  [n s]
  (letfn [(sum-s? [[i j k]]
            (= s (+ i j k)))]
    (filter sum-s? (ordered-triples n))))
 (filtered-triples 5 5)
 => ([1 1 3] [1 2 2] [1 3 1] [2 1 2] [2 2 1] [3 1 1])

using for

(defn filtered-triples
  [n s]
  (for [i (range 1 (inc n))
        j (range 1 (inc n))
        k (range 1 (inc n))
        :when (= s (+ i j k))]
    [i j k]))
 
(ns sicp.chpt2.ex2-42)

scaffolding

(defrecord Position [col row])
(defn make-position
  [col row]
  (Position. col row))
(defn column-value
  [position]
  (.col position))
(defn row-value
  [position]
  (.row position))

implementation

(def empty-board ())
(defn adjoin-position
  [row k positions]
  (conj positions (make-position (dec k) row)))
(defn attacks?
  [p1 p2]
  (or (= (row-value p1) (row-value p2))
      (= (column-value p1) (column-value p2))
      (= (- (row-value p1) (column-value p1))     ; along right diagonal
         (- (row-value p2) (column-value p2)))
      (= (+ (row-value p1) (column-value p1))     ; along left diagonal
         (+ (row-value p2) (column-value p2)))))
(defn safe?
  [k positions]
  (not (some (partial attacks? (first positions))
             (rest positions))))
(defn queens
  [board-size]
  (letfn [(queen-cols
            [k]
            (if (zero? k)
              [empty-board]
              (filter (fn [positions] (safe? k positions))
                      (mapcat
                       (fn [rest-of-queens]
                         (map (fn [new-row]
                                (adjoin-position new-row k rest-of-queens))
                              (range board-size)))
                       (queen-cols (dec k))))))]
    (queen-cols board-size)))

using for

(defn queens
  [board-size]
  (letfn [(queen-cols
            [k]
            (if (zero? k)
              [empty-board]
              (for [positions (queen-cols (dec k))
                    new-row (range board-size)
                    :when (safe? k (adjoin-position new-row k positions))]
                (adjoin-position new-row k positions))))]
    (queen-cols board-size)))

ascii art

(defn place-pieces
  [board-size positions]
  (reduce (fn [board position]
            (assoc-in board [(row-value position) (column-value position)] :q))
          (vec (repeat board-size (vec (repeat board-size :-))))
          positions))
(defn print-board
  [board]
  (doseq [row board]
    (println row)))
 (doseq [positions (queens 4)]
   (println)
   (print-board (place-pieces 4 positions))
   (println))
 # [:- :- :q :-]
 # [:q :- :- :-]
 # [:- :- :- :q]
 # [:- :q :- :-]
 # [:- :q :- :-]
 # [:- :- :- :q]
 # [:q :- :- :-]
 # [:- :- :q :-]

 => nil
 
(ns sicp.chpt2.ex2-43)

Both algorithms are recursive

The first algorithm is linearly recursive, every iteration calls queen-cols once, so for an \(n \times n\) board, the runtime is \(O(n)\)

The second algorithm is tree recursive, with queen-cols being called for every row in every iteration, so for an \(n \times n\) board, the runtime is \(O(n^n)\)

If the first algorithm runs in time \(T\), the second algorithm will complete after time \(T^T\)

 
(ns sicp.chpt2.ex2-44
  (:use [sicp.chpt2.ex2-51 :only [below beside]]
        [sicp.chpt2.ex2-49 :only [wave-painter
                                  identity-frame
                                  render]]))

The first few functions defined in this section refer to functions defined later (like below and beside)

(defn up-split
  [painter n]
  (if (zero? n)
    painter
    (let [smaller (up-split painter (dec n))]
      (below painter (beside smaller smaller)))))

Don't worry too much about the examples right now, just evaluating them to understand what they do is enough

the basic wave-painter

(render (wave-painter identity-frame))

up-split

(render ((up-split wave-painter 3) identity-frame))
 
(ns sicp.chpt2.ex2-45
  (:use [sicp.chpt2.ex2-51 :only [beside below]]
        [sicp.chpt2.ex2-49 :only [wave-painter
                                  identity-frame
                                  render]]))
(defn split
  [major-op minor-op]
  (fn [painter n]
    (if (zero? n)
      painter
      (let [smaller ((split major-op minor-op) painter (dec n))]
        (major-op painter (minor-op smaller smaller))))))
(def right-split (split beside below))
(def up-split (split below beside))

right-split

 (render ((right-split wave-painter 3) identity-frame))

up-split

 (render ((up-split wave-painter 3) identity-frame))
 
(ns sicp.chpt2.ex2-46)
(defrecord Vector [x y])
(defn make-vect
  [x y]
  (Vector. x y))
(defn xcor-vect
  [v]
  (.x v))
(defn ycor-vect
  [v]
  (.y v))
(xcor-vect (make-vect 3 4))
=> 3
(ycor-vect (make-vect 3 4))
=> 4
(defn add-vect
  [v1 v2]
  (make-vect (+ (xcor-vect v1)
                (xcor-vect v2))
             (+ (ycor-vect v1)
                (ycor-vect v2))))
(add-vect (make-vect 3 4)
          (make-vect 5 6))
=> #sicp.chpt2.ex2_46.Vector{:x 8, :y 10}
(defn sub-vect
  [v1 v2]
  (make-vect (- (xcor-vect v1)
                (xcor-vect v2))
             (- (ycor-vect v1)
                (ycor-vect v2))))
(sub-vect (make-vect 5 6)
          (make-vect 3 4))
=> #sicp.chpt2.ex2_46.Vector{:x 2, :y 2}
(defn scale-vect
  [c v]
  (make-vect (* c (xcor-vect v))
             (* c (ycor-vect v))))
(scale-vect 5 (make-vect 3 4))
=> #sicp.chpt2.ex2_46.Vector{:x 15, :y 20}
 
(ns sicp.chpt2.ex2-47
  (:use [sicp.chpt2.ex2-46 :only [make-vect]]))

Clojure doesn't have a concept of pairs so cons can't be used

using list

(defn make-frame
  [origin edge1 edge2]
  (list origin edge1 edge2))
(defn origin-frame
  [frame]
  (nth frame 0))
(defn edge1-frame
  [frame]
  (nth frame 1))
(defn edge2-frame
  [frame]
  (nth frame 2))
(let [frame (make-frame (make-vect 0 0)
                        (make-vect 1 1)
                        (make-vect 2 2))]
  [(origin-frame frame)
   (edge1-frame frame)
   (edge2-frame frame)])
=> [#sicp.chpt2.ex2_46.Vector{:x 0, :y 0}
    #sicp.chpt2.ex2_46.Vector{:x 1, :y 1}
    #sicp.chpt2.ex2_46.Vector{:x 2, :y 2}]

using records

(defrecord Frame [origin edge1 edge2])
(defn make-frame
  [origin edge1 edge2]
  (Frame. origin edge1 edge2))
(defn origin-frame
  [frame]
  (.origin frame))
(defn edge1-frame
  [frame]
  (.edge1 frame))
(defn edge2-frame
  [frame]
  (.edge2 frame))
 
(ns sicp.chpt2.ex2-48
  (:use [sicp.chpt2.ex2-46 :only [make-vect]]))
(defrecord Segment [start end])
(defn make-segment
  [start end]
  (Segment. start end))
(defn start-segment
  [seg]
  (.start seg))
(defn end-segment
  [seg]
  (.end seg))
(let [seg (make-segment (make-vect 0 0)
                        (make-vect 1 1))]
  [(start-segment seg)
   (end-segment seg)])
=> [#sicp.chpt2.ex2_46.Vector{:x 0, :y 0}
    #sicp.chpt2.ex2_46.Vector{:x 1, :y 1}]
 
(ns sicp.chpt2.ex2-49
  (:use [sicp.chpt2.ex2-46 :only [add-vect
                                  scale-vect
                                  make-vect
                                  xcor-vect
                                  ycor-vect]]
        [sicp.chpt2.ex2-47 :only [make-frame
                                  origin-frame
                                  edge1-frame
                                  edge2-frame]]
        [sicp.chpt2.ex2-48 :only [make-segment
                                  start-segment
                                  end-segment]]
        [seesaw.graphics :only [draw line style]])
  (:require [seesaw.core :as ss]))

seesaw is a swing wrapper for Clojure and made the picture language a lot simpler to implement

There are a few differences from the SICP version

Applying a painter to a frame returns a renderer which is a function which takes a canvas and a graphics object as arguments. This function can be attached to a seesaw.core/canvas and is used whenever it needs to be redrawn.

Since the renderer is redrawn whenever the canvas is resized, it scales automatically to fill all available space

(defn frame-coord-map
  [frame]
  (fn [v]
    (add-vect (origin-frame frame)
              (add-vect (scale-vect (xcor-vect v)
                                    (edge1-frame frame))
                        (scale-vect (ycor-vect v)
                                    (edge2-frame frame))))))
(def identity-frame
  (make-frame (make-vect 0 0)
              (make-vect 1 0)
              (make-vect 0 1)))

Projects the vectors of a frame to match a rectangle of different dimensions

(defn project-frame
  [frame x-axis y-axis]
  (make-frame (make-vect (* x-axis (xcor-vect (origin-frame frame)))
                         (* y-axis (ycor-vect (origin-frame frame))))
              (scale-vect x-axis (edge1-frame frame))
              (scale-vect y-axis (edge2-frame frame))))

Converts a segment into a seesaw.graphics/line

(defn segment->line
  ([segment]
     (segment->line identity-frame segment))
  ([frame segment]
     (let [translate (frame-coord-map frame)
           start (translate (start-segment segment))
           end (translate (end-segment segment))]
       (line (xcor-vect start) (ycor-vect start)
             (xcor-vect end) (ycor-vect end)))))
(defn segments->painter
  [segment-list]
  (fn [frame]
    (fn [c g]
      (let [style (style :foreground :black :stroke 1)
            projected (project-frame frame (.getWidth c) (.getHeight c))]
        (doseq [segment segment-list]
          (draw g (segment->line projected segment) style))))))

Initializes a resizable seesaw.core/frame with the renderer as the paint function

(defn render
  [renderer]
  (ss/frame :width 200
            :height 200
            :visible? true
            :content (ss/border-panel
                      :center (ss/canvas
                               :background "#ffffff"
                               :paint renderer))))

Returns a new renderer which draws all passed renderers in sequence

(defn chain
  [& renderers]
  (fn [c g]
    (doseq [r renderers]
      (r c g))))
(def outline-painter
  (segments->painter [(make-segment (make-vect 0 0)
                                    (make-vect 0 1))
                      (make-segment (make-vect 0 1)
                                    (make-vect 1 1))
                      (make-segment (make-vect 1 1)
                                    (make-vect 1 0))
                      (make-segment (make-vect 1 0)
                                    (make-vect 0 0))]))
(def x-painter
  (segments->painter [(make-segment (make-vect 0 0)
                                    (make-vect 1 1))
                      (make-segment (make-vect 0 1)
                                    (make-vect 1 0))]))
(def diamond-painter
  (segments->painter [(make-segment (make-vect 0.5 0)
                                    (make-vect 1 0.5))
                      (make-segment (make-vect 1 0.5)
                                    (make-vect 0.5 1))
                      (make-segment (make-vect 0.5 1)
                                    (make-vect 0 0.5))
                      (make-segment (make-vect 0 0.5)
                                    (make-vect 0.5 0))]))
(def wave-painter
  (segments->painter [;; head
                      (make-segment (make-vect 0.4 0)
                                    (make-vect 0.3 0.2))
                      (make-segment (make-vect 0.3 0.2)
                                    (make-vect 0.4 0.4))
                      (make-segment (make-vect 0.6 0)
                                    (make-vect 0.7 0.2))
                      (make-segment (make-vect 0.7 0.2)
                                    (make-vect 0.6 0.4))
                      ;; legs
                      (make-segment (make-vect 0.4 1)
                                    (make-vect 0.5 0.8))
                      (make-segment (make-vect 0.6 1)
                                    (make-vect 0.5 0.8))
                      (make-segment (make-vect 0.2 1)
                                    (make-vect 0.3 0.8))
                      (make-segment (make-vect 0.8 1)
                                    (make-vect 0.7 0.8))
                      ;; left arm
                      (make-segment (make-vect 0 0.2)
                                    (make-vect 0.2 0.4))
                      (make-segment (make-vect 0 0.4)
                                    (make-vect 0.2 0.6))
                      ;; right arm
                      (make-segment (make-vect 1 0.8)
                                    (make-vect 0.8 0.6))
                      (make-segment (make-vect 1 0.6)
                                    (make-vect 0.8 0.4))
                      ;; body
                      (make-segment (make-vect 0.2 0.4)
                                    (make-vect 0.4 0.4))
                      (make-segment (make-vect 0.6 0.4)
                                    (make-vect 0.8 0.4))
                      (make-segment (make-vect 0.2 0.6)
                                    (make-vect 0.3 0.6))
                      (make-segment (make-vect 0.8 0.6)
                                    (make-vect 0.7 0.6))
                      (make-segment (make-vect 0.3 0.6)
                                    (make-vect 0.3 0.8))
                      (make-segment (make-vect 0.7 0.6)
                                    (make-vect 0.7 0.8))]))

outline-painter

(render (outline-painter identity-frame))

x-painter

(render (x-painter identity-frame))

diamond-painter

(render (diamond-painter identity-frame))

wave-painter

(render (wave-painter identity-frame))
 
(ns sicp.chpt2.ex2-50
  (:use [sicp.chpt2.ex2-46 :only [make-vect
                                  sub-vect]]
        [sicp.chpt2.ex2-47 :only [make-frame]]
        [sicp.chpt2.ex2-49 :only [frame-coord-map
                                  identity-frame
                                  wave-painter
                                  render]]))
(defn transform-painter
  [painter origin corner1 corner2]
  (fn [frame]
    (let [m (frame-coord-map frame)
          new-origin (m origin)]
      (painter
       (make-frame new-origin
                   (sub-vect (m corner1) new-origin)
                   (sub-vect (m corner2) new-origin))))))
(defn flip-vert
  [painter]
  (transform-painter painter
                     (make-vect 0 1)
                     (make-vect 1 1)
                     (make-vect 0 0)))
(defn flip-horiz
  [painter]
  (transform-painter painter
                     (make-vect 1 0)
                     (make-vect 0 0)
                     (make-vect 1 1)))
(defn rotate90
  [painter]
  (transform-painter painter
                     (make-vect 0 1)
                     (make-vect 0 0)
                     (make-vect 1 1)))
(defn rotate180
  [painter]
  (transform-painter painter
                     (make-vect 1 1)
                     (make-vect 0 1)
                     (make-vect 1 0)))
(defn rotate270
  [painter]
  (transform-painter painter
                     (make-vect 1 0)
                     (make-vect 1 1)
                     (make-vect 0 0)))

alternative implementations

(def rotate180
  (comp rotate90 rotate90))
(def rotate270
  (comp rotate180 rotate90))

flip-vert

(render ((flip-vert wave-painter) identity-frame))

flip-horiz

(render ((flip-horiz wave-painter) identity-frame))

rotate90

(render ((rotate90 wave-painter) identity-frame))

rotate180

(render ((rotate180 wave-painter) identity-frame))

rotate270

(render ((rotate270 wave-painter) identity-frame))
 
(ns sicp.chpt2.ex2-51
  (:use [sicp.chpt2.ex2-46 :only [make-vect]]
        [sicp.chpt2.ex2-48 :only [make-segment]]
        [sicp.chpt2.ex2-49 :only [render
                                  chain
                                  identity-frame
                                  wave-painter]]
        [sicp.chpt2.ex2-50 :only [transform-painter
                                  rotate90
                                  rotate270]]))
(defn beside
  [painter1 painter2]
  (let [paint-left (transform-painter painter1
                                      (make-vect 0 0)
                                      (make-vect 0.5 0)
                                      (make-vect 0 1))
        paint-right (transform-painter painter2
                                       (make-vect 0.5 0)
                                       (make-vect 1 0)
                                       (make-vect 0.5 1))]
    (fn [frame]
      (chain (paint-left frame)
             (paint-right frame)))))
(defn below
  [painter1 painter2]
  (let [paint-top (transform-painter painter1
                                     (make-vect 0 0)
                                     (make-vect 1 0)
                                     (make-vect 0 0.5))
        paint-bottom (transform-painter painter2
                                        (make-vect 0 0.5)
                                        (make-vect 1 0.5)
                                        (make-vect 0 1))]
    (fn [frame]
      (chain (paint-top frame)
             (paint-bottom frame)))))
(defn below
  [painter1 painter2]
  (rotate270
   (beside (rotate90 painter1)
           (rotate90 painter2))))

beside

(render ((beside wave-painter wave-painter) identity-frame))

below

(render ((below wave-painter wave-painter) identity-frame))
 
(ns sicp.chpt2.ex2-52
  (:use [sicp.chpt2.ex2-45 :only [up-split right-split]]
        [sicp.chpt2.ex2-46 :only [make-vect]]
        [sicp.chpt2.ex2-48 :only [make-segment]]
        [sicp.chpt2.ex2-49 :only [render
                                  chain
                                  identity-frame
                                  segments->painter
                                  wave-painter]]
        [sicp.chpt2.ex2-50 :only [flip-vert flip-horiz rotate180]]
        [sicp.chpt2.ex2-51 :only [beside below]]))
(defn dance-painter
  [frame]
  (let [face-painter (segments->painter [(make-segment (make-vect 0.35 0.3)
                                                       (make-vect 0.45 0.3))
                                         (make-segment (make-vect 0.3 0.15)
                                                       (make-vect 0.4 0.15))])]
    (chain (wave-painter frame)
           (face-painter frame))))
(defn corner-split
  [painter n]
  (if (zero? n)
    painter
    (let [up (up-split painter (dec n))
          right (right-split painter (dec n))
          corner (corner-split painter (dec n))]
      (beside (below painter up)
              (below right corner)))))
(defn square-of-four
  [tl tr bl br]
  (fn [painter]
    (let [top (beside (tl painter)
                      (tr painter))
          bottom (beside (bl painter)
                         (br painter))]
      (below bottom top))))
(defn square-limit
  [painter n]
  (let [combine4 (square-of-four flip-vert rotate180
                                 identity flip-horiz)]
    (combine4 (corner-split painter n))))

dance-painter

(render (dance-painter identity-frame))

corner-split

(render ((corner-split dance-painter 3) identity-frame))

square-limit

(render ((square-limit dance-painter 3) identity-frame))
 
(ns sicp.chpt2.ex2-53)

car is the same as first while cdr is the same as rest, cadr can be replaced by (comp first rest)

(defn memq
  [s l]
  (cond
   (empty? l)
   false
   (= s (first l))
   l
   :else
   (recur s (rest l))))
(list 'a 'b 'c)
=> (a b c)
(list (list 'george))
=> ((george))
(rest '((x1 x2) (y1 y2)))
=> ((y1 y2))
((comp first rest) '((x1 x2) (y1 y2)))
=> (y1 y2)
(coll? (first '(a short list)))
=> false
(memq 'red '((red shoes) (blue socks)))
=> false
(memq 'red '(red shoes blue socks))
=> (red shoes blue socks)
 
(ns sicp.chpt2.ex2-54)
(defn equal?
  [l1 l2]
  (cond
   (and (symbol? l1)
        (symbol? l2))
   (= l1 l2)
   (or (symbol? l1)
       (symbol? l2))
   false
   (and (empty? l1)
        (empty? l2))
   true
   (or (empty? l1)
       (empty? l2))
   false
   :else
   (and (equal? (first l1) (first l2))
        (recur (rest l1) (rest l2)))))
(equal? '((a b c) d (e f g))
        '((a b c) d (e f g)))
=> true
(equal? '(a b)
        '(a b c))
=> false
 
(ns sicp.chpt2.ex2-55)

' expands to (quote ?) where ? is whatever immediately follows '

'x is equivalent to (quote x)

''abracadabra expands to (quote (quote abracadabra)) and resolves to (quote abracadabra)

`(first ''abracadabra)`
=> `quote`
 
(ns sicp.chpt2.ex2-56
  (:use [sicp.chpt1.ex1-16 :only [fast-expt]]))
(defn variable?
  [e]
  (symbol? e))
(defn same-variable?
  [v1 v2]
  (= v1 v2))
(defn sum?
  [e]
  (and (coll? e)
       (= (first e) '+)))
(defn addend
  [e]
  (nth e 1))
(defn augend
  [e]
  (nth e 2))
(defn =number?
  [exp num]
  (and (number? exp)
       (= exp num)))
(defn make-sum
  [a1 a2]
  (cond (=number? a1 0)
        a2
        (=number? a2 0)
        a1
        (and (number? a1) (number? a2))
        (+ a1 a2)
        :else
        ['+ a1 a2]))
(defn product?
  [e]
  (and (coll? e)
       (= (first e) '*)))
(defn multiplier
  [e]
  (nth e 1))
(defn multiplicand
  [e]
  (nth e 2))
(defn make-product
  [m1 m2]
  (cond (or (=number? m1 0)
            (=number? m2 0))
        0
        (=number? m1 1)
        m2
        (=number? m2 1)
        m1
        (and (number? m1) (number? m2))
        (* m1 m2)
        :else
        ['* m1 m2]))
(defn exponentiation?
  [exp]
  (and (coll? exp)
       (= '** (first exp))))
(defn base
  [exp]
  (nth exp 1))
(defn exponent
  [exp]
  (nth exp 2))
(defn make-exponentiation
  [b e]
  (cond (=number? e 0)
        1
        (=number? e 1)
        b
        (and (number? b) (number? e))
        (fast-expt b e)
        :else
        ['** b e]))
(defn deriv
  [exp var]
  (cond (number? exp)
        0
        (variable? exp)
        (if (same-variable? exp var) 1 0)
        (sum? exp)
        (make-sum (deriv (addend exp) var)
                  (deriv (augend exp) var))
        (product? exp)
        (make-sum
         (make-product (multiplier exp)
                       (deriv (multiplicand exp) var))
         (make-product (deriv (multiplier exp) var)
                       (multiplicand exp)))
        (exponentiation? exp)
        (make-product
         (make-product (exponent exp)
                       (make-exponentiation (base exp)
                                            (make-sum (exponent exp)
                                                      -1)))
         (deriv (base exp) var))
        :else
        (throw (Exception. (str "unknown expression type -- DERIV " exp)))))
(deriv '(+ (* x y) (** x 2)) 'x)
=> [+ y [* 2 x]]
(deriv '(+ y (* 2 x)) 'x)
=> 2
(deriv '2 'x)
=> 0
 
(ns sicp.chpt2.ex2-57
  (:require [sicp.chpt2.ex2-56 :as ex2-56]))
(defn augend
  [e]
  (if (> (count e) 3)
    (conj (drop 2 e) '+)
    (nth e 2)))
(defn multiplicand
  [e]
  (if (> (count e) 3)
    (conj (drop 2 e) '*)
    (nth e 2)))

with-redefs rebinds the functions for all threads in it's context. An alternative would be to use binding and mark ex2-56/augend and ex2-56/multiplicand dynamic

(defn deriv
  [exp var]
  (with-redefs [ex2-56/augend augend
                ex2-56/multiplicand multiplicand]
    (ex2-56/deriv exp var)))
(deriv '(+ x x x) 'x)
=> 3
(deriv '(* x x x) 'x)
=> [+ [* x [+ x x]] (* x x)]
 
(ns sicp.chpt2.ex2-58
  (:require [sicp.chpt2.ex2-56 :as ex2_56])
  (:use [sicp.chpt1.ex1-16 :only [fast-expt]]))

a sum is a sequence containing a +, similarly a product contains a *

the addend/multiplier consists of all terms to the first occurrence of the operator and the augend/multiplicand, the remaining terms

exponentiation is right-associative unlike addition and multiplication, so the base consists of all terms to the last occurrence of ** and the exponent, the remaining terms

to handle precedence, check for the operator with the lowest precedence first, + first, then * and finally **

(defn single?
  [e]
  (and (coll? e)
       (= 1 (count e))))
(defn sum?
  [e]
  (and (coll? e)
       (some #{'+} e)))
(defn addend
  [e]
  (let [a (take-while (complement #{'+}) e)]
    (if (single? a) (first a) a)))
(defn augend
  [e]
  (let [a (rest (drop-while (complement #{'+}) e))]
    (if (single? a) (first a) a)))
(defn make-sum
  [a1 a2]
  (cond (ex2_56/=number? a1 0)
        a2
        (ex2_56/=number? a2 0)
        a1
        (and (number? a1) (number? a2))
        (+ a1 a2)
        :else
        [a1 '+ a2]))
(defn product?
  [e]
  (and (coll? e)
       (some #{'*} e)))
(defn multiplier
  [e]
  (let [m (take-while (complement #{'*}) e)]
    (if (single? m) (first m) m)))
(defn multiplicand
  [e]
  (let [m (rest (drop-while (complement #{'*}) e))]
    (if (single? m) (first m) m)))
(defn make-product
  [m1 m2]
  (cond (or (ex2_56/=number? m1 0)
            (ex2_56/=number? m2 0))
        0
        (ex2_56/=number? m1 1)
        m2
        (ex2_56/=number? m2 1)
        m1
        (and (number? m1) (number? m2))
        (* m1 m2)
        :else
        [m1 '* m2]))
(defn exponentiation?
  [e]
  (and (coll? e)
       (some #{'**} e)))
(defn base
  [e]
  (let [m (rest (drop-while (complement #{'**}) (reverse e)))]
    (if (single? m) (first m) (reverse m))))
(defn exponent
  [e]
  (let [m (take-while (complement #{'**}) (reverse e))]
    (if (single? m) (first m) (reverse m))))
(defn make-exponentiation
  [b e]
  (cond (ex2_56/=number? e 0)
        1
        (ex2_56/=number? e 1)
        b
        (and (number? b) (number? e))
        (fast-expt b e)
        :else
        [b '** e]))
(defn deriv
  [exp var]
  (with-redefs [ex2_56/sum? sum?
                ex2_56/addend addend
                ex2_56/augend augend
                ex2_56/make-sum make-sum
                ex2_56/product? product?
                ex2_56/multiplier multiplier
                ex2_56/multiplicand multiplicand
                ex2_56/make-product make-product
                ex2_56/exponentiation? exponentiation?
                ex2_56/base base
                ex2_56/exponent exponent
                ex2_56/make-exponentiation make-exponentiation]
    (ex2_56/deriv exp var)))
(deriv '(x ** 2 + x * x) 'x)
=> [[2 * x] + [x + x]]
(deriv '(x ** 2 ** 3) 'x)
=> [[3 * [(x ** 2) ** 2]] * [2 * x]]
 
(ns sicp.chpt2.ex2-59)
(defn element-of-set?
  [x s]
  (cond (empty? s)
        false
        (= x (first s))
        true
        :else
        (recur x (rest s))))
(defn adjoin-set
  [x s]
  (if (element-of-set? x s)
    s
    (conj s x)))
(defn union-set
  [s1 s2]
  (cond (empty? s1)
        s2
        (empty? s2)
        s1
        (element-of-set? (first s1) s2)
        (recur (rest s1) s2)
        :else
        (conj (union-set (rest s1) s2) (first s1))))
(union-set [1 2 3] [4 5 6])
=> [4 5 6 3 2 1]
(union-set [1 2 3] [3 4 5])
=> [3 4 5 2 1]

alternative implementation

(defn union-set
  [s1 s2]
  (reduce #(adjoin-set %2 %1) s1 s2))
(union-set [1 2 3] [4 5 6])
=> [1 2 3 4 5 6]
(union-set [1 2 3] [3 4 5])
=> [1 2 3 4 5]
 
(ns sicp.chpt2.ex2-60
  (:use [sicp.chpt2.ex2-59 :only [element-of-set?]]))

with either representation, element-of-set? works the same way and doesn't need to be reimplemented

ajoin-set no longer needs to check membership

(defn adjoin-set
  [x s]
  (conj s x))
(adjoin-set 2 [1 2 3 1])
=> [1 2 3 1 2]
(adjoin-set 4 [1 2 3 1])
=> [1 2 3 1 4]

intersection-set doesn't change since it's built on top of element-of-set?

(defn intersection-set
  [s1 s2]
  (cond (or (empty? s1) (empty? s2))
        []
        (element-of-set? (first s1) s2)
        (conj (intersection-set (rest s1) s2) (first s1))
        :else
        (recur (rest s1) s2)))
(intersection-set [1 2 3] [4 5 6])
=> []
(intersection-set [1 2 3] [3 4 5])
=> [3]

without removing duplicates, a union of 2 sets is simply their concatenation

(defn union-set
  [s1 s2]
  (concat s1 s2))
(union-set [1 2 3] [4 5 6])
=> [1 2 3 4 5 6]
(union-set [1 2 3] [3 4 5])
=> [1 2 3 3 4 5]

the alternative implementation of union-set using adjoin-set would not need to be reimplemented, the implementation detail of duplicates is contained in adjoin-set

(defn union-set
  [s1 s2]
  (reduce #(adjoin-set %2 %1) s1 s2))
(union-set [1 2 3] [4 5 6])
=> [1 2 3 4 5 6]
(union-set [1 2 3] [3 4 5])
=> [1 2 3 3 4 5]

for applications where a set is required but duplicates are rare and the most common operation is union this implementation is much more performant, adjoin-set is now an \(O(1)\) operation while union-set depends on the implementation of concat which is at worst \(O(n)\)

 
(ns sicp.chpt2.ex2-61)
(defn adjoin-set
  [x s]
  (cond (empty? s)
        (conj s x)
        (< x (first s))
        (conj s x)
        :else
        s))
(adjoin-set 3 '(2 3 4))
=> (2 3 4)
(adjoin-set 1 '(2 3 4))
=> (1 2 3 4)
 
(ns sicp.chpt2.ex2-62)
(defn union-set
  [s1 s2]
  (cond (empty? s1)
        s2
        (empty? s2)
        s1
        (< (first s1) (first s2))
        (conj (union-set (rest s1) s2) (first s1))
        (> (first s1) (first s2))
        (conj (union-set s1 (rest s2)) (first s2))
        :else
        (conj (union-set (rest s1) (rest s2))
              (first s1))))
(union-set '(1 3 5) '(2 3 6))
=> (1 2 3 5 6)
 
(ns sicp.chpt2.ex2-63)

Both tree->list-1 and tree->list-2 walk the tree in order

Each algorithm walks the tree just once and so both take the same number of steps \(O(n)\).

(defrecord Tree [entry left right])
(defn make-tree
  [entry left right]
  (Tree. entry left right))
(defn left-branch
  [tree]
  (.left tree))
(defn right-branch
  [tree]
  (.right tree))
(defn entry
  [tree]
  (.entry tree))
(defn tree->list-1
  [tree]
  (if (nil? tree)
    []
    (concat (tree->list-1 (left-branch tree))
            [(entry tree)]
            (tree->list-1 (right-branch tree)))))
(defn tree->list-2
  [tree]
  (letfn [(copy-to-list
            [t result-list]
            (if (nil? t)
              result-list
              (recur (left-branch t)
                     (conj (copy-to-list (right-branch t) result-list)
                           (entry t)))))]
    (copy-to-list tree ())))

examples from figure 2.16

(def tree-a
  (make-tree 7
             (make-tree 3
                        (make-tree 1 nil nil)
                        (make-tree 5 nil nil))
             (make-tree 9
                        nil
                        (make-tree 11 nil nil))))
(def tree-b
  (make-tree 3
             (make-tree 1 nil nil)
             (make-tree 7
                        (make-tree 5 nil nil)
                        (make-tree 9
                                   nil
                                   (make-tree 11 nil nil)))))
(def tree-c
  (make-tree 5
             (make-tree 3
                        (make-tree 1 nil nil)
                        nil)
             (make-tree 9
                        (make-tree 7 nil nil)
                        (make-tree 11 nil nil))))
(tree->list-1 tree-a)
=> (1 3 5 7 9 11)
(tree->list-1 tree-b)
=> (1 3 5 7 9 11)
(tree->list-1 tree-c)
=> (1 3 5 7 9 11)
(tree->list-2 tree-a)
=> (1 3 5 7 9 11)
(tree->list-2 tree-b)
=> (1 3 5 7 9 11)
(tree->list-2 tree-c)
=> (1 3 5 7 9 11)
 
(ns sicp.chpt2.ex2-64
  (:use [sicp.chpt2.ex2-63 :only [make-tree]]))

list-tree converts a sorted sequence of elements into a balanced binary tree in just one pass over elts, it does this by using partial-tree

partial-tree builds the tree bottom up and in-order, the first element in elts becomes the bottom left leaf node in the whole tree and as the list is "consumed", builds up to the root node.

At the root node, partial-tree uses the remaining elements to build the right branch in the same way.

partial-tree only traverses elts once and so grows linearly with the number of elements.

(declare partial-tree)
(defn list->tree
  [elts]
  (first (partial-tree elts (count elts))))
(defn partial-tree
  [elts n]
  (if (zero? n)
    [nil elts]
    (let [left-size (quot (dec n) 2)
          [left-tree non-left-elts] (partial-tree elts left-size)
          right-size (- n (inc left-size))
          this-entry (first non-left-elts)
          [right-tree remaining-elts] (partial-tree (rest non-left-elts) right-size)]
      [(make-tree this-entry left-tree right-tree) remaining-elts])))

partial-tree avoids counting or partitioning elts to have a runtime of \(O(n)\)

The naive list->tree algorithm partitions the remaining elements at every level and so has a runtime similar to merge-sort, \(O(log _2 n)\)

(defn list->tree-naive
  [elts]
  (when-not (empty? elts)
    (let [pivot (quot (count elts) 2)
          [left-elts [this-entry & right-elts]] (split-at pivot elts)]
      (make-tree this-entry
                 (list->tree left-elts)
                 (list->tree right-elts)))))
 
(ns sicp.chpt2.ex2-65
  (:use [sicp.chpt2.ex2-62 :only [union-set]]
        [sicp.chpt2.ex2-63 :only [tree->list-1]]
        [sicp.chpt2.ex2-64 :only [list->tree]]))

Since tree->list-1, list->tree and union-set/intersection-set are all \(O(n)\), a linear combination of these operations is also \(O(n)\)

intersection of 2 sorted sequences

(defn intersection-set
  [s1 s2]
  (cond (or (empty? s1) (empty? s2))
        ()
        (< (first s1) (first s2))
        (recur (rest s1) s2)
        (> (first s1) (first s2))
        (recur s1 (rest s2))
        :else
        (conj (intersection-set (rest s1) (rest s2))
              (first s1))))
(intersection-set [1 3 5 7 9] [2 3 5 7 8])
=> (3 5 7)
(intersection-set [1 3 5] [2 4 6])
=> ()
(defn union-btree
  [b1 b2]
  (list->tree
   (union-set (tree->list-1 b1)
              (tree->list-1 b2))))
(tree->list-1
 (union-btree (list->tree [1 3 5])
              (list->tree [2 4 6])))
=> (1 2 3 4 5 6)
(defn intersection-btree
  [b1 b2]
  (list->tree
   (intersection-set (tree->list-1 b1)
                     (tree->list-1 b2))))
(tree->list-1
  (intersection-btree (list->tree [1 3 5])
                      (list->tree [2 4 6])))
=> ()
 
(ns sicp.chpt2.ex2-66
  (:refer-clojure :exclude [key])
  (:use [sicp.chpt2.ex2-63 :only [make-tree left-branch right-branch entry]]))

This is similar to element-of-set? where the set was a balanced binary tree except here the tree entries are also compound objects

(defrecord Record [key data])
(defn make-record
  [key data]
  (Record. key data))
(defn key
  [record]
  (.key record))
(defn data
  [record]
  (.data record))
(defn lookup
  [given-key set-of-records]
  (cond (nil? set-of-records)
        nil
        (< given-key (key (entry set-of-records)))
        (recur given-key (left-branch set-of-records))
        (> given-key (key (entry set-of-records)))
        (recur given-key (right-branch set-of-records))
        :else
        (entry set-of-records)))
(def record-tree
  (make-tree (make-record 4 :four)
             (make-tree (make-record 3 :three)
                        (make-tree (make-record 1 :one)
                                   nil
                                   nil)
                        (make-tree (make-record 2 :two)
                                   nil
                                   nil))
             (make-tree (make-record 6 :six)
                        (make-tree (make-record 5 :five)
                                   nil
                                   nil)
                        (make-tree (make-record 7 :seven)
                                   nil
                                   nil))))
(lookup 3 record-tree)
=> #sicp.chpt2.ex2_66.Record{:key 3, :data :three}
(lookup 0 record-tree)
=> nil
 
(ns sicp.chpt2.ex2-67)

Clojure has better alternatives for dynamic dispatch, protocols

(defprotocol CodeNode
  (symbols [this])
  (weight [this]))
(defrecord Leaf [sym w]
  CodeNode
  (symbols [this]
    [(.sym this)])
  (weight [this]
    (.w this)))
(defn make-leaf
  [symbol weight]
  (Leaf. symbol weight))
(defn leaf?
  [this]
  (= (class this) Leaf))
(defrecord CodeTree [left right syms w]
  CodeNode
  (symbols [this]
    (.syms this))
  (weight [this]
    (.w this)))
(defn make-code-tree
  [left right]
  (CodeTree. left
             right
             (concat (symbols left)
                     (symbols right))
             (+ (weight left)
                (weight right))))
(defn left-branch
  [tree]
  (.left tree))
(defn right-branch
  [tree]
  (.right tree))

Both Leaf and CodeTree have their own implementations of weight and symbols which are part of the CodeNode protocol, no conditional switching in the code required

(defn choose-branch
  [bit branch]
  (cond (zero? bit)
        (left-branch branch)
        (= 1 bit)
        (right-branch branch)
        :else
        (throw (RuntimeException. (str "Invalid bit, " bit)))))
(defn decode
  [bits tree]
  (letfn [(decode-1 [bs current-branch]
            (if (empty? bs)
              ()
              (let [next-branch (choose-branch (first bs) current-branch)]
                (if (leaf? next-branch)
                  (conj (decode-1 (rest bs) tree)
                        (first (symbols next-branch)))
                  (recur (rest bs) next-branch)))))]
    (decode-1 bits tree)))

example

(def sample-tree
  (make-code-tree (make-leaf 'A 4)
                  (make-code-tree
                   (make-leaf 'B 2)
                   (make-code-tree (make-leaf 'D 1)
                                   (make-leaf 'C 1)))))
(def sample-message
  [0 1 1 0 0 1 0 1 0 1 1 1 0])
(decode sample-message sample-tree)
=> (A D A B B C A)
 
(ns sicp.chpt2.ex2-68
  (:use [sicp.chpt2.ex2-59 :only [element-of-set?]]
        [sicp.chpt2.ex2-67 :only [left-branch right-branch leaf? symbols sample-tree]]))
(defn encode-symbol
  [sym tree]
  (loop [path [] branch tree]
    (cond (leaf? branch)
          path
          (element-of-set? sym (symbols (left-branch branch)))
          (recur (conj path 0) (left-branch branch))
          (element-of-set? sym (symbols (right-branch branch)))
          (recur (conj path 1) (right-branch branch))
          :else
          (throw (RuntimeException. (str "Symbol not in tree, " sym))))))
(defn encode
  [message tree]
  (if (empty? message)
    []
    (concat (encode-symbol (first message) tree)
            (encode (rest message) tree))))
(encode '(A D A B B C A) sample-tree)
=> (0 1 1 0 0 1 0 1 0 1 1 1 0)
 
(ns sicp.chpt2.ex2-69
  (:use [sicp.chpt2.ex2-67 :only [weight make-code-tree make-leaf decode]]
        [sicp.chpt2.ex2-68 :only [encode]]))

implementing more declarative versions of both adjoin-set and make-leaf-set

(defn adjoin-set
  [x s]
  (let [[smaller larger] (split-with #(< (weight %) (weight x)) s)]
    (concat smaller (conj larger x))))
(defn make-leaf-set
  [leaves]
  (reduce #(adjoin-set %2 %1) () leaves))
(defn successive-merge
  [leaf-set]
  (if (= 1 (count leaf-set))
    (first leaf-set)
    (recur (adjoin-set (make-code-tree (second leaf-set)
                                       (first leaf-set))
                       (drop 2 leaf-set)))))
(defn generate-huffman-tree
  [leaves]
  (successive-merge (make-leaf-set leaves)))
(def tree
  (generate-huffman-tree [(make-leaf 'A 8)
                          (make-leaf 'B 4)
                          (make-leaf 'D 1)
                          (make-leaf 'C 1)]))
(decode [0 1 1 0 0 1 0 1 0 1 1 1 0] tree)
=> (A D A B B C A)
(encode '(A D A B B C A) tree)
=> (0 1 1 0 0 1 0 1 0 1 1 1 0)
 
(ns sicp.chpt2.ex2-70
  (:use [sicp.chpt2.ex2-67 :only [make-leaf decode]]
        [sicp.chpt2.ex2-68 :only [encode]]
        [sicp.chpt2.ex2-69 :only [generate-huffman-tree]]))
(def rock-tree
  (generate-huffman-tree [(make-leaf 'A 2)
                          (make-leaf 'BOOM 1)
                          (make-leaf 'GET 2)
                          (make-leaf 'JOB 2)
                          (make-leaf 'NA 16)
                          (make-leaf 'SHA 3)
                          (make-leaf 'YIP 9)
                          (make-leaf 'WAH 1)]))
(encode '[GET A JOB
          SHA NA NA NA NA NA NA NA NA
          GET A JOB
          SHA NA NA NA NA NA NA NA NA
          WAH YIP YIP YIP YIP YIP YIP YIP YIP YIP
          SHA BOOM]
        rock-tree)
=> (0 0 0 0 1 0 0 0  0 0 0 0 1 0 0 0
    0 1 1 1 1 1 1 1  1 1 0 0 0 0 1 0
    0 0 0 0 0 0 1 0  0 0 0 1 1 1 1 1
    1 1 1 1 0 0 1 1  1 0 1 0 1 0 1 0
    1 0 1 0 1 0 1 0  1 0 1 0 0 0 1 0
    0 1 1 0)

With the huffman tree, the encoded message length is 84 bits. With a fixed length code you'd need 3 bits to uniquely represent all 8 words and the total message length would be 108 bits

 
(ns sicp.chpt2.ex2-71)

for \(n=5\), most frequent takes 1 bit, least frequent takes 4

-0-16
|
1
|
-0-8
|
1
|
-0-4
|
1
|
-0-2
|
1
|
1

for \(n=10\), most frequent takes 1 bit, least frequent takes 9

-0-512
|
1
|
-0-256
|
1
|
-0-128
|
1
|
-0-64
|
1
|
-0-32
|
1
|
-0-16
|
1
|
-0-8
|
1
|
-0-4
|
1
|
-0-2
|
1
|
1

for such trees in general and for \(n\) symbols, the most frequent symbol requires 1 bit, while the least frequent symbol requires \(n-1\) bits

 
(ns sicp.chpt2.ex2-72)

element-of-set? is used to determine which branch to traverse

In the trees from ex 2.71, the most frequent symbol requires 1 branch lookup and the least frequent requires \(n-1\) branch lookups where \(n\) is the number of symbols in the tree

Since the symbol-sets are implemented as lists in this case, branch lookups are \(O(n)\) and encoding a symbol is \(O(n^{2})\) for the least frequent symbol

 
(ns sicp.chpt2.ex2-73
  (:refer-clojure :exclude [get])
  (:use [sicp.chpt2.ex2-56 :only [variable?
                                  same-variable?
                                  make-sum
                                  make-product
                                  make-exponentiation]]))

number? and same-variable don't dispatch on a particular operator and so can't be used with the data-directed approach

Clojure is opinionated about mutable state and controls access to it through atoms, refs and agents

(def dispatch-table (atom {}))
(defn put
  [op type item]
  (swap! dispatch-table assoc-in [op type] item))
(defn get
  [op type]
  (get-in @dispatch-table [op type] false))
(defn operator
  [exp]
  (first exp))
(defn operands
  [exp]
  (rest exp))
(defn deriv
  [exp var]
  (cond (number? exp)
        0
        (variable? exp)
        (if (same-variable? exp var) 1 0)
        :else
        ((get 'deriv (operator exp)) (operands exp) var)))
(defn addend
  [ops]
  (first ops))
(defn augend
  [ops]
  (if (< 2 (count ops))
    (conj (rest ops) '+)
    (second ops)))
(defn sum-deriv
  [ops var]
  (make-sum (deriv (addend ops) var)
            (deriv (augend ops) var)))
(defn multiplier
  [ops]
  (first ops))
(defn multiplicand
  [ops]
  (if (< 2 (count ops))
    (conj (rest ops) '*)
    (second ops)))
(defn product-deriv
  [ops var]
  (make-sum
   (make-product (multiplier ops)
                 (deriv (multiplicand ops) var))
   (make-product (deriv (multiplier ops) var)
                 (multiplicand ops))))

install sum and product

(put 'deriv '+ sum-deriv)
(put 'deriv '* product-deriv)
(deriv '(+ x x x) 'x)
=> 3
(deriv '(* x x x) 'x)
=> [+ [* x [+ x x]] (* x x)]
(defn base
  [ops]
  (first ops))
(defn exponent
  [ops]
  (if (< 2 (count ops))
    (conj (rest ops) '**)
    (second ops)))
(defn exponent-deriv
  [ops var]
  (make-product
   (make-product (exponent ops)
                 (make-exponentiation (base ops)
                                      (make-sum (exponent ops)
                                                -1)))
   (deriv (base ops) var)))

install exponent

(put 'deriv '** exponent-deriv)
(deriv '(+ (* x y) (** x 2)) 'x)
=> [+ y [* 2 x]]

changing the order of the arguments to get would only require that to be reflected in put

(put 'deriv '+ sum-deriv) to (put '+ 'deriv sum-deriv)

It doesn't matter how the function is stored as long as its accessed the same way

alternative implementation

Clojure does have its own take on polymorphic dispatch using multimethods, the same problem can be solved without an explicit dispatch table

(defmulti deriv-multi (fn [op _ _] op))
(defn deriv
  [exp var]
  (cond (number? exp)
        0
        (variable? exp)
        (if (same-variable? exp var) 1 0)
        :else
        (deriv-multi (operator exp) (operands exp) var)))
(defmethod deriv-multi '+
  [_ ops var]
  (sum-deriv ops var))
(defmethod deriv-multi '*
  [_ ops var]
  (product-deriv ops var))
(defmethod deriv-multi '**
  [_ ops var]
  (exponent-deriv ops var))
(deriv '(+ x x x) 'x)
=> 3
(deriv '(* x x x) 'x)
=> [+ [* x [+ x x]] (* x x)]
(deriv '(+ (* x y) (** x 2)) 'x)
=> [+ y [* 2 x]]
 
(ns sicp.chpt2.ex2-74
  (:refer-clojure :exclude [get])
  (:use [sicp.chpt2.ex2-73 :only [get put]]))

defining apply-generic

(defn apply-generic
  [op & args]
  (apply (get op (type (first args))) args))

Each file would need to store the type information of how its data is structured. For this solution, I'm using clojure records to store both the type information and the data

EmployeeList stores records in a list of vectors with the format [name record]

(defrecord EmployeeList [employees])
(defn get-record-list
  [employee-list name]
  (some (fn [[n rec]]
          (when (= n name)
            rec))
        (.employees employee-list)))

EmployeeMap stores records in a hash-map with employee names as keys and the records as values

(defrecord EmployeeMap [employees])
(defn get-record-map
  [employee-map name]
  ((.employees employee-map) name))

Installing get-record for both types

(put 'get-record EmployeeList #'get-record-list)
(put 'get-record EmployeeMap #'get-record-map)
(defn get-record
  [employees name]
  (apply-generic 'get-record employees name))
(defrecord AbbreviatedEmployee [n s a])
(defrecord DetailedEmployee [name salary address])
(def employee-a
  (AbbreviatedEmployee. "Alpha" 100 "Argentina"))
(def employee-b
  (AbbreviatedEmployee. "Bravo" 200 "Brazil"))
(def employee-c
  (DetailedEmployee. "Charlie" 300 "Chile"))
(def employee-list
  (EmployeeList. [["Alpha" employee-a]
              ["Bravo" employee-b]]))
(def employee-map
  (EmployeeMap. {"Charlie" employee-c}))
(get-record employee-list "Alpha")
=> #sicp.chpt2.ex2_74.AbbreviatedEmployee{:n "Alpha", :s 100, :a "Argentina"}
(get-record employee-map "Charlie")
=> #sicp.chpt2.ex2_74.DetailedEmployee{:name "Charlie", :salary 300, :address "Chile"}
(defn get-salary-abbr
  [employee]
  (.s employee))
(defn get-salary-detailed
  [employee]
  (.salary employee))

Installing get-salary for both types

(put 'get-salary AbbreviatedEmployee #'get-salary-abbr)
(put 'get-salary DetailedEmployee #'get-salary-detailed)
(defn get-salary
  [employee]
  (apply-generic 'get-salary employee))
(get-salary employee-b)
=> 200
(get-salary employee-c)
=> 300
(defn find-employee-record
  [files name]
  (some #(get-record % name) files))
(find-employee-record [employee-list employee-map] "Bravo")
=> #sicp.chpt2.ex2_74.AbbreviatedEmployee{:n "Bravo", :s 200, :a "Brazil"}
(find-employee-record [employee-list employee-map] "Charlie")
=> #sicp.chpt2.ex2_74.DetailedEmployee{:name "Charlie", :salary 300, :address "Chile"}

When Insatiable takes over a new company, the company must expose functions which map to Insatiable's employee functions.

These functions can then be installed just like get-employees-map and get-employees-list

alternative implementation

Multimethods would work here too, with a dispatch function on type

When you need to dispatch on type, Clojure provides an alternative, more efficient dispatch mechanism, protocols

(defprotocol EmployeeFile
  (get-record [this name]))
(extend-type EmployeeList
  EmployeeFile
  (get-record [this name]
    (get-record-list this name)))
(extend-type EmployeeMap
  EmployeeFile
  (get-record [this name]
    (get-record-map this name)))
(get-record employee-list "Alpha")
=> #sicp.chpt2.ex2_74.AbbreviatedEmployee{:n "Alpha", :s 100, :a "Argentina"}
(get-record employee-map "Charlie")
=> #sicp.chpt2.ex2_74.DetailedEmployee{:name "Charlie", :salary 300, :address "Chile"}
(defprotocol Employee
  (get-salary [this]))
(extend-type AbbreviatedEmployee
  Employee
  (get-salary [this]
    (.s this)))
(extend-type DetailedEmployee
  Employee
  (get-salary [this]
    (.salary this)))
(get-salary employee-b)
=> 200
(get-salary employee-c)
=> 300

find-employee-record requires no changes

(find-employee-record [employee-list employee-map] "Bravo")
=> #sicp.chpt2.ex2_74.AbbreviatedEmployee{:n "Bravo", :s 200, :a "Brazil"}
(find-employee-record [employee-list employee-map] "Charlie")
=> #sicp.chpt2.ex2_74.DetailedEmployee{:name "Charlie", :salary 300, :address "Chile"}

In this case, all the new company would have to do is extend the EmployeeFile protocol to their file implementation and the Employee protocol to their record implementation

 
(ns sicp.chpt2.ex2-75)

returning a map since clojure maps are functions of their keys

(defn make-from-mag-ang
  [mag ang]
  (let [dispatch {'real-part (* mag (Math/cos ang))
                  'imag-part (* mag (Math/sin ang))
                  'magnitude mag
                  'angle ang}]
    dispatch))
(defn apply-generic
  [op arg]
  (arg op))
(apply-generic 'real-part (make-from-mag-ang 10 (/ Math/PI 4)))
=> 7.0710678118654755
(apply-generic 'imag-part (make-from-mag-ang 10 (/ Math/PI 4)))
=> 7.0710678118654755
(apply-generic 'magnitude (make-from-mag-ang 10 (/ Math/PI 4)))
=> 10
(apply-generic 'angle (make-from-mag-ang 10 (/ Math/PI 4)))
=> 0.7853981633974483
 
(ns sicp.chpt2.ex2-76)

Explicit dispatch requires every user of each implementation to update their code to handle the new type or operation, there is no simple way to determine whether a type or operation is supported

In the data-directed style, adding a new operation or type requires a new entry in the global lookup table. This can be done with an explicit installation function for the type or the operation.

With message passing, new operations need to be added to the dispatch function in every type constructor where they're to be supported. A new type, on the other hand, is trivial to add with no change to any existing code or global state.

In a system where new types are added often, message passing makes the most sense since the impact on the existing system is minimal. If new operations are added more frequently, the data directed approach is preferable.