-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathchapter4.tex
More file actions
1802 lines (1511 loc) · 67.6 KB
/
chapter4.tex
File metadata and controls
1802 lines (1511 loc) · 67.6 KB
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
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
%% Thinking Forth
%% Copyright (C) 2004 Leo Brodie
%% Initial transcription by Nils M Holm
%% Based on OCR scans by John Hogerhuis
%%
%% Chapter: Four - Detailed Design/Problem Solving
\chapter{Detailed~Design/\penalty 0\allowhyphens Problem~Solving}\Chapmark{4}
\index{D!Detailed design|(}%
\index{D!Detailed design!problem solving techniques|(}%
\begin{tfquot}
\emph{Trivial:} I can see how to do this. I just don't know how long it
will take.\\
\emph{Non-trivial:} I haven't a \emph{clue} how to do this!
%!! right-justify paragraph
\begin{flushright}
---\emph{Operating philosophy developed at the Laboratory\\
Automation and Instrumentation Design Group,\\
Chemistry Dept., Virginia Polytechnic Institute and State University}
\end{flushright}
\end{tfquot}
\initial Once you've decided upon the components in your application, your next
step is to design those components. In this chapter we'll apply
problem-solving techniques to the detailed design of a \Forth{}
application. This is the time for pure invention, the part that many of
us find the most fun. There's a special satisfaction in going to the mat
with a non-trivial problem and coming out the victor.
In English it's difficult to separate an idea from the words used to
express the idea. In writing a \Forth{} application it's difficult to
separate the detailed design phase from implementation, because we tend to
design in \Forth{}. For this reason, we'll get a bit ahead of ourselves in
this chapter by not only presenting a problem but also designing a
solution to it, right on through to the coded implementation.
\section{Problem-Solving Techniques}%
\index{P!Problem-solving techniques|(}%
Even neophytes can solve programming problems without devoting any
conscious thought to problem solving techniques. So what's the point in
studying techniques of problem solving? To quicken the process. By
thinking about the \emph{ways} in which we solve problems, apart from
the problems themselves, we enrich our subconscious storehouse of
techniques.
\person{G. Polya} has written several books on problem solving, especially of
the mathematical problem. The most accessible of these is
\emph{How to Solve It} \cite{polya}.%
\index{P!Polya, G.}%
\index{H!How to@\emph{How to Solve It} (Polya)}
Although solving a mathematical problem isn't quite the same as
solving a software problem, you'll find some valuable suggestions there.
The following series of tips summarize several techniques recommended by
the science of problem solving:
\begin{tip}
Determine your goal.
\end{tip}
Know what you're trying to accomplish. As we saw in \Chap{2}, this
step can be detailed further:
\index{I!Interface definition}
Determine the data interfaces: Know what data will be required to
accomplish the goal, and make sure those data are available (input).
Know what data the function is expected to produce (output). For a single
definition, this means writing the stack-effect comment.
Determine the rules;\index{R!Rule definition}
review all the facts that you know. In Chapter Two we described the
rates for computing the cost of a phone call along with the rules for
applying the rates.
\begin{tip}
Picture the problem as a whole.
\end{tip}
In the \emph{analysis} phase we separated the problem into its parts, to
clarify our understanding of each piece. We are now entering the
\emph{synthesis} phase. We must visualize the problem as a whole.
Try to retain as much information about the problem in your mind
as possible. Use words, phrases, figures and tables, or any kind of graphic
representation of the data and/or rules to help you see the maximum
information at a glance. Fill your mind to bursting with the requirements
of the problem you need to solve, the way you might fill your lungs with
air.
Now hold that mental image, the way you might hold your breath.
One of two things will happen:
You may see the solution in a flash of insight. Great! Exhale a sigh
of relief and proceed directly to implementation. Or\dots{}, the problem is
too complex or too unfamiliar to be solved so easily. In this case, you'll
have to turn your attention to analogies and partial solutions. As you do
so, it's important that you have already concentrated on the problem's
requirements all at once, engraving these requirements on your mental
retina.
\begin{tip}
Develop a plan.
\end{tip}
If the solution didn't come at a glance, the next step is to determine the
approach that you will take to solve it. Set a course for action and avoid
the trap of fumbling about aimlessly.
The following tips suggest several approaches you might consider.
\begin{tip}
Think of an analogous problem.
\index{A!Analogous problems}
\end{tip}
Does this problem sound familiar? Have you written a definition like it
before? Figure out what parts of the problem are familiar, and in what
ways this problem might differ. Try to remember how you solved it
before, or how you solved something like it.
\begin{tip}
Work forward.
\end{tip}
The normal, obvious way to attack a problem is by beginning with the
known, and proceeding to the unknown. In deciding which horse to bet
on, you'd begin with their recent histories, their current health, and so on,
apply weights to these various factors and arrive at a favorite.
\begin{tip}
Work backward.
\end{tip}
More complicated problems present many possible ways to go with the
incoming data. How do you know which route will take you closer to the
solution? You don't. This class of problem is best solved by working
backward (\Fig{fig4-1}).
\wepsfiga{fig4-1}{A problem that is easier to solve backward than
forward.}
%!! include Figure 4-1 here
\begin{tip}
Believe.
\end{tip}
Belief is a necessary ingredient for successfully working backward. We'll
illustrate with a famous mathematical problem. Suppose we have two
containers. The containers have no graduation marks, but one holds nine
gallons and the other holds four gallons. Our task is to measure out exactly
six gallons of water from the nearby stream in one of the containers
(\Fig{fig4-2}).
\wepsfigt{fig4-2}{Two containers.}
%!! include Figure 4-2 here
Try to solve this on your own before reading further.
How can we get a ``six'' out of a ``nine'' and a ``four''? We can
start out working forward\index{W!Working forwards}, by mentally
transferring water from one container to the other. For example, if we
fill the large container twice from the small container, we'll get
eight gallons. If we fill the nine-gallon container to the brim, then
empty enough water to fill the four-gallon container, we'll have
exactly five gallons in the large container.
These ideas are interesting, but they haven't gotten us six gallons.
And it's not clear how they will get us six gallons.
Let's try working backward.\index{W!Working backwards|(}
We assume we've measured six gallons
of water, and it's sitting in the large container (it won't fit in the
small one!). Now, how did we get it there? What was the state of our
containers one step previously?
There are only two possibilities (\Fig{fig4-3}):
%!! there's certainly some better way to do ordered lists in TeX
\begin{enumerate}
\item The four-gallon container was full, and we just added it to the large
container. This implies that we already had two gallons in the large
container. Or\dots{}
%!! line break? % enumerate suspend/resume?
\item The nine-gallon container was full, and we just poured off three gallons
into the small container.
\end{enumerate}
Which choice? Let's make a guess. The first choice requires a two-gallon
measurement, the second requires a three-gallon measurement. In our initial
playing around, we never saw a unit like two. But we did see a difference
of one, and one from four is three. Let's go with version b.
Now comes the real trick. We must make ourselves \emph{believe} without
doubt that we have arrived at the situation described. We have just
poured off three gallons into the small container. Suspending all disbelief,
we concentrate on how we did it.
How can we pour off three gallons into the small container? If there
had already been one gallon in the small container! Suddenly we're over
the hump. The simple question now is, how do we get one gallon in the
small container? We must have started with a full nine-gallon container,
poured off four gallons twice, leaving one gallon. Then we transferred the
one gallon to the small container.
\wepsfigt{fig4-3}{Achieving the end result.}
%!! include Figure 4-3 here
%!! include cartoon of page 103 here
\wepsfigp{img4-103}{Intent on a complicated problem.}
Our final step should be to check our logic by running the problem
forwards again.
Here's another benefit of working backward:\index{W!Working backwards|)}
If the problem is unsolvable,
working backward helps you quickly prove that it has no solution.
\begin{tip}
Recognize the auxiliary problem.\index{A!Auxiliary problems}
\end{tip}
Before we've solved a problem, we have only a hazy notion of what
steps---or even how many steps---may be required. As we become more
familiar with the problem, we begin to recognize that our problem
includes one or more subproblems that somehow seem different from the
main outline of the proposed procedure.
In the problem we just solved, we recognized two subproblems: filling
the small container with one gallon and then filling the large container
with six gallons.
Recognizing these smaller problems, sometimes called
``auxiliary problems,''\index{A!Auxiliary problems}
is an important problem-solving technique. By identifying
the subproblem, we can assume it has a straightforward solution.
Without stopping to determine what that solution might be, we forge
ahead with our main problem.
(\Forth{} is ideally suited to this technique, as we'll see.)
\begin{tip}
Step back from the problem.
\end{tip}
It's easy to get so emotionally attached to one particular solution that we
forget to keep an open mind.
The literature of problem solving often employs the example of the
nine dots. It stumped me, so I'll pass it along. We have nine dots arranged
as shown in \Fig{fig4-4}. The object is to draw straight lines that
touch or pass through all nine dots, without lifting the pen off the paper.
The constraint is that you must touch all nine dots with only four lines.
\wepsfiga{fig4-4}{The nine dots problem.}
%!! include Figure 4-4 here
You can sit a good while and do no better than the almost-right
\Fig{fig4-5}. If you concentrate really hard, you may eventually conclude
that the problem is a trick---there's no solution.
\wepsfiga{fig4-5}{Not quite right.}
%!! include Figure 4-5 here
But if you sit back and ask yourself,
%!! indent paragraph
\begin{tfquot}
``Am I cheating myself out a useful tack by being narrow-minded? Am I
assuming any constraints not specified in the problem? What constraints
might they be?''
\end{tfquot}
then you might think of extending some of the lines beyond the perimeter
of the nine dots.
\begin{tip}
Use whole-brain thinking.\index{W!Whole-brain thinking}
\end{tip}
When a problem has you stumped and you seem to be getting nowhere,
relax, stop worrying about it, perhaps even forget about it for a while.
Creative people have always noted that their best ideas seem to
come out of the blue, in bed or in the shower. Many books on problem
solving suggest relying on the subconscious for the really difficult
problems.
Contemporary theories on brain functions explore the differences
between rational, conscious thought (which relies on the manipulation of
symbols) and subconscious thought (which correlates perceptions to
previously stored information, recombining and relinking knowledge in
new and useful ways).
\person{Leslie Hart}\index{H!Hart, Leslie} \cite{hart75} explains the
difficulty of solving a large problem by means of logic:
%!! begin indented paragraph
\begin{tfquot}
A huge load is placed on that one small function of the brain that can be
brought into the attention zone for a period. The feat is possible, like
the circus act, but it seems more sensible to\dots{} use the full
resources of our glorious neocortex\dots{} the multibillion-neuron
capacity of the brain.
\dots{} The work aspect lies in providing the brain with raw input, as in
observing, reading, collecting data, and reviewing what others have
achieved. Once in, [subconscious] procedures take over, simultaneously,
automatically, outside of the attention zone.
\dots{} It seems apparent\dots{} that a search is going on during the
interval, though not necessarily continuously, much as in a large
computer. I would hazard the guess that the search ramifies, starts and
stops, reaches dead ends and begins afresh, and eventually assembles an
answer that is evaluated and then popped into conscious attention---often
in astonishingly full-blown detail.
\end{tfquot}
%!! end indented paragraph
\begin{tip}
Evaluate your solution. Look for other solutions.
\end{tip}
You may have found one way of skinning the cat. There may be other
ways, and some of them may be better.
Don't invest too much effort in your first solution without asking
yourself for a second opinion.
\index{P!Problem-solving techniques|)}%
\index{D!Detailed design!problem solving techniques|)}
%!! include cartoon of page 106 here
\wepsfigp{img4-106}{``I'm not just sleeping. I'm using my neocortex.''}
\section{Interview with a Software Inventor}
\index{B!Burgess, Donald A.|(}
\begin{interview}
\person{Donald A. Burgess}, owner and president of Scientek Instrumentation,
Inc.:
%!! begin indented paragraph
\begin{tfquot}
I have a few techniques I've found useful over the years in designing
anything, to keep myself flexible.
My first rule is, ``Nothing is impossible.''
My second rule is, ``Don't forget, the object is to make a buck.''
First examine the problem, laying out two or three approaches on paper.
Then try the most appealing one, to see if it works. Carry it through. Then
deliberately go all the way back to the beginning, and start over.
Starting over has two values. First, it gives you a fresh approach. You
either gravitate back to the way you started, or the way you started
gravitates toward the new way.
Second, the new approach may show all kinds of powerful possibilities. Now
you have a benchmark. You can look at both approaches and compare the
advantages of both. You're in a better position to judge.
Getting stuck comes from trying too hard to follow a single approach.
Remember to say, ``I want this kumquat crusher to be different. Let's
reject the traditional design as not interesting. Let's try some crazy
ideas.''
The best thing is to start drawing pictures. I draw little men. That keeps
it from looking like ``data'' and interfering with my thinking process. The
human mind works exceptionally well with analogies. Putting things in
context keeps you from getting stuck within the confines of any language,
even \Forth{}.
When I want to focus my concentration, I draw on little pieces of paper.
When I want to think in broad strokes, to capture the overall flow, I draw
on great big pieces of paper. These are some of the crazy tricks I use to keep
from getting stagnant.
When I program in \Forth{}, I spend a day just dreaming, kicking around
ideas. Usually before I start typing, I sketch it out in general terms. No
code, just talk. Notes to myself.
Then I start with the last line of code first. I describe what I would like
to do, as close to English as I can. Then I use the editor to slide this
definition towards the bottom of the screen, and begin coding the internal
words. Then I realize that's a lousy way to do it. Maybe I split my top word
into two and transfer one of them to an earlier block so I can use it earlier.
I run the hardware if I have it; otherwise I simulate it.
\Forth{} requires self-discipline. You have to stop diddling with the
keyboard. \Forth{} is so willing to do what I tell it to, I'll tell it to
do all kinds of ridiculous things that have nothing to do with where I'm
trying to go. At those times I have to get away from the keyboard.
\Forth{} lets you play. That's fine, chances are you'll get some ideas. As
long as you keep yourself from playing as a habit. Your head is a whole lot
better than the computer for inventing things.
\end{tfquot}
\end{interview}%
\index{B!Burgess, Donald A.|)}
\section{Detailed Design}%
\index{L!Lexicons|(}
We're now at the point in the development cycle at which we've decided
we need a component (or a particular word). The component will consist
of a number of words, some of which (those that comprise the lexicon) will
be used by other components and some of which (the internal words) will
be only used within this component.
Create as many words as necessary to obey the following tip:
\begin{tip}
Each definition should perform a simple, well-defined task.
\end{tip}%
\index{D!Detailed design!steps in|(}
Here are the steps generally involved in designing a component:
%!! there's certainly some better way to do ordered lists in TeX
\begin{enumerate}
\item Based on the required functions, decide on the names and syntax for the
external definitions (define the interfaces).
\item Refine the conceptual model by describing the algorithm(s) and data
structure(s).
\item Recognize auxiliary definitions.
\item Determine what auxiliary definitions and techniques are already available.
\item Describe the algorithm with pseudocode.
\item Implement it by working backwards from existing definitions to the inputs.
\item Implement any missing auxiliary definitions.
\item If the lexicon contains many names with strong elements in common,
design and code the commonalities as internal definitions, then implement
the external definitions.
\end{enumerate}%
\index{D!Detailed design!steps in|)}
We'll discuss the first two steps in depth. Then we'll engage in an
extended example of designing a lexicon.
\section{\Forth{} Syntax}%
\index{D!Detailed design!forth@\Forth{} syntax|(}%
\index{F!forth@\Forth{}!syntax|(}%
\index{S!Syntax \Forth{}|(}
At this point in the development cycle you must decide how the words in
your new lexicon will be used in context. In doing so, keep in mind how
the lexicon will be used by subsequent components.
\begin{tip}
In designing a component, the goal is to create a lexicon that will make your
later code readable and easy to maintain.
\end{tip}
Each component should be designed with components that use it in mind.
You must design the syntax of the lexicon so that the words make sense
when they appear in context. Hiding interrelated information within the
component will ensure maintainability, as we've seen.
At the same time, observe \Forth{}'s own syntax. Rather than insisting
on a certain syntax because it seems familiar, you may save
yourself from writing a lot of unnecessary code by choosing a syntax that
\Forth{} can support without any special effort on your part.
Here are some elementary rules of \Forth{}'s natural syntax:
\begin{tip}
Let numbers precede names.
\index{N!Numbers-precede-names syntax rule}
\end{tip}
%!! include cartoon of page 110 here
Words that require a numeric argument will naturally expect to find that
number on the stack. Syntactically speaking, then, the number should
precede the name. For instance, the syntax of the word \forth{SPACES}, which
emits ``$n$'' number of spaces, is
\begin{Code}
20 spaces
\end{Code}
Sometimes this rule violates the order that our ear is accustomed to
hearing. For instance, the \Forth{} word \forth{+} expects to be preceded
by both arguments, as in
\begin{Code}
3 4 +
\end{Code}
\index{P!Postfix notation|(}
This ordering, in which values precede operators, is called ``postfix.''
\Forth{}, in its magnanimity, won't \emph{insist} upon postfix notation.
You could redefine \forth{+} to expect one number in the input stream,
like this:
\begin{Code}
3 + 4
\end{Code}
by defining it so:
\begin{Code}
: + bl word number drop + ;
\end{Code}
(where \forthb{WORD} is 79/83 Standard, returning an address, and
\forthb{NUMBER} returns a double-length value as in the 83 Standard
Uncontrolled Reference Words).
Fine. But you wouldn't be able to use this definition inside other colon
definitions or pass it arguments, thereby defeating one of \Forth{}'s
major advantages.
Frequently, ``noun'' type words pass their addresses (or any type of
pointer) as a stack argument to ``verb'' type words. The \Forth{}-like
syntax of
\begin{quote}
%!! sans-serif
{\sf ``noun'' ``verb''}
\end{quote}
\wepsfigxx{img4-110}
will generally prove easiest to implement because of the stack.\medbreak
In some cases this word order\index{W!Words:!ordering} sounds
unnatural. For instance, suppose we have a file named
\forth{INVENTORY}. One thing we can do with that file is \forth{SHOW}
it; that is, format the information in pretty columns. If
\forth{INVENTORY} passes a pointer to \forth{SHOW}, which acts upon
it, the syntax becomes
\begin{Code}
inventory show
\end{Code}
If your spec demands the English word-order,\index{W!Words:!ordering}
\Forth{} offers ways to
achieve it. But most involve new levels of complexity. Sometimes the
best thing to do is to choose a better name. How about
\begin{Code}
inventory report
\end{Code}
(We've made the ``pointer'' an adjective, and the ``actor'' a noun.)
If the requirements insist on the syntax
\begin{Code}
show inventory
\end{Code}
we have several options. \forth{SHOW} might set a flag and
\forth{INVENTORY} would act according to the flag. Such an approach has
certain disadvantages, especially that \forth{INVENTORY} must be ``smart''
enough to know all the possible actions that might be taken on it. (We'll
treat these problems in Chapters \ref{chapter-7} and \ref{chapter-8}.)%
\index{P!Postfix notation|)}
Or, \forth{SHOW} might look ahead at the next word in the input stream.
We'll discuss this approach in a tip, ``Avoid expectations,'' later in this
chapter.
Or, the recommended approach, \forth{SHOW} might set an ``execution
variable'' that \forth{INVENTORY} will then execute. (We'll discuss vectored
execution in \Chap{7}.)
\begin{tip}
Let text follow names.
\index{T!Text-follows-names syntax rule}
\end{tip}
If the \Forth{} interpreter finds a string of text that is neither a number
nor a predefined word, it will abort with an error message. For this
reason, an undefined string must be preceded by a defined word.
An example is \forth{."} (dot-quote), which precedes the text it will
later print. Another example is \forthb{CREATE} (as well as all defining
words), which precedes the name that is, at the moment, still undefined.
The rule also applies to defined words that you want to refer to, but
not execute in the usual way. An example is \forthb{FORGET}, as in
\begin{Code}
forget task
\end{Code}
Syntactically, \forthb{FORGET} must precede \forth{TASK} so that
\forth{TASK} doesn't execute.
\begin{tip}
Let definitions consume their arguments.
\end{tip}
This syntax rule is more a convention of good \Forth{} programming
than a preference of \Forth{}.
\index{D!Definitions-consume-arguments syntax rule}
Suppose you're writing the word \forth{LAUNCH}, which requires the
number of a launch pad and fires the appropriate rocket. You want the
definition to look roughly like this:
\begin{Code}
: launch ( pad# -- ) load aim fire ;
\end{Code}
Each of the three internal definitions will require the same argument, the
launch pad number. You'll need two \forthb{DUP}s somewhere. The question
is where? If you put them inside \forth{LOAD} and \forth{AIM}, then you
can keep them out of \forth{LAUNCH}, as in the definition above. If you
leave them out of \forth{LOAD} and \forth{AIM}, you'll have to define:
\begin{Code}
: launch ( pad# -- ) dup load dup aim fire ;
\end{Code}
By convention, the latter version is preferable, because \forth{LOAD} and
\forth{AIM} are cleaner. They do what you expect them to do. Should you
have to define \forth{READY}, you can do it so:
\begin{Code}
: ready ( pad# -- ) dup load aim ;
\end{Code}
and not
\begin{Code}
: ready ( pad# -- ) load aim drop ;
\end{Code}
\begin{tip}
Use zero-relative numbering.
\end{tip}
By habit we humans number things starting with one: ``first, second,
third,'' etc. Mathematical models, on the other hand, work more naturally
\index{Z!Zero-relative numbering|(}
when starting with zero. Since computers are numeric processors, software
becomes easier to write when we use zero-relative numbering.
To illustrate, suppose we have a table of eight-byte records. The first
record occupies the first eight bytes of the table. To compute its
starting address, we add ``0'' to \forth{TABLE}. To compute the starting
address of the ``second'' record, we add ``8'' to \forth{TABLE}.
\wepsfiga{fig4-6}{A table of 8-byte records.}
%!! include Figure 4-6 here
\medbreak
It's easy to derive a formula to achieve these results:
%!! should be two columns, right-hand side sans-serif
\bigskip
\begin{tabular}{@{}l@{ }l@{}r}
\sf first record starts at: & $\mathsf{0 \times 8} = {}$ & \sf 0 \\
\sf second record starts at: & $\mathsf{1 \times 8} = {}$ & \sf 8 \\
\sf third record starts at: & $\mathsf{2 \times 8} = {}$ & \sf 16 \\
\end{tabular}
\bigskip
\noindent
We can easily write a word which converts a record\# into the address
where that record begins:
\begin{Code}
: record ( record# -- adr )
8 * table + ;
\end{Code}
Thus in computer terms it makes sense to call the ``first record'' the 0th
record.
If your requirements demand that numbering start at one, that's
fine. Use zero-relative numbering throughout your design and then, only
in the ``user lexicons'' (the set of words that the end-user will use)
include the conversion from zero-to one-relative numbering:
\begin{Code}
: item ( n -- adr ) 1- record ;
\end{Code}
\index{Z!Zero-relative numbering|)}
\begin{tip}
Let addresses precede counts.\index{A!Address-precedes-counts syntax rule}
\end{tip}
Again, this is a convention, not a requirement of \Forth{}, but such
conventions are essential for readable code. You'll find examples of this
rule in the words \forthb{TYPE}, \forthb{ERASE}, and \forthb{BLANK}.
\begin{tip}
Let sources precede destinations.
\index{S!Source-precede-destination syntax rule}
\end{tip}
Another convention for readability. For instance, in some systems, the
phrase
\begin{Code}
22 37 copy
\end{Code}
copies Screen 22 to Screen 37. The syntax of \forth{CMOVE} incorporates both
this convention and the previous convention:
\begin{Code}[commandchars=\&\{\}]
source destination count &poorbf{cmove}
\end{Code}
\index{E!Expectations-in-input-stream syntax rule|(}
\begin{tip}
Avoid expectations (in the input stream).
\end{tip}
Generally try to avoid creating words that presume there will be other
words in the input stream.
Suppose your color computer represents blue with the value 1, and
light-blue with 9. You want to define two words: \forth{BLUE} will return
1; \forth{LIGHT} may precede \forth{BLUE} to produce 9.
In \Forth{}, it would be possible to define \forth{BLUE} as a constant, so
that when executed it always returns 1.\program{color1}
\begin{Code}
1 Constant blue
\end{Code}
And then define \forth{LIGHT} such that it looks for the next word in the
input stream, executes it, and ``ors'' it with 8 (the logic of this will
become apparent when we visit this example again, later in the book):
\begin{Code}
: light ( "color" -- color-value ) \ precedes a color
' execute 8 or ;
\end{Code}
\noindent (For novices: The apostrophe in the definition of \forth{LIGHT}
is a \Forth{} word called ``tick.'' Tick is a dictionary-search word; it
takes a name and looks it up in the dictionary, returning the address
where the definition resides. Used in this definition, it will find the
address of the word following \forth{LIGHT}---for instance,
\forth{BLUE}---and pass this address to the word \forthb{EXECUTE}, which
will execute \forth{BLUE}, pushing a one onto the stack. Having ``sucked
up'' the operation of \forth{BLUE}, \forth{LIGHT} now ``or''s an 8 into
the 1, producing a 9.)
This definition will work when invoked in the input stream, but special
handling is required if we want to let \forth{LIGHT} be invoked within a
colon definition, as in:
\begin{Code}
: editing light blue border ;
\end{Code}
Even in the input stream, the use of \forth{EXECUTE} here will cause a
crash if \forth{LIGHT} is accidentally followed by something other than a
defined word.
The preferred technique, if you're forced to use this particular
syntax, is to have \forth{LIGHT} set a flag, and have \forth{BLUE}
determine whether that flag was set, as we'll see later on.
There will be times when looking ahead in the input stream is desirable,
even necessary. (The proposed \forth{TO} solution is often implemented
this way \cite{rosen82}.)
But generally, avoid expectations. You're setting yourself up for
disappointment.
\index{E!Expectations-in-input-stream syntax rule|)}
\begin{tip}
Let commands perform themselves.
\end{tip}%
\index{C!Compilers|(}%
This rule is a corollary to ``Avoid expectations.'' It's one of
\Forth{}'s philosophical quirks to let words do their own work. Witness
the \Forth{} compiler (the function that compiles colon definitions),
caricatured in \Fig{fig4-7}. It has very few rules:
\wepsfigt{fig4-7}{The traditional compiler vs. the \Forth{} compiler.}
%!! include Figure 4-7 here
%!! this paragraph should be an indented, unordered list
\begin{itemize}
\item Scan for the next word in the input stream and look it up in the
dictionary.
\item If it's an ordinary word, \emph{compile} its address.
\item If it's an ``immediate'' word, \emph{execute} it.
\item If it's not a defined word, try to convert it to a number and
compile it as a literal.
\item If it's not a number, abort with an error message.
\end{itemize}
Nothing is mentioned about compiling-words such as \forthb{IF},
\forthb{ELSE}, \forthb{THEN}, etc. The colon compiler doesn't know about
these words. It merely recognizes certain words as ``immediate'' and
executes them, letting them do their own work. (See \emph{Starting
\Forth{}}, Chapter Eleven, ``How to Control the Colon Compiler.'')
The compiler doesn't even ``look for'' semicolon to know when to stop
compiling. Instead it \emph{executes} semicolon, allowing it to do the
work of ending the definition and shutting off the compiler.
There are two tremendous advantages to this approach. First, the
compiler is so simple it can be written in a few lines of code. Second,
there's no limit on the number of compiling words you can add at any
time, simply by making them immediate. Thus, even \Forth{}'s colon
compiler is extensible!
\index{I!Interpreters|(}
\Forth{}'s text interpreter and \Forth{}'s address interpreter also
adhere to this same rule.
The following tip is perhaps the most important in this chapter:
\begin{tip}
Don't write your own interpreter/compiler when you can use \Forth{}'s.
\end{tip}
One class of applications answers a need for a special purpose
language---a self-contained set of commands for doing one particular
thing. An example is a machine-code assembler. Here you have a large
group of commands, the mnemonics, with which you can describe the
instructions you want assembled. Here again, \Forth{} takes a radical
departure from mainstream philosophy.
Traditional assemblers\index{A!Assemblers} are special-purpose
interpreters---that is, they are complicated programs that scan the
assembly-language listing looking for recognized mnemonics such as
\code{ADD}, \code{SUB}, \code{JMP}, etc., and
assemble machine instructions correspondingly. The \Forth{} assembler,
however, is merely a lexicon of \Forth{} words that themselves assemble
machine instructions.
There are many more examples of the special purpose language,
each specific to individual applications. For instance:
%!! begin ordered list
\begin{enumerate}
\item If you're building an Adventure-type game, you'd want to write a
language that lets you create and describe monsters and rooms, etc. You
might create a defining word called \forth{ROOM} to be used like this:
\begin{Code}
room dungeon
\end{Code}
Then create a set of words to describe the room's attributes by building
unseen data structures associated with the room:
\begin{Code}[commandchars=\&\{\}]
east-of dragon-lair
west-of bridge
containing pot-o-gold
&textrm{etc.}
\end{Code}
%!! 'etc.' should not be part of the code, should it?
The commands of this game-building language can simply be \Forth{}
words, with \Forth{} as the interpreter.
% typo: originally, ``WORDS'' was upper case. Doesn't make sense here.
\item If you're working with Programmable Array Logic (PAL) devices,
\index{P!Programmable Array Logic (PAL)}
you'd like a form of notation that lets you describe the behavior of
the output pins in logical terms, based on the states of the input
pins. A PAL programmer was written with wonderful simplicity in
\Forth{} by \person{Michael Stolowitz} \cite{stolowitz82}.
\index{S!Stolowitz, Michael}
\item If you must create a series of user menus to drive your application,
you might want to first develop a menu-compiling language. The words of
this new language allow an application programmer to quickly program the
needed menus---while hiding information about how to draw borders, move
the cursor, etc.
\end{enumerate}
All of these examples can be coded in \Forth{} as lexicons, using the
normal \Forth{} interpreter, without having to write a special-purpose
interpreter or compiler.
\index{C!Compilers|)}
\index{M!Moore, Charles|(}
\begin{interview}
\person{Moore}:
\begin{tfquot}
A simple solution is one that does not obscure the problem with
irrelevancies. It's conceivable that something about the problem requires
a unique interpreter. But every time you see a unique interpreter, it
implies that there is something particularly awkward about the problem.
And that is almost never the case.
If you write your own interpreter, the interpreter is almost certainly the
most complex, elaborate part of your entire application. You have switched
from solving a problem to writing an interpreter.
I think that programmers like to write interpreters. They like to do these
elaborate difficult things. But there comes a time when the world is going
to have to quit programming keypads and converting numbers to binary,
and start solving problems.
\end{tfquot}
\end{interview}%
\index{M!Moore, Charles|)}%
\index{D!Detailed design!forth@\Forth{} syntax|)}%
\index{F!forth@\Forth{}!syntax|)}%
\index{S!Syntax \Forth{}|)}%
\index{I!Interpreters|)}%
\index{L!Lexicons|)}
\section{Algorithms and Data Structures}%
\index{A!Algorithms|(}%
\index{D!Detailed design!algorithms|(}
In \Chap{2} we learned how to describe a problem's requirements in terms
of interfaces and rules. In this section we'll refine the conceptual model
for each component into clearly defined algorithms and data structures.
An algorithm is a procedure, described as a finite number of rules, for
accomplishing a certain task. The rules must be unambiguous and guaranteed
to terminate after a finite number of applications. (The word is named for
the ninth century Persian mathematician \person{al-Khowarizmi}.)
An algorithm lies halfway between the imprecise directives of human
speech, such as ``Please sort these letters chronologically,'' and the
precise directives of computer language, such as ``\forth{BEGIN 2DUP < IF}
\dots{}'' etc. The algorithm for sorting letters chronologically might be
this:
\begin{enumerate}
\item Take an unsorted letter and note its date.
\item Find the correspondence folder for that month and year.
\item Flip through the letters in the folder, starting from the front, until
you find the first letter dated later than your current letter.
\item Insert your current letter just in front of the letter dated later.
(If the folder is empty, just insert the letter.)
\end{enumerate}
There may be several possible algorithms for the same job. The algorithm
given above would work fine for folders containing ten or fewer letters,
but for folders with a hundred letters, you'd probably resort to a more
efficient algorithm, such as this:
\begin{enumerate}
\item (same)
\item (same)
\item If the date falls within the first half of the month, open the
folder a third of the way in. If the letter you find there is dated later
than your current letter, search forward until you find a letter dated the
same or before your current letter. Insert your letter at that point. If
the letter you find is dated earlier than your current letter, search
backward\dots{}
\end{enumerate}
\dots{} You get the point. This second algorithm is more complicated than
the first. But in execution it will require fewer steps on the average
(because you don't have to search clear from the beginning of the folder
every time) and therefore can be performed faster.
\index{D!Data structures:!defined|(}
A data structure is an arrangement of data or locations for data,
organized especially to match the problem. In the last example, the file
cabinet containing folders and the folders containing individual letters
can be thought of as data structures.
\index{D!Data structures:!defined|)}%
The new conceptual model includes the filing cabinets and folders
(data structures) plus the steps for doing the filing (algorithms).
\index{A!Algorithms|)}%
\index{D!Detailed design!algorithms|)}
\section{Calculations vs. Data Structures vs. Logic}%
\index{C!Calculations|(}%
\index{D!Data structures:!calculation@vs. calculation vs. logic|(}%
\index{D!Detailed design!calculations|(}%
\index{D!Detailed design!data structures|(}%
\index{D!Detailed design!logic|(}%
\index{L!Logic|(}
We've stated before that the best solution to a problem is the simplest
adequate one; for any problem we should strive for the simplest
approach.
Suppose we must write code to fulfill this specification:
%!! sans-serif
\begin{Code}[fontfamily=cmss]
if the input argument is 1, the output is 10
if the input argument is 2, the output is 12
if the input argument is 3, the output is 14
\end{Code}
There are three approaches we could take:
\begin{description}
\item[Calculation]~
\begin{Code}
( n) 1- 2* 10 +
\end{Code}
\medbreak
\item[Data Structure]~
\begin{Code}
Create table 10 c, 12 c, 14 c,
( n) 1- table + c@
\end{Code}
\medbreak
\item[Logic]~
\begin{Code}
( n) CASE
1 OF 10 ENDOF
2 OF 12 ENDOF
3 OF 14 ENDOF ENDCASE
\end{Code}
\end{description}
In this problem, calculation is simplest. Assuming it is also adequate
(speed is not critical), calculation is best.
The problem of converting angles to sines and cosines can be implemented
more simply (at least in terms of lines of code and object size)
by calculating the answers than by using a data structure. But for many
applications requiring trig, it's faster to look up the answer in a table
stored in memory. In this case, the simplest \emph{adequate} solution is
using the data structure.
In \Chap{2} we introduced the telephone rate problem. In that
problem the rates appeared to be arbitrary, so we designed a data
structure:
\bigskip
%!! this should be a table; see pg 119
\begin{tabular}{lccc}
& \emph{Full Rate} & \emph{Lower Rate} & \emph{Lowest Rate} \\ \hline
First Min. & .30 & .22 & .12 \\ \hline
Add'1 Mins. & .12 & .10 & .06 \\ \hline
\end{tabular}\program{phone3}
\bigskip
\noindent Using a data structure was simpler than trying to invent a
formula by which these values could be calculated. And the formula might
prove wrong later. In this case, table-driven code is easier to maintain.
In \Chap{3} we designed a keystroke interpreter for our Tiny
Editor using a decision table:\program{editor3}
%!! this should be a table; see pg 119
%%typo: The original has here ``Cntrl''. Usually, it's Ctrl, and other chapters
%%use that name, too.
\medskip
\begin{tabular}{lll}
\emph{Key} & \emph{Not-Inserting} & \emph{Inserting} \\
\texttt{Ctrl-D} & \texttt{DELETE} & \texttt{INSERT-OFF} \\
\texttt{Ctrl-I} & \texttt{INSERT-ON} & \texttt{INSERT-OFF} \\
\texttt{backspace} & \texttt{BACKWARD} & \texttt{INSERT<} \\