summaryrefslogtreecommitdiff
path: root/coding-exercises
diff options
context:
space:
mode:
authorMike Vink <>2023-04-18 23:47:17 +0200
committerMike Vink <>2023-04-18 23:47:17 +0200
commit6d9a546f69023788d1b04fbd4722874466c3891d (patch)
treeef0833582058ea0e314d3b42611c1edaeca9e12c /coding-exercises
parent6643d15b64d4ab0f72a7cd29458fb2cbecd02e2b (diff)
fixup
Diffstat (limited to 'coding-exercises')
-rw-r--r--coding-exercises/2/30.rkt4
-rw-r--r--coding-exercises/2/73.rkt137
-rw-r--r--coding-exercises/2/74.rkt62
-rw-r--r--coding-exercises/2/75.rkt25
-rw-r--r--coding-exercises/2/76.rkt1
-rw-r--r--coding-exercises/2/77.rkt9
-rw-r--r--coding-exercises/2/78.rkt8
7 files changed, 189 insertions, 57 deletions
diff --git a/coding-exercises/2/30.rkt b/coding-exercises/2/30.rkt
index 785a8dc..b9f079a 100644
--- a/coding-exercises/2/30.rkt
+++ b/coding-exercises/2/30.rkt
@@ -1,6 +1,6 @@
#lang racket
(define (scale-tree tree factor)
- (cond ((null? tree) nil)
+ (cond ((null? tree) '())
((not (pair? tree)) (* tree factor))
(else (cons (scale-tree (car tree) factor)
(scale-tree (cdr tree) factor)))))
@@ -18,7 +18,7 @@
;; (list)
;; (cons (square (car items)) (square-list (cdr items)))))
(define (square-tree tree)
- (cond ((null? tree) nil)
+ (cond ((null? tree) '())
((not (pair? tree)) (* tree tree))
(else (cons (square-tree (car tree))
(square-tree (cdr tree))))))
diff --git a/coding-exercises/2/73.rkt b/coding-exercises/2/73.rkt
index f8b4fad..26e456a 100644
--- a/coding-exercises/2/73.rkt
+++ b/coding-exercises/2/73.rkt
@@ -44,19 +44,20 @@
(error "Not found or bad entry -- GET" op type op-entry))))
(define (put op type item)
(if (find-first (make-eq-type? op) dispatch-table)
- (set! dispatch-table (map (lambda (op-entry) ;;just copy the table for now, don't want to mutate yet
- (if (not (eq? (type-tag op-entry) op))
- op-entry
- (attach-tag op
- (let ((installed-types (map (lambda (type-entry)
- (if (not (eq? (type-tag type-entry) type))
- type-entry
- (attach-tag type item)))
- (cdr op-entry))))
- (if (find-first (make-eq-type? type) installed-types)
- installed-types
- (cons (attach-tag type item) installed-types))))))
- dispatch-table))
+ (set! dispatch-table
+ (map (lambda (op-entry) ;;just copy the table for now, don't want to mutate yet
+ (if (not (eq? (type-tag op-entry) op))
+ op-entry
+ (attach-tag op
+ (let ((installed-types (map (lambda (type-entry)
+ (if (not (eq? (type-tag type-entry) type))
+ type-entry
+ (attach-tag type item)))
+ (cdr op-entry))))
+ (if (find-first (make-eq-type? type) installed-types)
+ installed-types
+ (cons (attach-tag type item) installed-types))))))
+ dispatch-table))
(set! dispatch-table (cons
(attach-tag op
(list (attach-tag type item)))
@@ -67,57 +68,83 @@
(define (putter t)
(caddr t))
+(define t (make-dispatch-table))
+(define get (getter t))
+(define put (putter t))
+
;; prefix combination notation of expression? (+ a b)
(define (operator ex)
- (car ex))
-
+ (car ex))
(define (operands ex)
(cdr ex))
-
-(define t (make-dispatch-table))
-(define get (getter t))
-(define put (putter t))
(define (deriv ex var)
(cond ((number? ex) 0)
((variable? ex) (if (same-variable? ex var) 1 0))
(else ((get 'deriv (operator ex)) (operands ex) var))))
-(define (=number? x num)
- (and (number? x) (= x num)))
-(define (make-sum a1 a2)
- (cond ((=number? a1 0) a2)
- ((=number? a2 0) a1)
- ((and (number? a1)
- (number? a2)) (+ a1 a2))
- (else (list '+ a1 a2))))
-(define (addend s) (car s))
-(define (augend s)
- (cond ((null? (cddr s)) (cadr s))
- (else (cons '+ (cdr s)))))
+(define (install-basic-deriv-rules)
+
+ (define (=number? x num)
+ (and (number? x) (= x num)))
+ (define (make-sum a1 a2)
+ (cond ((=number? a1 0) a2)
+ ((=number? a2 0) a1)
+ ((and (number? a1)
+ (number? a2)) (+ a1 a2))
+ (else (list '+ a1 a2))))
+ (define (addend s) (car s))
+ (define (augend s)
+ (cond ((null? (cddr s)) (cadr s))
+ (else (cons '+ (cdr s)))))
+
+ (define (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 (list '* m1 m2))))
+ (define (multiplier p)
+ (car p))
+ (define (multiplicand p)
+ (cond ((null? (cddr p))
+ (cadr p))
+ (else (cons '* (cdr p)))))
+
+ (define (make-exponent e p)
+ (cond ((=number? p 0) 1)
+ ((=number? p 1) e)
+ (else (list '** e p))))
+ (define (base expo)
+ (car expo))
+ (define (exponent expo)
+ (cadr expo))
-(put 'deriv '+ (lambda (ex var)
- (make-sum
- (deriv (addend ex) var)
- (deriv (augend ex) var))))
-(define (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 (list '* m1 m2))))
-(define (multiplier p)
- (car p))
-(define (multiplicand p)
- (cond ((null? (cddr p))
- (cadr p))
- (else (cons '* (cdr p)))))
+ ;;b
+ (put 'deriv '+ (lambda (ex var)
+ (make-sum
+ (deriv (addend ex) var)
+ (deriv (augend ex) var))))
+ (put 'deriv '* (lambda (ex var)
+ (make-sum
+ (make-product
+ (multiplier ex)
+ (deriv (multiplicand ex) var))
+ (make-product
+ (deriv (multiplier ex) var)
+ (multiplicand ex)))))
+ ;;c
+ (put 'deriv '** (lambda (ex var)
+ (make-product
+ (deriv (base ex) var)
+ (make-product
+ (exponent ex)
+ (make-exponent (base ex) (- (exponent ex) 1)))))))
-(put 'deriv '* (lambda (ex var)
- (make-sum
- (make-product
- (multiplier ex)
- (deriv (multiplicand ex) var))
- (make-product
- (deriv (multiplier ex) var)
- (multiplicand ex)))))
+(install-basic-deriv-rules)
(deriv '(+ (* 3 x) (* 2 x)) 'x)
+(deriv '(** x 2) 'x)
+;;d
+;; No changes to the derivative system are necessary so long as (op, 'deriv) points
+;; to the same method as ('deriv, op) in the dispatch table of the consuming package.
+;; I guess you could argue that the put arguments should be reversed in the derivative system.
+;; But the actual items in the dispatch table don't have to change since the call signature is the same.
diff --git a/coding-exercises/2/74.rkt b/coding-exercises/2/74.rkt
new file mode 100644
index 0000000..c6bc137
--- /dev/null
+++ b/coding-exercises/2/74.rkt
@@ -0,0 +1,62 @@
+#lang racket
+(require "../../shared/data-directed-programming.rkt")
+(require "../../shared/lists.rkt")
+
+(define test-dispatch (make-dispatch-table))
+(define get (getter test-dispatch))
+(define put (putter test-dispatch))
+
+;; Example implementations
+(define test-division (attach-tag
+ 'division-a
+ (list (attach-tag
+ 'henk
+ (list (attach-tag 'salary 100))))))
+(put 'record 'division-a (lambda (file-set employee)
+ (let ((record (find-first
+ (make-eq-type? employee)
+ file-set)))
+ (if record
+ record
+ (error "Employee record not found -- GET-RECORD DIVISION-A" employee)))))
+(put 'salary 'division-a (lambda (record)
+ (let ((salary (find-first
+ (make-eq-type? 'salary)
+ record)))
+ (if salary
+ salary
+ (error "Salary not found -- GET-SALARY DIVISION-A" record)))))
+
+;;a Each divisions file must be a datum tagged with the divisions name.
+;; Together with the division type tag and an operation type tag
+;; we can get a procedure that knows how to do that operation for the given employee.
+(define (get-record file employee)
+ ((get 'record (type-tag file)) (contents file) employee))
+
+(define test-record (get-record test-division 'henk))
+
+;; b The record can have any structure that is handled by the salary procedure of the
+;; division we dispatch the procedure from
+(define (get-salary file record)
+ ((get 'salary (type-tag file)) (contents record)))
+
+
+(get-salary test-division test-record)
+
+;;c
+(define (find-employee-record files employee)
+ (define (search fi)
+ (if (null? fi)
+ false
+ (let ((result (with-handlers
+ ([exn:fail? (lambda (exn)
+ false)])
+ (get-record (car fi) employee))))
+ (if result
+ result
+ (search (cdr fi))))))
+ (search files))
+(find-employee-record (list test-division test-division) 'henk)
+
+;;d
+;; new implementations for the division representation for the existing operations on a type
diff --git a/coding-exercises/2/75.rkt b/coding-exercises/2/75.rkt
new file mode 100644
index 0000000..4a5cf23
--- /dev/null
+++ b/coding-exercises/2/75.rkt
@@ -0,0 +1,25 @@
+#lang racket
+
+(define (make-from-mag-ang mag ang)
+ (define (dispatch op)
+ (cond ((eq? op 'real-part) (* mag (cosine ang)))
+ ((eq? op 'imag-part) (* mag (sine ang)))
+ ((eq? op 'magnitude) mag)
+ ((eq? op 'angle) ang)
+ (else (error "Unknown op -- MAKE-FROM-MAG-ANG" op))))
+ dispatch)
+
+;; Explicit dispatch
+;; The logic for dispatching has to be repeated for every operation and every type.
+;; If there are a number of representations for a type or multiple operations, this is not what you want.
+;;
+;; data dispatch
+;; If new operations need to be added then we have to extend all existing type packages to support dispatching the operation to those types.
+;; When adding new types we need to install a dispatchable procedure for every operation only in the new type package.
+;;
+;; message passing
+;; If new operations need to be added then we have to add a message handling case to all data representations.
+;; When adding new types we need to make a procedure that handles all operation messages.
+;;
+;; In general I think if the operation is less smart then it is easier to add to a system, that's why message passing is more appropriate if you often need to add operations.
+;; The same goes for data dispatching, if the operations are smart, the data doesn't have to be. This makes adding more data representations more convenient.
diff --git a/coding-exercises/2/76.rkt b/coding-exercises/2/76.rkt
new file mode 100644
index 0000000..6f1f7b4
--- /dev/null
+++ b/coding-exercises/2/76.rkt
@@ -0,0 +1 @@
+#lang racket
diff --git a/coding-exercises/2/77.rkt b/coding-exercises/2/77.rkt
new file mode 100644
index 0000000..65feaf3
--- /dev/null
+++ b/coding-exercises/2/77.rkt
@@ -0,0 +1,9 @@
+#lang racket
+
+;; (apply-generic 'magnitude z)
+;; This strips the complex type-tag from z and passes the contents to the generic magnitude procedure defined in the complex package.
+;; The magnitude procedure is responsible for dispatching the operation to the magnitude procedure of either the rectangular or the polar form representation.
+;; (apply-generic 'magnitude z)
+;; This strips away the rectangular type tag of the args and passes the contents of the args to the corresponding 'magnitude '(rectangular) procedure.
+;; In the end the rectangular magnitude procedure's return value is bubbled up to the calling function.
+(print "hi")
diff --git a/coding-exercises/2/78.rkt b/coding-exercises/2/78.rkt
new file mode 100644
index 0000000..3a4b100
--- /dev/null
+++ b/coding-exercises/2/78.rkt
@@ -0,0 +1,8 @@
+#lang racket
+(require "../../shared/data-directed-programming.rkt")
+;; We are basically making a data directed framework for arithmethic operations in this module
+(define pkg (make-dispatch-table))
+(define put (putter pkg))
+(define get (getter pkg))
+(define apply-generic (make-apply put get))
+