From 550f8d76eff28b0bef34dc21fef3c4b268061647 Mon Sep 17 00:00:00 2001 From: Denis Smetannikov Date: Sun, 18 Feb 2024 22:03:06 +0400 Subject: [PATCH] Exercise 2.77 and refactor parts of SICP chapter 2's code (#166) * Update progress and add exercise 2.77 in README The number of completed exercises was updated in the progress bar of the README, demonstrating more tasks have been accomplished. Additionally, code related to exercise 2.77 has been added, which covers generic arithmetic operations. * Refactor parts of SICP chapter 2's code The code refactor focused on the parts related to packages in chapter 2 of SICP. It included separating different packages into their own files, implementing a generic operation system, and standardizing the function interface. This has resulted in cleaner, more maintainable, and more understandable code. --- README.md | 6 +- project.clj | 2 +- .../chapter_2/packages/install_complex.clj | 45 ++++++ src/sicp/chapter_2/packages/install_polar.clj | 24 +++ .../chapter_2/packages/install_rational.clj | 44 ++++++ .../packages/install_rectangular.clj | 25 +++ .../packages/install_scheme_number.clj | 17 +++ src/sicp/chapter_2/packages/op_table.clj | 36 +++++ src/sicp/chapter_2/part_4/book_2_4.clj | 13 +- src/sicp/chapter_2/part_5/book_2_5.clj | 143 ++---------------- src/sicp/chapter_2/part_5/ex_2_77.clj | 22 +++ test/sicp/chapter_2/part_5/book_2_5_test.clj | 47 +++--- test/sicp/chapter_2/part_5/ex_2_77_test.clj | 21 +++ 13 files changed, 279 insertions(+), 166 deletions(-) create mode 100644 src/sicp/chapter_2/packages/install_complex.clj create mode 100644 src/sicp/chapter_2/packages/install_polar.clj create mode 100644 src/sicp/chapter_2/packages/install_rational.clj create mode 100644 src/sicp/chapter_2/packages/install_rectangular.clj create mode 100644 src/sicp/chapter_2/packages/install_scheme_number.clj create mode 100644 src/sicp/chapter_2/packages/op_table.clj create mode 100644 src/sicp/chapter_2/part_5/ex_2_77.clj create mode 100644 test/sicp/chapter_2/part_5/ex_2_77_test.clj diff --git a/README.md b/README.md index 2ffcaec..719825f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Clojure CI](https://github.com/SmetDenis/Clojure-Sicp/actions/workflows/main.yml/badge.svg?branch=main)](https://github.com/SmetDenis/Clojure-Sicp/actions/workflows/main.yml) [![Coverage Status](https://coveralls.io/repos/github/SmetDenis/Clojure-SICP/badge.svg?branch=main)](https://coveralls.io/github/SmetDenis/Clojure-SICP?branch=main) -![Progress](https://progress-bar.dev/122/?scale=356&title=Solved&width=500&suffix=) +![Progress](https://progress-bar.dev/123/?scale=356&title=Solved&width=500&suffix=) SICP (Structure and Interpretation of Computer Programs) is the book of Harold Abelson and Gerald Jay Sussman on basics of computer science and software engineering. @@ -43,7 +43,7 @@ Jay Sussman on basics of computer science and software engineering. ### Chapter 2 - Building Abstractions with Data -![Progress](https://progress-bar.dev/76/?scale=97&title=Solved&width=500&suffix=) +![Progress](https://progress-bar.dev/77/?scale=97&title=Solved&width=500&suffix=) * [2.1](https://sarabander.github.io/sicp/html/Chapter-2.xhtml#Chapter-2) Introduction to Data Abstraction - [Code in book](src/sicp/chapter_2/part_1/book_2_1.clj) * [2.1.1](https://sarabander.github.io/sicp/html/2_002e1.xhtml#g_t2_002e1_002e1) Example: Arithmetic Operations for Rational Numbers - [2.1](src/sicp/chapter_2/part_1/ex_2_01.clj) @@ -65,7 +65,7 @@ Jay Sussman on basics of computer science and software engineering. * [2.4.2](https://sarabander.github.io/sicp/html/2_002e4.xhtml#g_t2_002e4_002e2) Tagged data * [2.4.3](https://sarabander.github.io/sicp/html/2_002e4.xhtml#g_t2_002e4_002e3) Data-Directed Programming and Additivity - [2.73](src/sicp/chapter_2/part_4/ex_2_73.clj), [2.74](src/sicp/chapter_2/part_4/ex_2_74.clj), [2.75](src/sicp/chapter_2/part_4/ex_2_75.clj), [2.76](src/sicp/chapter_2/part_4/ex_2_76.clj) * [2.5](https://sarabander.github.io/sicp/html/2_002e5.xhtml#g_t2_002e5) Systems with Generic Operations - [Code in book](src/sicp/chapter_2/part_5/book_2_5.clj) - * [2.5.1](https://sarabander.github.io/sicp/html/2_002e5.xhtml#g_t2_002e5_002e1) Generic Arithmetic Operations + * [2.5.1](https://sarabander.github.io/sicp/html/2_002e5.xhtml#g_t2_002e5_002e1) Generic Arithmetic Operations - [2.77](src/sicp/chapter_2/part_5/ex_2_77.clj) * [2.5.2](https://sarabander.github.io/sicp/html/2_002e5.xhtml#g_t2_002e5_002e2) Combining Data of Different Types * [2.5.3](https://sarabander.github.io/sicp/html/2_002e5.xhtml#g_t2_002e5_002e3) Example: Symbolic Algebra diff --git a/project.clj b/project.clj index ab1046e..b5ea37e 100644 --- a/project.clj +++ b/project.clj @@ -7,7 +7,7 @@ :source-paths ["src"] :test-paths ["test"] :main ^:skip-aot sicp - :target-path "build/%s" + :target-path "target/%s" :plugins [[lein-cloverage "1.2.2"]] :profiles {:dev {:dependencies [[org.clojure/clojure "1.11.1"] [io.github.noahtheduke/splint "1.12"]]} diff --git a/src/sicp/chapter_2/packages/install_complex.clj b/src/sicp/chapter_2/packages/install_complex.clj new file mode 100644 index 0000000..bd4ca54 --- /dev/null +++ b/src/sicp/chapter_2/packages/install_complex.clj @@ -0,0 +1,45 @@ +(ns sicp.chapter-2.packages.install-complex + (:require + [sicp.chapter-2.packages.op-table :as ot] + [sicp.chapter-2.part-4.book-2-4 :as b24])) + +(defn install-complex-package + [] + ; Imported procedures from rectangular and polar packages + (letfn [(make-from-real-imag [x y] ((ot/get :make-from-real-imag :rectangular) x y)) + (make-from-mag-ang [r a] ((ot/get :make-from-mag-ang :polar) r a)) + ; Internal procedures + (add-complex + [z1 z2] + (make-from-real-imag (+ (b24/real-part z1) (b24/real-part z2)) + (+ (b24/imag-part z1) (b24/imag-part z2)))) + (sub-complex + [z1 z2] + (make-from-real-imag (- (b24/real-part z1) (b24/real-part z2)) + (- (b24/imag-part z1) (b24/imag-part z2)))) + (mul-complex + [z1 z2] + (make-from-mag-ang (* (b24/magnitude z1) (b24/magnitude z2)) + (+ (b24/angle z1) (b24/angle z2)))) + (div-complex + [z1 z2] + (make-from-mag-ang (/ (b24/magnitude z1) (b24/magnitude z2)) + (- (b24/angle z1) (b24/angle z2)))) + ; Interface to rest of the system + (tag [z] (ot/attach-tag :complex z))] + ; Putting functions in a map or registry + (ot/put :add [:complex :complex] (fn [z1 z2] (tag (add-complex z1 z2)))) + (ot/put :sub [:complex :complex] (fn [z1 z2] (tag (sub-complex z1 z2)))) + (ot/put :mul [:complex :complex] (fn [z1 z2] (tag (mul-complex z1 z2)))) + (ot/put :div [:complex :complex] (fn [z1 z2] (tag (div-complex z1 z2)))) + (ot/put :make-from-real-imag :complex (fn [x y] (tag (make-from-real-imag x y)))) + (ot/put :make-from-mag-ang :complex (fn [r a] (tag (make-from-mag-ang r a)))) + :done)) + +(defn make-complex-from-real-imag + [x y] + ((ot/get :make-from-real-imag :complex) x y)) + +(defn make-complex-from-mag-ang + [r a] + ((ot/get :make-from-mag-ang :complex) r a)) diff --git a/src/sicp/chapter_2/packages/install_polar.clj b/src/sicp/chapter_2/packages/install_polar.clj new file mode 100644 index 0000000..2987594 --- /dev/null +++ b/src/sicp/chapter_2/packages/install_polar.clj @@ -0,0 +1,24 @@ +(ns sicp.chapter-2.packages.install-polar + (:require + [sicp.chapter-2.packages.op-table :as ot])) + +(defn install-polar-package + [] + (letfn [(magnitude [z] (first z)) + (angle [z] (second z)) + (make-from-mag-ang [r a] (list r a)) + (real-part [z] (* (magnitude z) (Math/cos (angle z)))) + (imag-part [z] (* (magnitude z) (Math/sin (angle z)))) + (make-from-real-imag + [x y] + (list (Math/sqrt (+ (Math/pow x 2) (Math/pow y 2))) + (Math/atan2 y x))) + (tag [x] (cons :polar x))] + ; interface to the rest of the system + (ot/put :real-part :polar real-part) + (ot/put :imag-part :polar imag-part) + (ot/put :magnitude :polar magnitude) + (ot/put :angle :polar angle) + (ot/put :make-from-real-imag :polar (fn [x y] (tag (make-from-real-imag x y)))) + (ot/put :make-from-mag-ang :polar (fn [r a] (tag (make-from-mag-ang r a)))) + :done)) diff --git a/src/sicp/chapter_2/packages/install_rational.clj b/src/sicp/chapter_2/packages/install_rational.clj new file mode 100644 index 0000000..9602856 --- /dev/null +++ b/src/sicp/chapter_2/packages/install_rational.clj @@ -0,0 +1,44 @@ +(ns sicp.chapter-2.packages.install-rational + (:require + [sicp.chapter-2.packages.op-table :as ot] + [sicp.misc :as m])) + +(defn install-rational-package + [] + ; Internal procedures + (letfn [(numer [x] (first x)) + (denom [x] (second x)) + (make-rat + [n d] + (let [g (m/gcd n d)] + (m/pair (/ n g) (/ d g)))) + (add-rat + [x y] + (make-rat (+ (* (numer x) (denom y)) + (* (numer y) (denom x))) + (* (denom x) (denom y)))) + (sub-rat + [x y] + (make-rat (- (* (numer x) (denom y)) + (* (numer y) (denom x))) + (* (denom x) (denom y)))) + (mul-rat + [x y] + (make-rat (* (numer x) (numer y)) + (* (denom x) (denom y)))) + (div-rat + [x y] + (make-rat (* (numer x) (denom y)) + (* (denom x) (numer y)))) + ; Interface to rest of the system + (tag [x] (ot/attach-tag :rational x))] + (ot/put :add [:rational :rational] (fn [x y] (tag (add-rat x y)))) + (ot/put :sub [:rational :rational] (fn [x y] (tag (sub-rat x y)))) + (ot/put :mul [:rational :rational] (fn [x y] (tag (mul-rat x y)))) + (ot/put :div [:rational :rational] (fn [x y] (tag (div-rat x y)))) + (ot/put :make :rational (fn [n d] (tag (make-rat n d)))) + :done)) + +(defn make-rational + [n d] + ((ot/get :make :rational) n d)) diff --git a/src/sicp/chapter_2/packages/install_rectangular.clj b/src/sicp/chapter_2/packages/install_rectangular.clj new file mode 100644 index 0000000..5dcad64 --- /dev/null +++ b/src/sicp/chapter_2/packages/install_rectangular.clj @@ -0,0 +1,25 @@ +(ns sicp.chapter-2.packages.install-rectangular + (:require + [sicp.chapter-2.packages.op-table :as ot])) + +(defn install-rectangular-package + [] + ; internal procedures + (letfn [(real-part [z] (first z)) + (imag-part [z] (second z)) + (make-from-real-imag [x y] (list x y)) + (magnitude + [z] + (Math/sqrt (+ (Math/pow (real-part z) 2) + (Math/pow (imag-part z) 2)))) + (angle [z] (Math/atan2 (imag-part z) (real-part z))) + (make-from-mag-ang [r a] (list (* r (Math/cos a)) (* r (Math/sin a)))) + (tag [x] (ot/attach-tag :rectangular x))] + ; interface to the rest of the system + (ot/put :real-part '(:rectangular) real-part) + (ot/put :imag-part '(:rectangular) imag-part) + (ot/put :magnitude '(:rectangular) magnitude) + (ot/put :angle '(:rectangular) angle) + (ot/put :make-from-real-imag :rectangular (fn [x y] (tag (make-from-real-imag x y)))) + (ot/put :make-from-mag-ang :rectangular (fn [r a] (tag (make-from-mag-ang r a)))) + :done)) diff --git a/src/sicp/chapter_2/packages/install_scheme_number.clj b/src/sicp/chapter_2/packages/install_scheme_number.clj new file mode 100644 index 0000000..bc5fa74 --- /dev/null +++ b/src/sicp/chapter_2/packages/install_scheme_number.clj @@ -0,0 +1,17 @@ +(ns sicp.chapter-2.packages.install-scheme-number + (:require + [sicp.chapter-2.packages.op-table :as ot])) + +(defn install-scheme-number-package + [] + (letfn [(tag [x] (ot/attach-tag :scheme-number x))] + (ot/put :add [:scheme-number :scheme-number] (fn [x y] (tag (+ x y)))) + (ot/put :sub [:scheme-number :scheme-number] (fn [x y] (tag (- x y)))) + (ot/put :mul [:scheme-number :scheme-number] (fn [x y] (tag (* x y)))) + (ot/put :div [:scheme-number :scheme-number] (fn [x y] (tag (/ x y)))) + (ot/put :make :scheme-number (fn [x] (tag x))) + :done)) + +(defn make-scheme-number + [n] + ((ot/get :make :scheme-number) n)) diff --git a/src/sicp/chapter_2/packages/op_table.clj b/src/sicp/chapter_2/packages/op_table.clj new file mode 100644 index 0000000..ffb5f9a --- /dev/null +++ b/src/sicp/chapter_2/packages/op_table.clj @@ -0,0 +1,36 @@ +(ns sicp.chapter-2.packages.op-table + (:refer-clojure :exclude [get]) + (:require + [clojure.pprint :as pp])) + +(comment "Custom helper functions. Made myself, just for testing ---------------------------------") + +(def operation-table (atom {})) + +(defn attach-tag + [tag value] + {:tag tag, :contents value}) + +(defn put + [operation types procedure] + (swap! operation-table assoc-in [operation types] procedure)) + +(defn get + [operation types] + (get-in @operation-table [operation types])) + +(defn apply-generic + [op & args] + (let [type-tags (map #(-> % :tag) args) + operation (get op type-tags)] + (if operation + (apply operation (map #(:contents %) args)) + (throw (IllegalArgumentException. (str "No method for: " op)))))) + +(defn inspect + [] + (->> @operation-table + (map (fn [item] + {:operation (first item) + :types (first (first (into '() (second item))))})) + (pp/print-table))) diff --git a/src/sicp/chapter_2/part_4/book_2_4.clj b/src/sicp/chapter_2/part_4/book_2_4.clj index d0cece0..aa5cf2e 100644 --- a/src/sicp/chapter_2/part_4/book_2_4.clj +++ b/src/sicp/chapter_2/part_4/book_2_4.clj @@ -91,15 +91,15 @@ (defn type-tag [datum] - (if (sequential? datum) - (first datum) - (throw (Exception. (str "Bad tagged datum: TYPE-TAG " datum))))) + (cond (sequential? datum) (first datum) + (map? datum) (get datum :tag) + :else (throw (Exception. (str "Bad tagged datum: TYPE-TAG " datum))))) (defn contents [datum] - (if (sequential? datum) - (rest datum) - (throw (Exception. (str "Bad tagged datum: CONTENTS " datum))))) + (cond (sequential? datum) (rest datum) + (map? datum) (get datum :contents) + :else (throw (Exception. (str "Bad tagged datum: CONTENTS " datum))))) (defn rectangular? [z] @@ -215,6 +215,7 @@ ; * 2.76 (defn apply-generic + "Just a wrapper for the dispatch table. It's a bit more verbose than the original, I don't use it" [op & args] (let [type-tags (map type-tag args) proc (get op type-tags)] diff --git a/src/sicp/chapter_2/part_5/book_2_5.clj b/src/sicp/chapter_2/part_5/book_2_5.clj index 5b9f79a..1d1fd1e 100644 --- a/src/sicp/chapter_2/part_5/book_2_5.clj +++ b/src/sicp/chapter_2/part_5/book_2_5.clj @@ -1,149 +1,30 @@ (ns sicp.chapter-2.part-5.book-2-5 (:require - [sicp.chapter-2.part-4.book-2-4 :as b24] - [sicp.misc :as m])) + [sicp.chapter-2.packages.op-table :as ot])) (comment "2.5 Systems with Generic Operations ----------------------------------------------------") (comment "2.5.1 Generic Arithmetic Operations ----------------------------------------------------") -; Custom helper functions. Made myself, just for testing ------------------------------------------- - -(def operation-table (atom {})) - -(defn attach-tag - [tag value] - {:tag tag, :contents value}) - -(defn put-op - [operation types procedure] - (swap! operation-table assoc-in [operation types] procedure)) - -(defn get-op - [operation types] - (get-in @operation-table [operation types])) - -(defn apply-generic - [op & args] - (let [type-tags (map #(-> % :tag) args) - operation (get-op op type-tags)] - (if operation - (apply operation (map #(:contents %) args)) - (throw (IllegalArgumentException. (str "No method for: " op)))))) - -; -------------------------------------------------------------------------------------------------- - (defn add [x y] - (apply-generic :add x y)) + (ot/apply-generic :add x y)) (defn sub [x y] - (apply-generic :sub x y)) + (ot/apply-generic :sub x y)) (defn mul [x y] - (apply-generic :mul x y)) + (ot/apply-generic :mul x y)) (defn div [x y] - (apply-generic :div x y)) - -(defn install-scheme-number-package - [] - (letfn [(tag [x] (attach-tag :scheme-number x))] - (put-op :add [:scheme-number :scheme-number] (fn [x y] (tag (+ x y)))) - (put-op :sub [:scheme-number :scheme-number] (fn [x y] (tag (- x y)))) - (put-op :mul [:scheme-number :scheme-number] (fn [x y] (tag (* x y)))) - (put-op :div [:scheme-number :scheme-number] (fn [x y] (tag (/ x y)))) - (put-op :make :scheme-number (fn [x] (tag x))) - :done)) - -(defn install-rational-package - [] - ; Internal procedures - (letfn [(numer [x] (first x)) - (denom [x] (second x)) - (make-rat - [n d] - (let [g (m/gcd n d)] - (m/pair (/ n g) (/ d g)))) - (add-rat - [x y] - (make-rat (+ (* (numer x) (denom y)) - (* (numer y) (denom x))) - (* (denom x) (denom y)))) - (sub-rat - [x y] - (make-rat (- (* (numer x) (denom y)) - (* (numer y) (denom x))) - (* (denom x) (denom y)))) - (mul-rat - [x y] - (make-rat (* (numer x) (numer y)) - (* (denom x) (denom y)))) - (div-rat - [x y] - (make-rat (* (numer x) (denom y)) - (* (denom x) (numer y)))) - ; Interface to rest of the system - (tag [x] (attach-tag :rational x))] - (put-op :add [:rational :rational] (fn [x y] (tag (add-rat x y)))) - (put-op :sub [:rational :rational] (fn [x y] (tag (sub-rat x y)))) - (put-op :mul [:rational :rational] (fn [x y] (tag (mul-rat x y)))) - (put-op :div [:rational :rational] (fn [x y] (tag (div-rat x y)))) - (put-op :make :rational (fn [n d] (tag (make-rat n d)))) - :done)) - -(defn install-complex-package - [] - ; Imported procedures from rectangular and polar packages - (letfn [(make-from-real-imag [x y] ((get-op :make-from-real-imag :rectangular) x y)) - (make-from-mag-ang [r a] ((get-op :make-from-mag-ang :polar) r a)) - ; Internal procedures - (add-complex - [z1 z2] - (make-from-real-imag - (+ (b24/real-part z1) (b24/real-part z2)) - (+ (b24/imag-part z1) (b24/imag-part z2)))) - (sub-complex - [z1 z2] - (make-from-real-imag - (- (b24/real-part z1) (b24/real-part z2)) - (- (b24/imag-part z1) (b24/imag-part z2)))) - (mul-complex - [z1 z2] - (make-from-mag-ang - (* (b24/magnitude z1) (b24/magnitude z2)) - (+ (b24/angle z1) (b24/angle z2)))) - (div-complex - [z1 z2] - (make-from-mag-ang - (/ (b24/magnitude z1) (b24/magnitude z2)) - (- (b24/angle z1) (b24/angle z2)))) - ; Interface to rest of the system - (tag [z] (attach-tag :complex z))] - ; Putting functions in a map or registry - (put-op :add [:complex :complex] (fn [z1 z2] (tag (add-complex z1 z2)))) - (put-op :sub [:complex :complex] (fn [z1 z2] (tag (sub-complex z1 z2)))) - (put-op :mul [:complex :complex] (fn [z1 z2] (tag (mul-complex z1 z2)))) - (put-op :div [:complex :complex] (fn [z1 z2] (tag (div-complex z1 z2)))) - (put-op :make-from-real-imag :complex (fn [x y] (tag (make-from-real-imag x y)))) - (put-op :make-from-mag-ang :complex (fn [r a] (tag (make-from-mag-ang r a)))) - :done)) - -(defn make-scheme-number - [n] - ((get-op :make :scheme-number) n)) - -(defn make-rational - [n d] - ((get-op :make :rational) n d)) - -(defn make-complex-from-real-imag - [x y] - ((get-op :make-from-real-imag :complex) x y)) - -(defn make-complex-from-mag-ang - [r a] - ((get-op :make-from-mag-ang :complex) r a)) + (ot/apply-generic :div x y)) + +(comment + "See also:" + "sicp.chapter-2.packages.install-scheme-number" + "sicp.chapter-2.packages.install-rational" + "sicp.chapter-2.packages.install-rectangular" + "sicp.chapter-2.packages.install-complex") diff --git a/src/sicp/chapter_2/part_5/ex_2_77.clj b/src/sicp/chapter_2/part_5/ex_2_77.clj new file mode 100644 index 0000000..4300b56 --- /dev/null +++ b/src/sicp/chapter_2/part_5/ex_2_77.clj @@ -0,0 +1,22 @@ +(ns sicp.chapter-2.part-5.ex-2-77 + (:require + [sicp.chapter-2.packages.op-table :as ot])) + +; Exercise 2.77 +; +; Louis Reasoner tries to evaluate the expression (magnitude z) where z is the object shown in +; Figure 2.24. To his surprise, instead of the answer 5 he gets an error message from apply-generic, +; saying there is no method for the operation magnitude on the types (complex). +; +; He shows this interaction to Alyssa P. Hacker, who says “The problem is that the complex-number +; selectors were never defined for complex numbers, just for polar and rectangular numbers. +; All you have to do to make this work is add the following to the complex package:” +; +; (put 'real-part '(complex) real-part) +; (put 'imag-part '(complex) imag-part) +; (put 'magnitude '(complex) magnitude) +; (put 'angle '(complex) angle) + +(defn magnitude + [z] + (ot/apply-generic :magnitude z)) diff --git a/test/sicp/chapter_2/part_5/book_2_5_test.clj b/test/sicp/chapter_2/part_5/book_2_5_test.clj index ab09e5e..23413a2 100644 --- a/test/sicp/chapter_2/part_5/book_2_5_test.clj +++ b/test/sicp/chapter_2/part_5/book_2_5_test.clj @@ -1,41 +1,38 @@ (ns sicp.chapter-2.part-5.book-2-5-test (:require [clojure.test :refer [deftest is]] + [sicp.chapter-2.packages.install-rational :as rational] + [sicp.chapter-2.packages.install-scheme-number :as scheme] + [sicp.chapter-2.packages.op-table :as ot] [sicp.chapter-2.part-5.book-2-5 :as b25] [sicp.misc :as m])) -(b25/install-scheme-number-package) -(b25/install-rational-package) -(b25/install-complex-package) - -(deftest install-test - (is (= :done (b25/install-scheme-number-package))) - (is (= :done (b25/install-rational-package))) - (is (= :done (b25/install-complex-package)))) +(scheme/install-scheme-number-package) +(rational/install-rational-package) (deftest add-test - (is (= (b25/make-scheme-number 3) (b25/add (b25/make-scheme-number 1) (b25/make-scheme-number 2)))) - (is (= (b25/make-scheme-number 4) (b25/add (b25/make-scheme-number 2) (b25/make-scheme-number 2)))) - (is (= (b25/make-rational 4 1) (b25/add (b25/make-rational 2 1) (b25/make-rational 2 1)))) - (is (= (b25/make-rational 1 1) (b25/add (b25/make-rational 2 3) (b25/make-rational 1 3))))) + (is (= (scheme/make-scheme-number 3) (b25/add (scheme/make-scheme-number 1) (scheme/make-scheme-number 2)))) + (is (= (scheme/make-scheme-number 4) (b25/add (scheme/make-scheme-number 2) (scheme/make-scheme-number 2)))) + (is (= (rational/make-rational 4 1) (b25/add (rational/make-rational 2 1) (rational/make-rational 2 1)))) + (is (= (rational/make-rational 1 1) (b25/add (rational/make-rational 2 3) (rational/make-rational 1 3))))) (deftest sub-test - (is (= (b25/make-scheme-number 1) (b25/sub (b25/make-scheme-number 4) (b25/make-scheme-number 3)))) - (is (= (b25/make-scheme-number -6) (b25/sub (b25/make-scheme-number 4) (b25/make-scheme-number 10)))) - (is (= (b25/make-rational 0 1) (b25/sub (b25/make-rational 2 1) (b25/make-rational 2 1)))) - (is (= (b25/make-rational 1 3) (b25/sub (b25/make-rational 2 3) (b25/make-rational 1 3))))) + (is (= (scheme/make-scheme-number 1) (b25/sub (scheme/make-scheme-number 4) (scheme/make-scheme-number 3)))) + (is (= (scheme/make-scheme-number -6) (b25/sub (scheme/make-scheme-number 4) (scheme/make-scheme-number 10)))) + (is (= (rational/make-rational 0 1) (b25/sub (rational/make-rational 2 1) (rational/make-rational 2 1)))) + (is (= (rational/make-rational 1 3) (b25/sub (rational/make-rational 2 3) (rational/make-rational 1 3))))) (deftest mul-test - (is (= (b25/make-scheme-number 12) (b25/mul (b25/make-scheme-number 4) (b25/make-scheme-number 3)))) - (is (= (b25/make-scheme-number -40) (b25/mul (b25/make-scheme-number -4) (b25/make-scheme-number 10)))) - (is (= (b25/make-rational 4 1) (b25/mul (b25/make-rational 2 1) (b25/make-rational 2 1)))) - (is (= (b25/make-rational 2 9) (b25/mul (b25/make-rational 2 3) (b25/make-rational 1 3))))) + (is (= (scheme/make-scheme-number 12) (b25/mul (scheme/make-scheme-number 4) (scheme/make-scheme-number 3)))) + (is (= (scheme/make-scheme-number -40) (b25/mul (scheme/make-scheme-number -4) (scheme/make-scheme-number 10)))) + (is (= (rational/make-rational 4 1) (b25/mul (rational/make-rational 2 1) (rational/make-rational 2 1)))) + (is (= (rational/make-rational 2 9) (b25/mul (rational/make-rational 2 3) (rational/make-rational 1 3))))) (deftest div-test - (is (= (b25/make-scheme-number 20) (b25/div (b25/make-scheme-number 100) (b25/make-scheme-number 5)))) - (is (= (b25/make-scheme-number 1/2) (b25/div (b25/make-scheme-number 3) (b25/make-scheme-number 6)))) - (is (= (b25/make-rational 1 1) (b25/div (b25/make-rational 2 1) (b25/make-rational 2 1)))) - (is (= (b25/make-rational 2 1) (b25/div (b25/make-rational 2 3) (b25/make-rational 1 3))))) + (is (= (scheme/make-scheme-number 20) (b25/div (scheme/make-scheme-number 100) (scheme/make-scheme-number 5)))) + (is (= (scheme/make-scheme-number 1/2) (b25/div (scheme/make-scheme-number 3) (scheme/make-scheme-number 6)))) + (is (= (rational/make-rational 1 1) (b25/div (rational/make-rational 2 1) (rational/make-rational 2 1)))) + (is (= (rational/make-rational 2 1) (b25/div (rational/make-rational 2 3) (rational/make-rational 1 3))))) (deftest apply-generic-test - (is (= true (m/is-exception? ((b25/apply-generic :undefined 1 2)) "No method for: :undefined")))) + (is (= true (m/is-exception? ((ot/apply-generic :undefined 1 2)) "No method for: :undefined")))) diff --git a/test/sicp/chapter_2/part_5/ex_2_77_test.clj b/test/sicp/chapter_2/part_5/ex_2_77_test.clj new file mode 100644 index 0000000..c2856ae --- /dev/null +++ b/test/sicp/chapter_2/part_5/ex_2_77_test.clj @@ -0,0 +1,21 @@ +(ns sicp.chapter-2.part-5.ex-2-77-test + (:require + [clojure.test :refer [deftest is]] + [sicp.chapter-2.packages.install-complex :as complex] + [sicp.chapter-2.packages.install-polar :as polar] + [sicp.chapter-2.packages.install-rectangular :as rectangular] + [sicp.chapter-2.packages.op-table :as ot] + [sicp.chapter-2.part-4.book-2-4 :as b24] + [sicp.chapter-2.part-5.ex-2-77 :refer [magnitude]])) + +(rectangular/install-rectangular-package) +(polar/install-polar-package) +(complex/install-complex-package) + +(ot/put :real-part '(:complex) b24/real-part) +(ot/put :imag-part '(:complex) b24/imag-part) +(ot/put :magnitude '(:complex) b24/magnitude) +(ot/put :angle '(:complex) b24/angle) + +(deftest magnitude-test + (is (= 5.0 (magnitude (complex/make-complex-from-real-imag 3 4)))))