Chapter 2, Building Abstractions with Data

Section - 2.5 - Systems with Generic Operations

Exercise 2.78


I have included the complete program so that it can be tested/executed easily.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#lang sicp

(#%require (only racket/base error))
(#%require (only racket/base make-hash))
(#%require (only racket/base hash-set!))
(#%require (only racket/base hash-ref))

; helper procedures
(define *op-table* (make-hash))

(define (put op type proc)
  (hash-set! *op-table* (list op type) proc)
)

(define (get op type)
  (hash-ref *op-table* (list op type) '())
)

(define (attach-tag type-tag contents) 
   (if (number? contents) 
       contents 
       (cons type-tag contents)
   )
) 

; procedures implemented as per the requirement of exercise  
(define (type-tag datum) 
   (cond ((number? datum) 'scheme-number)
         ((pair? datum) (car datum)) 
         (error "Bad tagged datum -- TYPE-TAG" datum)
   )
)
  
(define (contents datum) 
   (cond ((number? datum) datum) 
         ((pair? datum) (cdr datum)) 
         (error "Bad tagged datum -- CONTENTS" datum)
   )
)

;remaining procedures
(define (install-scheme-number-package)
  (define (tag x)
    (attach-tag 'scheme-number x))
  (put 'add '(scheme-number scheme-number)
       (lambda (x y) (tag (+ x y))))
  (put 'sub '(scheme-number scheme-number)
       (lambda (x y) (tag (- x y))))
  (put 'mul '(scheme-number scheme-number)
       (lambda (x y) (tag (* x y))))
  (put 'div '(scheme-number scheme-number)
       (lambda (x y) (tag (/ x y))))
  (put 'make 'scheme-number
       (lambda (x) (tag x)))
  'done
)

(install-scheme-number-package)

(define (make-number n)
  ((get 'make 'scheme-number) n)
)  

(define (apply-generic op . args)
  (let ((type-tags (map type-tag args)))

    (let ((proc (get op type-tags)))
      (if proc
          (apply proc (map contents args))
          (error
            "No method for these types -- APPLY-GENERIC"
            (list op type-tags))))))

I shall first add the output generated without the changes in apply-tag, tag or contents:

1
2
3
4
5
6
7
> (display (make-number 5))
(scheme-number 5)
> (apply-generic 'add 5 10)
(scheme-number 15)
> (apply-generic 'mul 5 10)
(scheme-number 50)
> 

Now, lets see the output after the changes:

1
2
3
4
5
6
7
8
9
> (make-number 5)
5
> (display (make-number 5))
5
> (apply-generic 'add 5 10)
15
> (apply-generic 'mul 5 10)
50
>