forked from ldct/isicp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path2-4-representation.html
779 lines (587 loc) · 46.9 KB
/
2-4-representation.html
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="web-worker-interpreter/deps/codemirror/lib/codemirror.css" />
<link rel="stylesheet" type="text/css" href="css/isicp.css" />
<link rel="stylesheet" type="text/css" href="css/footnotes.css" />
<link rel="stylesheet" type="text/css" href="css/theme.css" />
<script src="js/helper.js"></script>
<script src="js/jquery.min.js"></script>
<script src="web-worker-interpreter/deps/codemirror/lib/codemirror.js"></script>
<script src="web-worker-interpreter/deps/codemirror/mode/scheme/scheme.js"></script>
<script src="web-worker-interpreter/coding.js"> </script>
<script>
set_interpreter_path("web-worker-interpreter/");
set_language("scheme");
</script>
<script src="js/footnotes.js"></script>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {inlineMath: [['$','$']]}
});
</script>
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<title> iSICP 2.4 - Multiple Representations for Abstract Data </title>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-36868476-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body>
<div id="sidebox">
<div class="tab"></div>
<div class="content">
<p>
<a href="index.html" class="navlink"> <img src='images/home.svg' width=32 height=32> </a>
<span id="toc-link" class="navlink"> <img src='images/list.svg' width=32 height=32> </span>
<span id="currently-editing-link" class="navlink"> <img src='images/file-edit.svg' width=32 height=32> </span>
<script src="http://cdn.jotfor.ms/static/feedback2.js?3.2.310" type="text/javascript">
new JotformFeedback({
formId:'40222623177447',
base:'http://jotform.me/',
windowTitle:'Notify Me',
background:'#FFA500',
fontColor:'#FFFFFF',
type:false,
height:500,
width:700
});
</script>
<a class="lightbox-40222623177447" style="cursor:pointer;color:blue;text-decoration:underline;"><img src='images/envelope.svg' width=32 height=32></a>
<p>
<div id="currently-editing"> </div>
<script>
function hideAll() {
$("#currently-editing").hide();
$("#toc").hide();
}
$("#currently-editing-link").click(function() {
hideAll();
$("#currently-editing").show();
});
$("#toc-link").click(function() {
hideAll();
$("#toc").show();
});
</script>
<div id="toc"> </div>
<p style='font-size:12px'> (Click on the left edge of this green box to hide it!)
<script>
hideAll();
$("#toc").show();
</script>
</div>
</div>
<script>
$('#sidebox .tab').toggle(function(){
$('#sidebox').animate({'right':'0%'});
}, function(){
$('#sidebox').animate({'right':'-30%'});
});
$(document).ready(createTOC);
</script>
<div id="main">
<a href='index.html' style="float:left"> <img src='images/chevron-up.svg' height=64 width=64> </a>
<span style="float:right">
<a href='223-symbolic.html'> <img src='images/chevron-left.svg' height=64 width=64> </a>
<a href='2-5-generic.html'> <img src='images/chevron-right.svg' height=64 width=64> </a>
</span>
<br> <br>
<h2> Multiple Representations for Abstract Data </h2>
<p> We have introduced data abstraction, a methodology for structuring systems in such a way that much of a program ca2 be specified independent of the choices involved in implementing the data objects that the program manipulates. For example, we saw in section 2-1-1 how to separate the task of designing a program that uses rational numbers from the task of implementing rational numbers in terms of the computer language's primitive mechanisms for constructing compound data. The key idea was to erect an abstraction barrier -- in this case, the selectors and constructors for rational numbers (<tt>make-rat</tt>, <tt>numer</tt>, <tt>denom</tt>)---that isolates the way rational numbers are used from their underlying representation in terms of list structure. A similar ab2traction barrier isolates the details of the procedures that perform rational arithmetic (<tt>add-rat</tt>, <tt>sub-rat</tt>, <tt>mul-rat</tt>, and <tt>div-rat</tt>) from the ``higher-level'' procedures that use rational numbers. The resulting program has the structure shown in Figure 2-1.
<p> These data-abstraction barriers are powerful tools for controlling complexity. By isolating the underlying representa2ions of data objects, we can divide the task of designing a large program into smaller tasks that can be performed separately. But this kind of data abstraction is not yet powerful enough, because it may not always make sense to speak of ``the underlying representation'' for a data object.
<p> For one thing, there might be more than one useful representation for a data object, and we might like to design sys2ems that can deal with multiple representations. To take a simple example, complex numbers may be represented in two almost equivalent ways: in rectangular form (real and imaginary parts) and in polar form (magnitude and angle). Sometimes rectangular form is more appropriate and sometimes polar form is more appropriate. Indeed, it is perfectly plausible to imagine a system in which complex numbers are represented in both ways, and in which the procedures for manipulating complex numbers work with either representation.
<p> More importantly, programming systems are often designed by many people working over extended periods of time, subject to requirements that change over time. In such an environment, it is simply not possible for everyone to agree in advance on choices of data representation. So in addition to the data-abstraction barriers that isolate representation from use, we need abstraction barriers that isolate different design choices from each other and permit different choices to coexist in a single program. Furthermore, since large programs are often created by combining pre-existing modules that were designed in isolation, we need conventions that permit programmers to incorporate modules into larger systems <tt>additively</tt> , that is, without having to redesign or reimplement these modules.
<p> In this section, we will learn how to cope with data that may be represented in different ways by different parts of a program. This requires constructing <tt>generic procedures</tt> ---procedures that can operate on data that may be represented in more than one way. Our main technique for building generic procedures will be to work in terms of data objects that have <em>type tags</em> , that is, data objects that include explicit information about how they are to be processed. We will also discuss <em>data-directed</em> programming, a powerful and convenient2implementation strategy for additively assembling systems with generic operations.
<p> We begin with the simple complex-number example. We will see how type tags and data-directed style enable us to design separate rectangular and polar representations for complex numbers while maintaining the notion of an abstract ``complex-number'' data object. We will accomplish this by defining arithmetic procedures for complex numbers (<tt>add-complex</tt>, <tt>sub-complex</tt>, <tt>mul-complex</tt>, and <tt>div-complex</tt>) in terms of generic selectors that access parts of a complex number independent of how the number is represented. The resulting complex-number system, as shown in Figure 2-19, contains two different kinds of abstraction barriers. The ``horizontal'' abstraction barriers play the same role as the ones in Figure 2-1. They isolate ``higher-level'' operations from ``lower-level'' representations. In addition, there is a ``vertical'' barrier that gives us the ability to separately design and install alternative representations.
<div class="figure">
<img src="http://mitpress.mit.edu/sicp/full-text/book/ch2-Z-G-54.gif">
<p> <b>Figure 2.19:</b> Data-abstraction barriers in the complex-number system.
</div>
<p> In section 2-5 we will show how to use type tags and data-directed style to develop a generic arithmetic package. This provides procedures (<tt>add</tt>, <tt>mul</tt>, and so on) that can be used to manipulate all sorts of ``numbers''and can be easily extended when a new kind of number is needed. In section 2-5-3, we'll show how to use generic arithmetic in a system that performs symbolic algebra.
<h3> Representations for Complex Numbers </h3>
<p> We will develop a system that performs arithmetic operations on complex numbers as a simple but unrealistic example of a program that uses generic operations. We begin by discussing two plausible representations for complex numbers as ordered pairs: rectangular form (real part and imaginary part) and polar form (magnitude and angle).<a name="footnote_link_2-43" class="footnote_link" href="#footnote_2-43">43</a> Section 2-4-2 will show how both representations can be made to coexist in a single system through the use of type tags and generic operations.
<p> Like rational numbers, complex numbers are naturally represented as ordered pairs. The set of complex numbers can be thought of as a two-dimensional space with two orthogonal axes, the "real" axis and the "imaginary" axis. (See Figure 2-20.) From this point of view, the complex number $z = x + iy$ (where $i^2 = - 1$) can be thought of as the point in the plane whose real coordinate is $x$ and whose imaginary coordinate is $y$. Addition of complex numbers reduces in this representation to addition of coordinates:
\begin{align}
\def\rp{\text{Real-part}}
\def\ip{\text{Imaginary-part}}
\rp(z_1 + z_2) &= \rp(z_1) + \rp(z_2) \\
\ip(z_1 + z_2) &= \ip(z_1) + \ip(z_2)
\end{align}
<p> When multiplying complex numbers, it is more natural to think in terms of representing a complex number in polar form, as a magnitude and an angle ($r$ and $A$ in Figure 2-20). The product of two complex numbers is the vector obtained by stretching one complex number by the length of the other and then rotating it through the angle of the other:
\begin{align}
\def\mg{\text{Magnitude}}
\def\ag{\text{Angle}}
\mg(z_1 * z_2) &= \mg(z_1) * \mg(z_2) \\
\ag(z_1 * z_2) &= \ag(z_1) + \ag(z_2)
\end{align}
<p> Thus, there are two different representations for complex numbers, which are appropriate for different operations. Yet, from the viewpoint of someone writing a program that uses complex numbers, the principle of data abstraction suggests that all the operations for manipulating complex numbers should be available regardless of which representation is used by the computer. For example, it is often useful to be able to find the magnitude of a complex number that is specified by rectangular coordinates. Similarly, it is often useful to be able to determine the real part of a complex number that is specified by polar coordinates.
<div class="figure">
<img src="http://mitpress.mit.edu/sicp/full-text/book/ch2-Z-G-59.gif">
<p> <b>Figure 2.20:</b> Complex numbers as points in the plane.
</div>
<p> To design such a system, we can follow the same data-abstraction strategy we followed in designing the rational-number package in section 2-1-1. Assume that the operations on complex numbers are implemented in terms of four selectors: <tt>real-part</tt>, <tt>imag-part</tt>, <tt>magnitude</tt>, and <tt>angle</tt>. Also assume that we have two procedures for constructing complex numbers: <tt>make-from-real-imag</tt> returns a complex number with specified real and imaginary parts, and <tt>make-from-mag-ang</tt> returns a complex number with specified magnitude and angle. These procedures have the property that, for any complex number <tt>z</tt>, both
<div id="scheme-reconstruct-real-imag">
(make-from-real-imag (real-part z) (imag-part z))
</div>
<script>
no_output_prompt("scheme-reconstruct-real-imag");
</script>
<p> and
<div id="scheme-reconstruct-magnitude-angle">
(make-from-mag-ang (magnitude z) (angle z))
</div>
<script>
no_output_prompt("scheme-reconstruct-magnitude-angle");
</script>
<p> produce complex numbers that are equal to <tt>z</tt>.
<p> Using these constructors and selectors, we can implement arithmetic on complex numbers using the ``abstract data'' specified by the constructors and selectors, just as we did for rational numbers in section 2-1-1. As shown in the formulas above, we can add and subtract complex numbers in terms of real and imaginary parts while multiplying and dividing complex numbers in terms of magnitudes and angles:
<div id="scheme-define-complex-arith">
(define (add-complex z1 z2)
(make-from-real-imag (+ (real-part z1) (real-part z2))
(+ (imag-part z1) (imag-part z2))))
(define (sub-complex z1 z2)
(make-from-real-imag (- (real-part z1) (real-part z2))
(- (imag-part z1) (imag-part z2))))
(define (mul-complex z1 z2)
(make-from-mag-ang (* (magnitude z1) (magnitude z2))
(+ (angle z1) (angle z2))))
(define (div-complex z1 z2)
(make-from-mag-ang (/ (magnitude z1) (magnitude z2))
(- (angle z1) (angle z2))))
</div>
<script>
prompt("scheme-define-complex-arith");
</script>
<p> To complete the complex-number package, we must choose a representation and we must implement the constructors and selectors in terms of primitive numbers and primitive list structure. There are two obvious ways to do this: We can represent a complex number in ``rectangular form'' as a pair (real part, imaginary part) or in ``polar form'' as a pair (magnitude, angle). Which shall we choose?
<p> In order to make the different choices concrete, imagine that there are two programmers, Ben Bitdiddle and Alyssa P. Hacker, who are independently designing representations for the complex-number system. Ben chooses to represent complex numbers in rectangular form. With this choice, selecting the real and imaginary parts of a complex number is straightforward, as is constructing a complex number with given real and imaginary parts. To find the magnitude and the angle, or to construct a complex number with a given magnitude and angle, he uses the trigonometric relations
\begin{align}
x &= r \cos A \qquad \qquad r=\sqrt{x^2+y^2} \\
y &= r \sin A \qquad \qquad A=\arctan{y,x}
\end{align}
<p> which relate the real and imaginary parts (x, y) to the magnitude and the angle (r, A).<a name="footnote_link_2-44" class="footnote_link" href="#footnote_2-44">44</a> Ben's representation is therefore given by the following selectors and constructors:
<div id="scheme-define-rectangular-selectors">
(define (real-part z) (car z))
(define (imag-part z) (cdr z))
(define (magnitude z)
(sqrt (+ (square (real-part z)) (square (imag-part z)))))
(define (angle z)
(atan (imag-part z) (real-part z)))
(define (make-from-real-imag x y) (cons x y))
(define (make-from-mag-ang r a)
(cons (* r (cos a)) (* r (sin a))))
</div>
<script>
prompt("scheme-define-rectangular-selectors");
</script>
<p> Alyssa, in contrast, chooses to represent complex numbers in polar form. For her, selecting the magnitude and angle is straightforward, but she has to use the trigonometric relations to obtain the real and imaginary parts. Alyssa's representation is:
<div id="scheme-define-polar-selectors">
(define (real-part z)
(* (magnitude z) (cos (angle z))))
(define (imag-part z)
(* (magnitude z) (sin (angle z))))
(define (magnitude z) (car z))
(define (angle z) (cdr z))
(define (make-from-real-imag x y)
(cons (sqrt (+ (square x) (square y)))
(atan y x)))
(define (make-from-mag-ang r a) (cons r a))
</div>
<script>
prompt("scheme-define-polar-selectors");
</script>
<p> The discipline of data abstraction ensures that the same implementation of <tt>add-complex</tt>, <tt>sub-complex</tt>, <tt>mul-complex</tt>, and <tt>div-complex</tt> will work with either Ben's representation or Alyssa's representation.
<h3> Tagged data </h3>
<p> One way to view data abstraction is as an application of the "principle of least commitment." In implementing the complex-number system in section 2-4-1, we can use either Ben's rectangular representation or Alyssa's polar representation. The abstraction barrier formed by the selectors and constructors permits us to defer to the last possible moment the choice of a concrete representation for our data objects and thus retain maximum flexibility in our system design.
<p> The principle of least commitment can be carried to even further extremes. If we desire, we can maintain the ambiguity of representation even <em>after</em> we have designed the selectors and constructors, and elect to use both Ben's representation <em>and</em> Alyssa's representation. If both representations are included in a single system, however, we will need some way to distinguish data in polar form from data in rectangular form. Otherwise, if we were asked, for instance, to find the <tt>magnitude</tt> of the pair <tt>(3,4)</tt>, we wouldn't know whether to answer $5$ (interpreting the number in rectangular form) or $3$ (interpreting the number in polar form). A straightforward way to accomplish this distinction is to include a <em>type tag</em> ---the symbol <tt>rectangular</tt> or <tt>polar</tt>---as part of each complex number. Then when we need to manipulate a complex number we can use the tag to decide which selector to apply.
<p> In order to manipulate tagged data, we will assume that we have procedures <tt>type-tag</tt> and <tt>contents</tt> that extract from a data object the tag and the actual contents (the polar or rectangular coordinates, in the case of a complex number). We will also postulate a procedure <tt>attach-tag</tt> that takes a tag and contents and produces a tagged data object. A straightforward way to implement this is to use ordinary list structure:
<div id="scheme-define-type-tag">
(define (attach-tag type-tag contents)
(cons type-tag contents))
(define (type-tag datum)
(if (pair? datum)
(car datum)
(error "Bad tagged datum -- TYPE-TAG" datum)))
(define (contents datum)
(if (pair? datum)
(cdr datum)
(error "Bad tagged datum -- CONTENTS" datum)))
</div>
<script>
prompt("scheme-define-type-tag");
</script>
<p> Using these procedures, we can define predicates <tt>rectangular?</tt> and <tt>polar?</tt>, which recognize polar and rectangular numbers, respectively:
<div id="scheme-define-recognise-rectangular-polar-tags">
(define (rectangular? z)
(eq? (type-tag z) 'rectangular))
(define (polar? z)
(eq? (type-tag z) 'polar))
</div>
<script>
promptDep("scheme-define-recognise-rectangular-polar-tags", ["scheme-define-type-tag"]);
</script>
<p> With type tags, Ben and Alyssa can now modify their code so that their two different representations can coexist in the same system. Whenever Ben constructs a complex number, he tags it as rectangular. Whenever Alyssa constructs a complex number, she tags it as polar. In addition, Ben and Alyssa must make sure that the names of their procedures do not conflict. One way to do this is for Ben to append the suffix <tt>rectangular</tt> to the name of each of his representation procedures and for Alyssa to append <tt>polar</tt> to the names of hers. Here is Ben's revised rectangular representation from section 2-4-1:
<div id="scheme-define-rectangular-tagged-selectors">
(define (real-part-rectangular z) (car z))
(define (imag-part-rectangular z) (cdr z))
(define (magnitude-rectangular z)
(sqrt (+ (square (real-part-rectangular z))
(square (imag-part-rectangular z)))))
(define (angle-rectangular z)
(atan (imag-part-rectangular z)
(real-part-rectangular z)))
(define (make-from-real-imag-rectangular x y)
(attach-tag 'rectangular (cons x y)))
(define (make-from-mag-ang-rectangular r a)
(attach-tag 'rectangular
(cons (* r (cos a)) (* r (sin a)))))
</div>
<script>
prompt("scheme-define-rectangular-tagged-selectors", ["scheme-define-type-tag"]);
</script>
<p> and here is Alyssa's revised polar representation:
<div id="scheme-define-polar-tagged-selectors">
(define (real-part-polar z)
(* (magnitude-polar z) (cos (angle-polar z))))
(define (imag-part-polar z)
(* (magnitude-polar z) (sin (angle-polar z))))
(define (magnitude-polar z) (car z))
(define (angle-polar z) (cdr z))
(define (make-from-real-imag-polar x y)
(attach-tag 'polar
(cons (sqrt (+ (square x) (square y)))
(atan y x))))
(define (make-from-mag-ang-polar r a)
(attach-tag 'polar (cons r a)))
</div>
<script>
prompt("scheme-define-polar-tagged-selectors", ["scheme-define-type-tag"]);
</script>
<p> Each generic selector is implemented as a procedure that checks the tag of its argument and calls the appropriate procedure for handling data of that type. For example, to obtain the real part of a complex number, <tt>real-part</tt> examines the tag to determine whether to use Ben's <tt>real-part-rectangular</tt> or Alyssa's <tt>real-part-polar</tt>. In either case, we use <tt>contents</tt> to extract the bare, untagged datum and send this to the rectangular or polar procedure as required:
<div id="scheme-define-tagged-complex-selectors">
(define (real-part z)
(cond ((rectangular? z)
(real-part-rectangular (contents z)))
((polar? z)
(real-part-polar (contents z)))
(else (error "Unknown type -- REAL-PART" z))))
(define (imag-part z)
(cond ((rectangular? z)
(imag-part-rectangular (contents z)))
((polar? z)
(imag-part-polar (contents z)))
(else (error "Unknown type -- IMAG-PART" z))))
(define (magnitude z)
(cond ((rectangular? z)
(magnitude-rectangular (contents z)))
((polar? z)
(magnitude-polar (contents z)))
(else (error "Unknown type -- MAGNITUDE" z))))
(define (angle z)
(cond ((rectangular? z)
(angle-rectangular (contents z)))
((polar? z)
(angle-polar (contents z)))
(else (error "Unknown type -- ANGLE" z))))
</div>
<script>
prompt("scheme-define-tagged-complex-selectors", ["scheme-define-recognise-rectangular-polar-tags", "scheme-define-rectangular-tagged-selectors", "scheme-define-polar-tagged-selectors"]);
</script>
<p> To implement the complex-number arithmetic operations, we can use the same procedures <tt>add-complex</tt>, <tt>sub-complex</tt>, <tt>mul-complex</tt>, and <tt>div-complex</tt> from section 2-4-1, because the selectors they call are generic, and so will work with either representation. For example, the procedure <tt>add-complex</tt> is still
<div id="scheme-define-tagged-add-complex">
(define (add-complex z1 z2)
(make-from-real-imag (+ (real-part z1) (real-part z2))
(+ (imag-part z1) (imag-part z2))))
</div>
<script>
prompt("scheme-define-tagged-add-complex", ["scheme-define-tagged-complex-selectors"]);
</script>
<p> Finally, we must choose whether to construct complex numbers using Ben's
representation or Alyssa's representation. One reasonable choice is to
construct rectangular numbers whenever we have real and imaginary parts and to
construct polar numbers whenever we have magnitudes and angles:
<div id="scheme-define-tagged-constructors">
(define (make-from-real-imag x y)
(make-from-real-imag-rectangular x y))
(define (make-from-mag-ang r a)
(make-from-mag-ang-polar r a))
</div>
<script>
prompt("scheme-define-tagged-constructors");
</script>
<p>
<div class="figure">
<img src="http://mitpress.mit.edu/sicp/full-text/book/ch2-Z-G-62.gif">
<p> <b>Figure 2.21:</b> Structure of the generic complex-arithmetic system.
</div>
<p> The resulting complex-number system has the structure shown in Figure 2-21. The system has been decomposed into three relatively independent parts: the complex-number-arithmetic operations, Alyssa's polar implementation, and Ben's rectangular implementation. The polar and rectangular implementations could have been written by Ben and Alyssa working separately, and both of these can be used as underlying representations by a third programmer implementing the complex-arithmetic procedures in terms of the abstract constructor/selector interface.
<p> Since each data object is tagged with its type, the selectors operate on the data in a generic manner. That is, each selector is defined to have a behavior that depends upon the particular type of data it is applied to. Notice the general mechanism for interfacing the separate representations: Within a given representation implementation (say, Alyssa's polar package) a complex number is an untyped pair (magnitude, angle). When a generic selector operates on a number of <tt>polar</tt> type, it strips off the tag and passes the contents on to Alyssa's code. Conversely, when Alyssa constructs a number for general use, she tags it with a type so that it can be appropriately recognized by the higher-level procedures. This discipline of stripping off and attaching tags as data objects are passed from level to level can be an important organizational strategy, as we shall see in section 2-5.
<h3> Data-Directed Programming and Additivity </h3>
<p> The general strategy of checking the type of a datum and calling an appropriate procedure is called <em>dispatching on type</em> . This is a powerful strategy for obtaining modularity in system design. Oh the other hand, implementing the dispatch as in section 2-4-2 has two significant weaknesses. One weakness is that the generic interface procedures (<tt>real-part</tt>, <tt>imag-part</tt>, <tt>magnitude</tt>, and <tt>angle</tt>) must know about all the different representations. For instance, suppose we wanted to incorporate a new representation for complex numbers into our complex-number system. We would need to identify this new representation with a type, and then add a clause to each of the generic interface procedures to check for the new type and apply the appropriate selector for that representation.
<p> Another weakness of the technique is that even though the individual representations can be designed separately, we must guarantee that no two procedures in the entire system have the same name. This is why Ben and Alyssa had to change the names of their original procedures from section 2-4-1.
<p> The issue underlying both of these weaknesses is that the technique for implementing generic interfaces is not <tt>additive</tt> . The person implementing the generic selector procedures must modify those procedures each time a new representation is installed, and the people interfacing the individual representations must modify their code to avoid name conflicts. In each of these cases, the changes that must be made to the code are straightforward, but they must be made nonetheless, and this is a source of inconvenience and error. This is not much of a problem for the complex-number system as it stands, but suppose there were not two but hundreds of different representations for complex numbers. And suppose that there were many generic selectors to be maintained in the abstract-data interface. Suppose, in fact, that no one programmer knew all the interface procedures or all the representations. The problem is real and must be addressed in such programs as large-scale data-base-management systems.
<p> What we need is a means for modularizing the system design even further. This is provided by the programming technique known as <tt>data-directed programming</tt> . To understand how data-directed programming works, begin with the observation that whenever we deal with a set of generic operations that are common to a set of different types we are, in effect, dealing with a two-dimensional table that contains the possible operations on one axis and the possible types on the other axis. The entries in the table are the procedures that implement each operation for each type of argument presented. In the complex-number system developed in the previous section, the correspondence between operation name, data type, and actual procedure was spread out among the various conditional clauses in the generic interface procedures. But the same information could have been organized in a table, as shown in Figure 2-22.
<p> Data-directed programming is the technique of designing programs to work with such a table directly. Previously, we implemented the mechanism that interfaces the complex-arithmetic code with the two representation packages as a set of procedures that each perform an explicit dispatch on type. Here we will implement the interface as a single procedure that looks up the combination of the operation name and argument type in the table to find the correct procedure to apply, and then applies it to the contents of the argument. If we do this, then to add a new representation package to the system we need not change any existing procedures; we need only add new entries to the table.
<div class="figure">
<img src="http://mitpress.mit.edu/sicp/full-text/book/ch2-Z-G-63.gif">
<p> <b>Figure 2.22:</b> Table of operations for the complex-number system.
</div>
<p> To implement this plan, assume that we have two procedures, <tt>put</tt> and <tt>get</tt>, for manipulating the operation-and-type table:
<ul>
<li>
<p> <tt>(put <em><op></em> <em><type></em> <em><item></em>)</tt> installs the <tt><em><item></em></tt> in the table, indexed by the <tt><em><op></em></tt> and the <tt><em><type></em></tt>.
</li>
<li>
<p> <tt>(get <em><op></em> <em><type></em>)</tt> looks up the <em><op></em>, <em><type></em> entry in the table and returns the item found there. If no item is found, <tt>get</tt> returns false.
</li>
</ul>
<p> For now, we can assume that <tt>put</tt> and <tt>get</tt> are included in our language. In Chapter 3 (section 3-3-3, Exercise 3-24) we will see how to implement these and other operations for manipulating tables.
<p> Here is how data-directed programming can be used in the complex-number system. Ben, who developed the rectangular representation, implements his code just as he did originally. He defines a collection of procedures, or a <tt>package</tt> , and interfaces these to the rest of the system by adding entries to the table that tell the system how to operate on rectangular numbers. This is accomplished by calling the following procedure:
<div id="scheme-define-install-rectangular-package">
(define (install-rectangular-package)
;; internal procedures
(define (real-part z) (car z))
(define (imag-part z) (cdr z))
(define (make-from-real-imag x y) (cons x y))
(define (magnitude z)
(sqrt (+ (square (real-part z))
(square (imag-part z)))))
(define (angle z)
(atan (imag-part z) (real-part z)))
(define (make-from-mag-ang r a)
(cons (* r (cos a)) (* r (sin a))))
;; interface to the rest of the system
(define (tag x) (attach-tag 'rectangular x))
(put 'real-part '(rectangular) real-part)
(put 'imag-part '(rectangular) imag-part)
(put 'magnitude '(rectangular) magnitude)
(put 'angle '(rectangular) angle)
(put 'make-from-real-imag 'rectangular
(lambda (x y) (tag (make-from-real-imag x y))))
(put 'make-from-mag-ang 'rectangular
(lambda (r a) (tag (make-from-mag-ang r a))))
'done)
</div>
<script>
prompt("scheme-define-install-rectangular-package");
</script>
<p> Notice that the internal procedures here are the same procedures from section 2-4-1 that Ben wrote when he was working in isolation. No changes are necessary in order to interface them to the rest of the system. Moreover, since these procedure definitions are internal to the installation procedure, Ben needn't worry about name conflicts with other procedures outside the rectangular package. To interface these to the rest of the system, Ben installs his <tt>real-part</tt> procedure under the operation name <tt>real-part</tt> and the type <tt>(rectangular)</tt>, and similarly for the other selectors.<a name="footnote_link_2-45" class="footnote_link" href="#footnote_2-45">45</a> The interface also defines the constructors to be used by the external system.<a name="footnote_link_2-46" class="footnote_link" href="#footnote_2-46">46</a> These are identical to Ben's internally defined constructors, except that they attach the tag.
<p> Alyssa's polar package is analogous:
<div id="scheme-define-install-polar-package">
(define (install-polar-package)
;; internal procedures
(define (magnitude z) (car z))
(define (angle z) (cdr z))
(define (make-from-mag-ang r a) (cons r a))
(define (real-part z)
(* (magnitude z) (cos (angle z))))
(define (imag-part z)
(* (magnitude z) (sin (angle z))))
(define (make-from-real-imag x y)
(cons (sqrt (+ (square x) (square y)))
(atan y x)))
;; interface to the rest of the system
(define (tag x) (attach-tag 'polar x))
(put 'real-part '(polar) real-part)
(put 'imag-part '(polar) imag-part)
(put 'magnitude '(polar) magnitude)
(put 'angle '(polar) angle)
(put 'make-from-real-imag 'polar
(lambda (x y) (tag (make-from-real-imag x y))))
(put 'make-from-mag-ang 'polar
(lambda (r a) (tag (make-from-mag-ang r a))))
'done)
</div>
<script>
prompt("scheme-define-install-polar-package");
</script>
<p> Even though Ben and Alyssa both still use their original procedures defined with the same names as each other's (e.g., <tt>real-part</tt>), these definitions are now internal to different procedures (see section 1-1-8), so there is no name conflict.
<p> The complex-arithmetic selectors access the table by means of a general ``operation'' procedure called <tt>apply-generic</tt>, which applies a generic operation to some arguments. <tt>apply-generic</tt> looks in the table under the name of the operation and the types of the arguments and applies the resulting procedure if one is present:<a name="footnote_link_2-47" class="footnote_link" href="#footnote_2-47">47</a>
<div id="scheme-defne-apply-generic">
(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))))))
</div>
<script>
prompt("scheme-defne-apply-generic");
</script>
<p> Using <tt>apply-generic</tt>, we can define our generic selectors as follows:
<div id="scheme-define-generic-selectors">
(define (real-part z) (apply-generic 'real-part z))
(define (imag-part z) (apply-generic 'imag-part z))
(define (magnitude z) (apply-generic 'magnitude z))
(define (angle z) (apply-generic 'angle z))
</div>
<script>
prompt("scheme-define-generic-selectors");
</script>
<p> Observe that these do not change at all if a new representation is added to the system.
<p> We can also extract from the table the constructors to be used by the programs external to the packages in making complex numbers from real and imaginary parts and from magnitudes and angles. As in section 2-4-2, we construct rectangular numbers whenever we have real and imaginary parts, and polar numbers whenever we have magnitudes and angles:
<div id="scheme-define-generic-constructors">
(define (make-from-real-imag x y)
((get 'make-from-real-imag 'rectangular) x y))
(define (make-from-mag-ang r a)
((get 'make-from-mag-ang 'polar) r a))
</div>
<script>
prompt("scheme-define-generic-constructors");
</script>
<p>
<div class="exercise">
<p> <b>Exercise 2.73:</b> Section 2-3-2 described a program that performs symbolic differentiation:
<div id="scheme-define-deriv">
(define (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))))
<more rules can be added here>
(else (error "unknown expression type -- DERIV" exp))))
</div>
<script>
prompt("scheme-define-deriv");
</script>
<p> We can regard this program as performing a dispatch on the type of the expression to be differentiated. In this situation the "type tag" of the datum is the algebraic operator symbol (such as <tt>+</tt>) and the operation being performed is <tt>deriv</tt>. We can transform this program into data-directed style by rewriting the basic derivative procedure as
<div id="scheme-define-generic-deriv">
(define (deriv exp var)
(cond ((number? exp) 0)
((variable? exp) (if (same-variable? exp var) 1 0))
(else ((get 'deriv (operator exp)) (operands exp)
var))))
(define (operator exp) (car exp))
(define (operands exp) (cdr exp))
</div>
<script>
prompt("scheme-define-generic-deriv");
</script>
<ul>
<li>
<p> Explain what was done above. Why can't we assimilate the predicates <tt>number?</tt> and <tt>same-variable?</tt> into the data-directed dispatch?
</li>
<li>
<p> Write the procedures for derivatives of sums and products, and the auxiliary code required to install them in the table used by the program above.
</li>
<li>
<p> Choose any additional differentiation rule that you like, such as the one for exponents (Exercise 2-56), and install it in this data-directed system.
</li>
<li>
<p> In this simple algebraic manipulator the type of an expression is the algebraic operator that binds it together. Suppose, however, we indexed the procedures in the opposite way, so that the dispatch line in <tt>deriv</tt> looked like
<div id="scheme-different-dispatch-deriv">
((get (operator exp) 'deriv) (operands exp) var)
</div>
<script>
no_output_frozen_prompt("scheme-different-dispatch-deriv")
</script>
What corresponding changes to the derivative system are required?
</li>
</ul>
</div>
<p>
<div class="exercise">
<p> <b>Exercise 2.74:</b> Insatiable Enterprises, Inc., is a highly decentralized conglomerate company consisting of a large number of independent divisions located all over the world. The company's computer facilities have just been interconnected by means of a clever network-interfacing scheme that makes the entire network appear to any user to be a single computer. Insatiable's president, in her first attempt to exploit the ability of the network to extract administrative information from division files, is dismayed to discover that, although all the division files have been implemented as data structures in Scheme, the particular data structure used varies from division to division. A meeting of division managers is hastily called to search for a strategy to integrate the files that will satisfy headquarters' needs while preserving the existing autonomy of the divisions.
<p> Show how such a strategy can be implemented with data-directed programming. As an example, suppose that each division's personnel records consist of a single file, which contains a set of records keyed on employees' names. The structure of the set varies from division to division. Furthermore, each employee's record is itself a set (structured differently from division to division) that contains information keyed under identifiers such as <tt>address</tt> and <tt>salary</tt>. In particular:
<ul>
<li>
<p> Implement for headquarters a <tt>get-record</tt> procedure that retrieves a specified employee's record from a specified personnel file. The procedure should be applicable to any division's file. Explain how the individual divisions' files should be structured. In particular, what type information must be supplied?
</li>
<li>
<p> Implement for headquarters a <tt>get-salary</tt> procedure that returns the salary information from a given employee's record from any division's personnel file. How should the record be structured in order to make this operation work?
</li>
<li>
<p> Implement for headquarters a <tt>find-employee-record</tt> procedure. This should search all the divisions' files for the record of a given employee and return the record. Assume that this procedure takes as arguments an employee's name and a list of all the divisions' files.
</li>
<li>
<p> When Insatiable takes over a new company, what changes must be made in order to incorporate the new personnel information into the central system?
</li>
</ul>
</div>
<h4> Message passing </h4>
<p> The key idea of data-directed programming is to handle generic operations in programs by dealing explicitly with operation-and-type tables, such as the table in Figure 2-22. The style of programming we used in section 2-4-2 organized the required dispatching on type by having each operation take care of its own dispatching. In effect, this decomposes the operation-and-type table into rows, with each generic operation procedure representing a row of the table.
<p> An alternative implementation strategy is to decompose the table into columns and, instead of using "intelligent operations" that dispatch on data types, to work with "intelligent data objects" that dispatch on operation names. We can do this by arranging things so that a data object, such as a rectangular number, is represented as a procedure that takes as input the required operation name and performs the operation indicated. In such a discipline, <tt>make-from-real-imag</tt> could be written as
<div id="scheme-define-make-intelligent-complex-from-real-imag">
(define (make-from-real-imag x y)
(define (dispatch op)
(cond ((eq? op 'real-part) x)
((eq? op 'imag-part) y)
((eq? op 'magnitude)
(sqrt (+ (square x) (square y))))
((eq? op 'angle) (atan y x))
(else
(error "Unknown op -- MAKE-FROM-REAL-IMAG" op))))
dispatch)
</div>
<script>
prompt("scheme-define-make-intelligent-complex-from-real-imag");
</script>
<p> The corresponding <tt>apply-generic</tt> procedure, which applies a generic operation to an argument, now simply feeds the operation's name to the data object and lets the object do the work:<a name="footnote_link_2-48" class="footnote_link" href="#footnote_2-48">48</a>
<div id="scheme-define-message-passing-apply-generic">
(define (apply-generic op arg) (arg op))
</div>
<script>
prompt("scheme-define-message-passing-apply-generic");
</script>
<p> Note that the value returned by <tt>make-from-real-imag</tt> is a procedure---the internal <tt>dispatch</tt> procedure. This is the procedure that is invoked when <tt>apply-generic</tt> requests an operation to be performed.
<p> This style of programming is called <tt>message passing</tt> . The name comes from the image that a data object is an entity that receives the requested operation name as a ``message.'' We have already seen an example of message passing in section 2-1-3, where we saw how <tt>cons</tt>, <tt>car</tt>, and <tt>cdr</tt> could be defined with no data objects but only procedures. Here we see that message passing is not a mathematical trick but a useful technique for organizing systems with generic operations. In the remainder of this chapter we will continue to use data-directed programming, rather than message passing, to discuss generic arithmetic operations. In Chapter 3 we will return to message passing, and we will see that it can be a powerful tool for structuring simulation programs.
<div class="exercise">
<p> <b>Exercise 2.75:</b> Implement the constructor <tt>make-from-mag-ang</tt> in message-passing style. This procedure should be analogous to the <tt>make-from-real-imag</tt> procedure given above.
</div>
<p>
<div class="exercise">
<p> <b>Exercise 2.76:</b> As a large system with generic operations evolves, new types of data objects or new operations may be needed. For each of the three strategies---generic operations with explicit dispatch, data-directed style, and message-passing-style---describe the changes that must be made to a system in order to add new types or new operations. Which organization would be most appropriate for a system in which new types must often be added? Which would be most appropriate for a system in which new operations must often be added?
</div>
<br>
<br>
<hr>
<div id="footnotes">
<h3 id='Notes'> Notes </h3>
<div id="footnote_2-43" class="footnote">
<p> <a href="#footnote_link_2-43" class="footnote_backlink">43</a> In actual computational systems, rectangular form is preferable to polar form most of the time because of roundoff errors in conversion between rectangular and polar form. This is why the complex-number example is unrealistic. Nevertheless, it provides a clear illustration of the design of a system using generic operations and a good introduction to the more substantial systems to be developed later in this chapter.
</div>
<div id="footnote_2-44" class="footnote">
<p> <a href="#footnote_link_2-44" class="footnote_backlink">44</a> The arctangent function referred to here, computed by Scheme's atan procedure, is defined so as to take two arguments y and x and to return the angle whose tangent is y/x. The signs of the arguments determine the quadrant of the angle.
</div>
<div id="footnote_2-45" class="footnote">
<p> <a href="#footnote_link_2-45" class="footnote_backlink">45</a> We use the list (rectangular) rather than the symbol rectangular to allow for the possibility of operations with multiple arguments, not all of the same type.
</div>
<div id="footnote_2-46" class="footnote">
<p> <a href="#footnote_link_2-46" class="footnote_backlink">46</a> The type the constructors are installed under needn't be a list because a constructor is always used to make an object of one particular type.
</div>
<div id="footnote_2-47" class="footnote">
<p> <a href="#footnote_link_2-47" class="footnote_backlink">47</a> <tt>Apply-generic</tt> uses the dotted-tail notation described in Exercise 2-20, because different generic operations may take different numbers of arguments. In <tt>apply-generic</tt>, <tt>op</tt> has as its value the first argument to <tt>apply-generic</tt> and <tt>args</tt> has as its value a list of the remaining arguments.
<p> <tt>Apply-generic</tt> also uses the primitive procedure <tt>apply</tt>, which takes two arguments, a procedure and a list. <tt>Apply</tt> applies the procedure, using the elements in the list as arguments. For example,
<div id="scheme-define-plus-1234">
(apply + (list 1 2 3 4))
</div>
<script>
prompt("scheme-define-plus-1234");
</script>
<p> returns 10.
</div>
<div id="footnote_2-48" class="footnote">
<p> <a href="#footnote_link_2-48" class="footnote_backlink">48</a> One limitation of this organization is it permits only generic procedures of one argument.
</div> </div>
<hr>
<p> <a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/deed.en_US" target="_blank"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/88x31.png" /></a><br /> Based on Structure and Interpretation of Computer Programs, a work at <a xmlns:dct="http://purl.org/dc/terms/" href="http://mitpress.mit.edu/sicp/" rel="dct:source" target="_blank">http://mitpress.mit.edu/sicp/</a>.
</div>
<a href="https://github.com/zodiac/isicp" target="_blank"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_green_007200.png" alt="Fork me on GitHub"></a>
</body>
</html>