SICP in Clojure: Chapter 2 (part 1)
Going on with my study of SICP, this is the first part of chapter 2 (that is a very big chapter and also has a lot of great examples). I also updated the code in the first chapter for some issues with chapter 2 names that were replicated (I made some private definitions there to use refer all here).
The painter example of this book was really cool and actually you can create a painter with Quil library if you want to see it works.
The painter example of this book was really cool and actually you can create a painter with Quil library if you want to see it works.
(ns sicp.chapter-2 (:require [sicp.chapter-1 :refer :all])) ;Common functions (defn null? [l] (and (seq? l) (empty? l))) ;Chapther 2: Building Abstractions with Data (defn linear-combination [a b x y] (+ (* a x) (* b y))) (declare add mul) (defn linear-combination [a b x y] (add (mul a x) (mul b y))) ;Chapter 2.1.1 (declare make-rat numer denom) (defn add-rat [x y] (make-rat (+ (* (numer x) (denom y)) (* (numer y) (denom x))) (* (denom x) (denom y)))) (defn sub-rat [x y] (make-rat (- (* (numer x) (denom y)) (* (numer y) (denom x))) (* (denom x) (denom y)))) (defn mul-rat [x y] (make-rat (* (numer x) (numer y)) (* (denom x) (denom y)))) (defn div-rat [x y] (make-rat (* (numer x) (denom y)) (* (denom x) (numer y)))) (defn equal-rat? [x y] (= (* (numer x) (denom y)) (* (numer y) (denom x)))) (def x (cons 1 [2])) (first x) (second x) (def x (cons 1 [2])) (def y (cons 3 [4])) (def z (cons x (cons y []))) (first (first z)) (first (second z)) (defn make-rat [x y] (cons x [y])) (def numer first) (def denom second) (defn print-rat [x] (println "") (println (str (numer x) "/" (denom x)))) (def one-half (make-rat 1 2)) (print-rat one-half) (def one-third (make-rat 1 3)) (print-rat (add-rat one-half one-third)) (print-rat (mul-rat one-half one-third)) (print-rat (add-rat one-third one-third)) (defn make-rat [n d] (let [g (gcd n d)] (cons (/ n g) [(/ d g)]))) (print-rat (add-rat one-third one-third)) (defn make-rat [n d] (cons n [d])) (defn numer [x] (let [g (gcd (first x) (second x))] (/ (first x) g))) (defn denom [x] (let [g (gcd (first x) (second x))] (/ (second x) g))) (print-rat (add-rat one-third one-third)) (defn cons [x y] (letfn [(dispatch [m] (cond (= m 0) x (= m 1) y :else (println "Argument not 0 or 1: CONS" m)))] dispatch)) (defn car [z] (z 0)) (defn cdr [z] (z 1)) ;Exercise 2.4 (defn cons [x y] #(% x y)) (defn car [z] (z (fn [p q] p))) (defn cdr [z] (z (fn [p q] q))) ;Exercise 2.6 (def zero (fn [f] (fn [x] x))) (defn add-1 [n] (fn [f] (fn [x] (f (n f) x)))) ;Chapters 2.1.4 (declare 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)))) (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 (/ 1.0 (upper-bound y)) (/ 1.0 (lower-bound y))))) ;Exercise 2.7 (defn make-interval [a b] (cons a [b])) (defn upper-bound [x] (first x)) (defn lower-bound [x] (second x)) ;Exercise 2.11 (defn make-center-width [c w] (make-interval (- c w) (+ c w))) (defn center [i] (/ (+ (lower-bound i) (upper-bound i)) 2)) (defn width [i] (/ (- (upper-bound i) (lower-bound i)) 2)) ;Exercise 2.13 (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))))) ;Chapter 2.2.1 (def cons clojure.core/cons) (cons 1 (cons 2 (cons 3 (cons 4 nil)))) (list 1 2 3 4) (def one-through-four (list 1 2 3 4)) (first one-through-four) ;first instead of car (rest one-through-four) ;rest instead of car (first (rest one-through-four)) (cons 10 one-through-four) (cons 5 one-through-four) ;List Operations (defn list-ref [items n] (if (= n 0) (first items) (list-ref (rest items) (- n 1)))) (def squares (list 1 4 9 16 25)) (list-ref squares 3) (defn length [items] (if (empty? items) 0 (+ 1 (length (rest items))))) (def odds (list 1 3 5 7)) (length odds) (defn length [items] (letfn [(length-iter [a count] (if (empty? a) count (length-iter (rest a) (+ 1 count))))] (length-iter items 0))) (defn append [list1 list2] (if (empty? list1) list2 (cons (first list1) (append (rest list1) list2)))) (append squares odds) (append odds squares) ;Exercise 2.19 (def us-coins (list 50 25 10 5 1)) (def uk-coins (list 100 50 20 10 5 2 1 0.5)) (declare no-more? except-first-denomination) (defn cc2-19 [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)))) ;Exercise 2.20 (comment (defn fn-name [ & <parameters>] <body>) (def f (fn [x y & z] <body>)) (def g (fn [& w] <body>))) ;Mapping over a list (defn scale-list [items factor] (if (empty? items) nil (cons (* (first items) factor) (scale-list (rest items) factor)))) (scale-list (list 1 2 3 4 5) 10) (defn map-ex [proc items] (if (empty? items) nil (cons (proc (first items)) (map-ex proc (rest items))))) (map-ex abs (list -10 2.5 -11.6 17)) (map #(* % %) (list 1 2 3 4)) (defn scale-list [items factor] (map #(* % factor) items)) ;Exercise 2.21 (declare <??>) (defn square-list [items] (if (empty? items) nil (cons <??> <??>))) (defn square-list [items] (map <??> <??>)) ;Exercise 2.22 (defn square-list [items] (letfn [(iter [things answer] (if (empty? things) answer (iter (rest things) (concat (square (rest things)) answer))))] (iter items nil))) (defn square-list [items] (letfn [(iter [things answer] (if (empty? things) answer (iter (rest things) (cons answer (concat (rest things))))))] (iter items nil))) ;Exercise 2.23 (def for-each map) (for-each (fn [x] (println "") (println x)) (list 57 321 88)) ;Chapter 2.2.2 (defn count-leaves [x] (cond (and (seq? x) (empty? x)) 0 ((complement seq?) x) 1 :else (+ (count-leaves (first x)) (count-leaves (rest x))))) (cons (list 1 2) (list 3 4)) (def x (cons (list 1 2) (list 3 4))) (length x) (count-leaves x) (list x x) (length (list x x)) (count-leaves (list x x)) ;Exercise 2.26 (def x (list 1 2 3)) (def y (list 4 5 6)) (append x y) (cons x y) (list x y) ;Exercise 2.27 (def x (list (list 1 2) (list 3 4))) x (reverse x) (comment (deep-reverse x)) ;Exercise 2.29 (defn make-mobile [left right] (list left right)) (defn make-branch [length structure] (list length structure)) ;Mapping over trees (defn scale-tree [tree factor] (cond (null? tree) nil ((complement seq?) tree) (* tree factor) :else (cons (scale-tree (first tree) factor) (scale-tree (rest tree) factor)))) (scale-tree (list 1 (list 2 (list 3 4) 5) (list 6 7)) 10) (defn scale-tree [tree factor] (map (fn [sub-tree] (if (seq? sub-tree) (scale-tree sub-tree factor) (* sub-tree factor))) tree)) ;Exercise 2.31 (declare tree-map) (defn square-tree [tree] (tree-map square tree)) ;Exercise 2.32 (defn subsets [s] (if (null? s) (list nil) (let [rest (subsets (rest s))] (concat rest (map <??> rest))))) ;Chapter 2.2.3 (defn sum-odd-squares [tree] (cond (null? tree) 0 (not (seq? tree)) (if (odd? tree) (square tree) 0) :else (+ (sum-odd-squares (first tree)) (sum-odd-squares (rest tree))))) (defn even-fibs [n] (letfn [(next [k] (if (> k n) nil (let [f (fib k)] (if (even? f) (cons f (next (+ k 1))) (next (+ k 1))))))] (next 0))) ;Sequence Operations (map square (list 1 2 3 4 5)) (defn filter [predicate sequence] (cond (null? sequence) nil (predicate (first sequence)) (cons (first sequence) (filter predicate (rest sequence))) :else (filter predicate (rest sequence)))) (filter odd? (list 1 2 3 4 5)) (defn accumulate [op initial sequence] (if (null? sequence) initial (op (first sequence) (accumulate op initial (rest sequence))))) (accumulate + 0 (list 1 2 3 4 5)) (accumulate * 1 (list 1 2 3 4 5)) (accumulate cons nil (list 1 2 3 4 5)) (defn enumerate-interval [low high] (if (> low high) nil (cons low (enumerate-interval (+ low 1) high)))) (enumerate-interval 2 7) (defn enumerate-tree [tree] (cond (null? tree) nil (not (seq? tree)) (list tree) :else (concat (enumerate-tree (first tree)) (enumerate-tree (rest tree))))) (enumerate-tree (list 1 (list 2 (list 3 4)) 5)) (defn sum-odd-squares [tree] (accumulate + 0 (map square (filter odd? (enumerate-tree tree))))) (defn even-fibs [n] (accumulate cons nil (filter even? (map fib (enumerate-interval 0 n))))) (defn list-fib-squares [n] (accumulate cons nil (map square (map fib (enumerate-interval 0 n))))) (list-fib-squares 10) (defn product-of-squares-of-odd-elements [sequence] (accumulate * 1 (map square (filter odd? sequence)))) (product-of-squares-of-odd-elements (list 1 2 3 4 5)) (letfn [(salary [] <??>) (programmer? [] <??>)] (defn salary-of-highest-paid-programmer [records] (accumulate max 0 (map salary (filter programmer? records))))) ;Exercise 2.23 (defn map-2.23 [p sequence] (accumulate (fn [x y] <??> nil sequence))) (defn append-2.23 [seq1 seq2] (accumulate cons <??> <??>)) (defn length-2.23 [sequence] (accumulate <??> 0 sequence)) ;Exercise 2.34 (defn horner-eval [x coefficient-sequence] (accumulate (fn [this-coeff higher-term] <??>) 0 coefficient-sequence)) ;Exercise 2.35 (defn count-leaves-2.35 [t] (accumulate <??> <??> (map <??> <??>))) ;Exercise 2.36 (defn accumulate-n [op init seqs] (if (null? (first seqs)) nil (cons (accumulate op init <??>) (accumulate-n op init <??>)))) ;Exercise 2.37 (defn dot-product [v w] (accumulate + 0 (map * v w))) (defn matrix-*-vector [m v] (map <??> m)) (defn transpose [mat] (accumulate-n <??> <??> mat)) (defn matrix-*-matrix [m n] (let [cols (transpose n)] (map <??> m))) ;Exercise 2.38 (def fold-right accumulate) (defn fold-left [op initial sequence] (letfn [(iter [result rest-seq] (if (null? rest) result (iter (op result (first rest-seq)) (rest rest-seq))))] (iter initial sequence))) (fold-right / 1 (list 1 2 3)) (try (fold-left / 1 (list 1 2 3)) (catch Exception e)) (fold-right list nil (list 1 2 3)) (try (fold-left list nil (list 1 2 3)) (catch StackOverflowError e)) ;Exercise 2.39 (defn reverse-1 [sequence] (fold-right (fn [x y] <??>) nil sequence)) (defn reverse-2 [sequence] (fold-left (fn [x y] <??>) nil sequence)) ;Nested Mappings (let [n 4] (accumulate append nil (map (fn [i] (map (fn [j] (list i j)) (enumerate-interval 1 (- i 1)))) (enumerate-interval 1 n)))) (defn flatmap [proc seq] (accumulate append nil (map proc seq))) (defn prime-sum? [pair] (prime? (+ (first pair) (first (rest pair))))) (defn make-pair-sum [pair] (list (first pair) (first (rest pair)) (+ (first pair) (first (rest pair))))) (defn prime-sum-pairs [n] (map make-pair-sum (filter prime-sum? (flatmap (fn [i] (map (fn [j] (list i j)) (enumerate-interval 1 (- i 1)))) (enumerate-interval 1 n))))) (defn permutations [s] (letfn [(remove [item sequence] (filter (fn [x] (not (= x item))) sequence))] (if (null? s) (list nil) (flatmap (fn [x] (map (fn [p] (cons x p)) (permutations (remove x s)))) s)))) ;Exercise 2.42 (letfn [(empty-board [] <??>) (safe? [] <??>) (adjoin-position [] <??>)] (defn queens [board-size] (letfn [(queen-cols [k] (if (= k 0) (list empty-board) (filter (fn [positions] (safe? k positions)) (flatmap (fn [rest-of-queens] (map (fn [new-row] (adjoin-position new-row k rest-of-queens)) (enumerate-interval 1 board-size))) (queen-cols (- k 1))))))] (queen-cols board-size)))) ;Exercise 2.43 (comment (flatmap (fn [new-row] (map (fn [rest-of-queens] (adjoin-position new-row k rest-of-queens)) (queen-cols (- k 1)))) (enumerate-interval 1 board-size))) ;Chapter 2.2.4 A Picture Language (declare wave beside flip-vert flip-horiz below up-split corner-split sub-vect make-vect add-vect origin-frame draw-line start-segment end-segment) (defn flipped-pairs [painter] (let [painter2 (beside painter (flip-vert painter))] (below painter2 painter2))) (comment (def wave2 (beside wave (flip-vert wave))) (def wave4 (below wave2 wave2)) (def wave4 (flipped-pairs wave))) (defn right-split [painter n] (if (= n 0) painter (let [smaller (right-split painter (- n 1))] (beside painter (below smaller smaller))))) (defn up-split [painter n] (if (= n 0) painter (let [smaller (up-split painter (- n 1))] (below painter (beside smaller smaller))))) (defn corner-split [painter n] (if (= n 0) painter (let [up (up-split painter (- n 1)) right (right-split painter (- n 1))] (let [top-left (beside up up) bottom-right (below right right) corner (corner-split painter (- n 1))] (beside (below painter top-left) (below bottom-right corner)))))) (defn square-limit [painter n] (let [quarter (corner-split painter n)] (let [half (beside (flip-horiz quarter) quarter)] (below (flip-vert half half))))) (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 flipped-pairs [painter] (let [combine4 (square-of-four identity flip-vert identity flip-vert)] (combine4 painter))) (def rotate180 (comp flip-vert flip-horiz)) (defn square-limit [painter n] (let [combine4 (square-of-four flip-horiz identity rotate180 flip-vert)])) (defn frame-coord-map [frame] (fn [v] (add-vect (origin-frame frame)))) ;Exercise 2.47 (defn make-frame [origin edge1 edge2] (list origin edge1 edge2)) ;Painters (defn segments->painter [segment-list] (fn [frame] (for-each (fn [segment] (draw-line ((frame-coord-map frame) (start-segment segment)) ((frame-coord-map frame) (end-segment segment)))) segment-list))) ;Transforming and combining painters (defn transform-painter [painter origin corner1 corner2] (fn [frame] (let [m (frame-coord-map frame)] (let [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.0 1.0) (make-vect 1.0 1.0) (make-vect 0.0 0.0))) (defn shrink-to-upper-right [painter] (transform-painter painter (make-vect 0.5 0.5) (make-vect 1.0 0.5) (make-vect 0.5 1.0))) (defn rotate80 [painter] (transform-painter painter (make-vect 1.0 0.0) (make-vect 1.0 1.0) (make-vect 0.0 0.0))) (defn squash-inwards [painter] (transform-painter painter (make-vect 0.0 0.0) (make-vect 0.65 0.35) (make-vect 0.35 0.65))) (defn beside [painter1 painter2] (let [split-point (make-vect 0.5 0.0)] (let [paint-left (transform-painter painter1 (make-vect 0.0 0.0) split-point (make-vect 0.0 1.0)) paint-right (transform-painter painter2 split-point (make-vect 1.0 0.0) (make-vect 0.5 1.0))] (fn [frame] (paint-left frame) (paint-right frame)))))
You could make it an extremely cool blog post using KLIPSE https://github.com/viebel/klipse
ReplyDeleteMmm cool, I will try to add it on next post by removing dependency on chapter 1 namespace. Thanks
Delete