about summary refs log tree commit diff stats
path: root/js/games/nluqo.github.io/~bh/v1ch4/v1ch4.html
blob: c36950f32cc53b8fbdd0d93c566a556582f2d942 (plain) (blame)
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
<HTML>
<HEAD>
<TITLE>Computer Science Logo Style vol 1 ch 4: Predicates</TITLE>
</HEAD>
<BODY>
<CITE>Computer Science Logo Style</CITE> volume 1:
<CITE>Symbolic Computing</CITE> 2/e Copyright (C) 1997 MIT
<H1>Predicates</H1>

<TABLE width="100%"><TR><TD>
<IMG SRC="../csls1.jpg" ALT="cover photo">
<TD><TABLE>
<TR><TD align="right"><CITE><A HREF="http://www.cs.berkeley.edu/~bh/">Brian
Harvey</A><BR>University of California, Berkeley</CITE>
<TR><TD align="right"><BR>
<TR><TD align="right"><A HREF="../pdf/v1ch04.pdf">Download PDF version</A>
<TR><TD align="right"><A HREF="../v1-toc2.html">Back to Table of Contents</A>
<TR><TD align="right"><A HREF="../v1ch3/v1ch3.html"><STRONG>BACK</STRONG></A>
chapter thread <A HREF="../v1ch5/v1ch5.html"><STRONG>NEXT</STRONG></A>
<TR><TD align="right"><A HREF="https://mitpress.mit.edu/books/computer-science-logo-style-second-edition-volume-1">MIT
Press web page for Computer Science Logo Style</A>
</TABLE></TABLE>

<HR>

<P>
By introducing variables in Chapter 3, we made it possible for a
procedure to operate on different data each time you invoke it.  But
the <EM>pattern</EM> of what the procedure does with the data remains
constant.  We can get even more variety out of our procedures if we
can vary the <EM>instructions</EM> that the procedure executes.  We
need a way to say, &quot;Sometimes do this; other times do that.&quot;

<P><H2>True or False</H2>

<P>One helpful metaphor is this:  When you invoke a command, you're giving
the computer an order.  &quot;Now hear this!  <CODE>Print</CODE> such-and-such!&quot;
But when you invoke an operation, you're asking the computer a <EM>
question.</EM>  &quot;What is the <CODE>first</CODE> member of such-and-such?&quot;

<P>In real life we single out as a special category <EM>
yes-or-no questions.</EM>
For example, these special questions form the basis of the
game Twenty Questions.  The corresponding
category in Logo is the <EM>predicate.</EM>
A predicate is an operation whose output is always either the word
<CODE>true</CODE> or the word <CODE>false</CODE>.

<P>For example, <CODE>listp</CODE> (pronounced &quot;list-pea&quot;) is a predicate
that takes one input.  The input can be any datum.  The output from
<CODE>listp</CODE> is <CODE>true</CODE> if the input is a list, <CODE>false</CODE> if the
input is a word.

<P><CODE>Wordp</CODE> is another predicate that takes one input.  The input can
be any datum.  The output from <CODE>wordp</CODE> is <CODE>true</CODE> if the input
is a word, <CODE>false</CODE> if the input is a list.  (This is the opposite
of the output from <CODE>listp</CODE>.)

<P><CODE>Emptyp</CODE> is also a predicate with one input.  The input can be any
datum. The output from <CODE>emptyp</CODE> is <CODE>true</CODE> if the input is
either the empty word or the empty list; if the input is anything
else, the output is <CODE>false</CODE>.

<P>You'll have noticed by now that predicates tend to have names ending
in the letter <CODE>p</CODE>.  This is not quite a universal rule, but almost.
It's a good idea to follow the same convention in naming your
own predicates.<SUP>*</SUP>

<P><SMALL><BLOCKQUOTE><SMALL><SUP>*</SUP>Many versions of Logo use a question mark at the end
of names of predicates, instead of a <CODE>p</CODE>.  For example, you may see <CODE>
list?</CODE> instead of <CODE>listp</CODE>.  Berkeley Logo accepts either form, but I
prefer the <CODE>p</CODE> version.</SMALL></BLOCKQUOTE></SMALL><P>

<P>As I'm describing primitive predicates, you might want to try them
out on the computer.  You can do experiments like this:

<P><PRE>? <U>print wordp &quot;hello</U>
true
? <U>print wordp [hello]</U>
false
? <U>print emptyp []</U>
true
? <U>print emptyp 0</U>
false
</PRE>

<P>Of course, most of the time you won't actually want to print
the output from a predicate.  You'll see in a few moments
how we can use a predicate to control the instructions carried out
in a procedure.

<P>But first here are a few more primitive predicates.  <CODE>Numberp</CODE> takes one
input, which can be any datum.  The output from <CODE>numberp</CODE> is <CODE>
true</CODE> if the input is a number, <CODE>false</CODE> otherwise.

<P><CODE>Equalp</CODE> takes two inputs, each of which can be any datum.  The output
from <CODE>equalp</CODE> is <CODE>true</CODE> if the two inputs are identical or if they're
both numbers and they're numerically equal.  That is, 3 and 3.0 are
numerically equal even though they're not identical words.  A list is
never equal to a word.

<P><PRE>? <U>print equalp 3 3.0</U>
true
? <U>print equalp &quot;hello [hello]</U>
false
? <U>print equalp &quot;hello first [hello]</U>
true
? <U>print equalp &quot; []</U>
false
? <U>print equalp [] butfirst [hello]</U>
true
</PRE>

<P>

<P>The equal sign (<CODE>=</CODE>) can
be used as an <EM>infix</EM> equivalent
of <CODE>equalp</CODE>:

<P><PRE>? <U>print &quot;hello = first [hello]</U>
true
? <U>print 2 = 3</U>
false
</PRE>

<P>As I mentioned in Chapter 2, if you use infix operations
you have to be careful about what is grouped with what.  It varies
between versions of Logo.  Here is an example I tried in Berkeley Logo:

<P><PRE>? <U>print first [hello] = &quot;hello</U>
f
</PRE>

<P>Among current commercial implementations, Object Logo and
Microworlds give the same answer <CODE>f</CODE>.  But here is the <EM>same</EM>
example in Logowriter:

<P><PRE>? <U>print first [hello] = &quot;hello</U>
true
</PRE>

<P>You can avoid confusion by using parentheses.  The following
instructions work reliably in any Logo:

<P><PRE>? <U>print (first [hello]) = &quot;hello</U>
true
? <U>print first ([hello] = &quot;hello)</U>
f
</PRE>

<P><CODE>Memberp</CODE> is a predicate with two inputs.  If the second input is a
list, then the first can be any datum.  If the second input is a word, then
the first must be a one-character word.  The output from <CODE>memberp</CODE>
is true if the first input is a member of the second input.

<P><PRE>? <U>print memberp &quot;rain [the rain in Spain]</U>
true
? <U>print memberp [the rain] [the rain in Spain]</U>
false
? <U>print memberp [the rain] [[the rain] in Spain]</U>
true
? <U>print memberp &quot;e &quot;please</U>
true
? <U>print memberp &quot;e &quot;plain</U>
false
</PRE>

<P><CODE>Lessp</CODE> and <CODE>greaterp</CODE> are predicates that take two inputs.
Both inputs must be numbers.  The output from <CODE>lessp</CODE> is <CODE>true</CODE> if
the first input is numerically less than the second; the output from <CODE>
greaterp</CODE> is true if the first is greater than the second.  Otherwise the
output is <CODE>false</CODE>.  (In particular, both <CODE>lessp</CODE> and <CODE>greaterp</CODE>
output <CODE>false</CODE> if the two inputs are equal.) The infix forms for <CODE>
lessp</CODE> (<CODE>&lt;</CODE>) and <CODE>greaterp</CODE> (<CODE>&gt;</CODE>) are also allowed.

<P><H2>Defining Your Own Predicates</H2>

<P>Here are two examples of how you can create new predicates:

<P><PRE>to vowelp :letter
output memberp :letter [a e i o u]
end

? <U>print vowelp &quot;e</U>
true
? <U>print vowelp &quot;g</U>
false

to oddp :number
output equalp (remainder :number 2) 1
end

? <U>print oddp 5</U>
true
? <U>print oddp 8</U>
false
</PRE>

<P><H2>Conditional Evaluation</H2>

<P> The main use of predicates is to
compute inputs to the primitive procedures <CODE>if</CODE> and <CODE>ifelse</CODE>.
We'll get to <CODE>ifelse</CODE> in a while, but first we'll explore <CODE>if</CODE>.

<P>
<CODE>If</CODE> is a command with two inputs.  The first input must
be either the word <CODE>true</CODE> or the word <CODE>false</CODE>.  The second input must
be a list containing Logo instructions.  If the first input is <CODE>true</CODE>,
the effect of <CODE>if</CODE> is to evaluate the instructions in the second input.
If the first input is <CODE>false</CODE>, <CODE>if</CODE> has no effect.

<P><PRE>? <U>if equalp 2 1+1 [print &quot;Yup.]</U>
Yup.
? <U>if equalp 3 2 [print &quot;Nope.]</U>
?
</PRE>

<P>Here is an example of how <CODE>if</CODE> can be used in a procedure.
This is an extension of the <CODE>converse</CODE> example in Chapter 3:

<P><PRE>to talk
local &quot;name
print [Please type your full name.]
make &quot;name readlist
print sentence [Your first name is] first :name
if (count :name) &gt; 2 ~
   [print sentence [Your middle name is] first bf :name]
print sentence [Your last name is] last :name
end

? <U>talk</U>
Please type your full name.
<U>George Washington</U>
Your first name is George
Your last name is Washington
? <U>talk</U>
Please type your full name.
<U>John Paul Jones</U>
Your first name is John
Your middle name is Paul
Your last name is Jones
</PRE>

<P><CODE>Talk</CODE> asks you to type your name and reads what you type
into a list, which is remembered in the variable named <CODE>
name</CODE>.  Your first and last names are printed as in the earlier
version.  If the list <CODE>:name</CODE> contains more than two members,
however, <CODE>talk</CODE> also prints the second member as your middle
name.  If <CODE>:name</CODE> contains only two members, <CODE>talk</CODE> assumes
that you don't have a middle name.

<P>&raquo;Write a procedure of your own that asks a question and uses <CODE>if</CODE> to
find out something about the response.

<P>You can use <CODE>if</CODE> to help in writing more interesting predicates.

<P><PRE>to about.computersp :sentence
if memberp &quot;computer :sentence [output &quot;true]
if memberp &quot;computers :sentence [output &quot;true]
if memberp &quot;programming :sentence [output &quot;true]
output &quot;false
end

? <U>print about.computersp [This book is about programming]</U>
true
? <U>print about.computersp [I like ice cream]</U>
false
?
</PRE>

<P>This procedure illustrates something I didn't explain before about <CODE>
output</CODE>: An <CODE>output</CODE> command finishes the evaluation of the
procedure in which it occurs.  For example, in <CODE>about.computersp</CODE>,
if the input sentence contains the word <CODE>computer</CODE>, the first <CODE>
if</CODE> evaluates the <CODE>output</CODE> instruction that is its second input.
The procedure immediately outputs the word <CODE>true</CODE>.  The remaining
instructions are not evaluated at all.

<P>&raquo;Write <CODE>past.tensep</CODE>, which takes a word as input and
outputs <CODE>true</CODE> if the word ends in <CODE>ed</CODE> or if it's one of a list of
exceptions, like <CODE>saw</CODE> and <CODE>went</CODE>.

<P>&raquo;Write <CODE>integerp</CODE>, which takes any Logo datum as input and
outputs <CODE>true</CODE> if and only if the datum is an integer (a number without a
fraction part).  Hint: a number with a fraction part will contain a decimal
point.

<P><H2>Choosing Between Alternatives</H2>

<P><CODE>If</CODE> gives the choice between carrying out some instructions and doing
nothing at all.  More generally, we may want to carry out either of <EM>
two</EM> sets of instructions, depending on the output from a predicate.
The primitive procedure <CODE>ifelse</CODE> meets this need.<SUP>*</SUP>  <CODE>Ifelse</CODE> is
an unusual primitive because it can be used either as a command or as an
operation.  We'll start with examples in which <CODE>ifelse</CODE> is used as a
command.

<P><SMALL><BLOCKQUOTE><SMALL><SUP>*</SUP>In some
versions of Logo, the name <CODE>if</CODE> is used both for the two-input command
discussed earlier and for the three-input one presented here.</SMALL></BLOCKQUOTE></SMALL><P><CODE>Ifelse</CODE> requires three inputs.  The first input must be either the word
<CODE>true</CODE> or the word <CODE>false</CODE>.  The second and third inputs must be
lists containing Logo instructions.  If the first input is <CODE>true</CODE>, the
effect of <CODE>if</CODE> is to evaluate the instructions in the second input.  If
the first input is <CODE>false</CODE>, the effect is to evaluate the instructions
in the third input.

<P><PRE>? <U>ifelse 4 = 2+2 [print &quot;Yup.] [print &quot;Nope.]</U>
Yup.
? <U>ifelse 4 = 3+5 [print &quot;Yup.] [print &quot;Nope.]</U>
Nope.
?
</PRE>

<P>
Here is an example of a procedure using <CODE>ifelse</CODE>:

<P><PRE>to groupie
local &quot;name
print [Hi, who are you?]
make &quot;name readlist
ifelse :name = [Ray Davies] ~
     [print [May I have your autograph?]] ~
     [print sentence &quot;Hi, first :name]
end

? <U>groupie</U>
Hi, who are you?
<U>Frank Sinatra</U>
Hi, Frank
? <U>groupie</U>
Hi, who are you?
<U>Ray Davies</U>
May I have your autograph?
</PRE>

<P>&raquo;Write an operation <CODE>color</CODE> that takes as input a word
representing a card, such as <CODE>10h</CODE> for the ten of hearts.  Its output
should be the word <CODE>red</CODE> if the card is a heart or a diamond, or <CODE>
black</CODE> if it's a spade or a club.

<P>&raquo;Write a conversational program that asks the user's name and figures
out how to address him or her.  For example:

<P><PRE>? <U>converse</U>
Hi, what's your name?
<U>Chris White</U>
Pleased to meet you, Chris.

? <U>converse</U>
Hi, what's your name?
<U>Ms. Grace Slick</U>
Pleased to meet you, Ms. Slick.

? <U>converse</U>
Hi, what's your name?
<U>J. Paul Getty</U>
Pleased to meet you, Paul.

? <U>converse</U>
Hi, what's your name?
<U>Sigmund Freud, M.D.</U>
Pleased to meet you, Dr. Freud.

? <U>converse</U>
Hi, what's your name?
<U>Mr. Lon Chaney, Jr.</U>
Pleased to meet you, Mr. Chaney.
</PRE>

<P>What should the program say if it meets Queen Elizabeth II?


<P><H2>Conditional Evaluation Another Way</H2>

<P>The use of <CODE>ifelse</CODE> in the <CODE>groupie</CODE> example above makes for
a rather long instruction line.  If you wanted to do several instructions
in each case, rather than just one <CODE>print</CODE>, the <CODE>if</CODE> line would become
impossible to read.  Logo provides another mechanism that is equivalent
to the <CODE>ifelse</CODE> command but may be easier to read.

<P><CODE>Test</CODE> is a command that takes one input.  The input must be
either the word <CODE>true</CODE> or the word <CODE>false</CODE>.  The effect of
<CODE>test</CODE> is just to remember what its input was in a special place.
You can think of this place as a variable without a name.  This
special variable is automatically local to the procedure from which
<CODE>test</CODE> is invoked.

<P><CODE>Iftrue</CODE> (abbreviation <CODE>ift</CODE>) is a command with one
input.  The input must be a list of Logo instructions.  The effect of
<CODE>iftrue</CODE> is to evaluate the instructions in its input only if the
unnamed variable set by the most recent <CODE>test</CODE> command in the same
procedure is <CODE>true</CODE>.  It is an error to use <CODE>iftrue</CODE> without
first using <CODE>test</CODE>.

<P><CODE>Iffalse</CODE> (abbreviation <CODE>iff</CODE>) is a command with one input, which
must be an instruction list.  The effect of <CODE>iffalse</CODE> is to evaluate
the instructions only if the remembered result of the most recent <CODE>test</CODE>
command is <CODE>false</CODE>.

<P><CODE>Iftrue</CODE> and <CODE>iffalse</CODE> can be invoked as many times as you like after
a <CODE>test</CODE>.  This allows you to break up a long sequence of conditionally evaluated
instructions into several instruction lines:

<P><PRE>to better.groupie
local &quot;name
print [Hi, who are you?]
make &quot;name readlist
test equalp :name [Ray Davies]
iftrue [print [Wow, can I have your autograph?]]
iftrue [print [And can I borrow a thousand dollars?]]
iffalse [print sentence [Oh, hello,] first :name]
end
</PRE>

<P><H2>About Those Brackets</H2>

<P>I hope that the problem I'm about to mention won't even have occurred
to you because you are so familiar with the idea of evaluation that
you understood right away.  But you'll probably have to explain it
to someone else, so I thought I'd bring it up here:

<P>

Some people get confused about why the second
input to <CODE>if</CODE> (and the second and third inputs to <CODE>ifelse</CODE>)
is surrounded by brackets but the first isn't.  That
is, they wonder, why don't we say

<P><PRE>if [equalp 2 3] [print &quot;really??]          ; (wrong!)
</PRE>

<P>They have this problem because someone lazily told them
to put brackets around the conditionally evaluated instructions without
ever explaining about brackets and quotation.

<P>I trust <EM>you</EM> aren't confused that way.  You understand that, as usual,
Logo evaluates the inputs to a procedure before invoking the procedure.  The
first input to <CODE>if</CODE> has to be either the word <CODE>true</CODE> or the word
<CODE>false</CODE>.  <EM>Before</EM> invoking <CODE>if</CODE>, Logo has to evaluate an
expression like <CODE>equalp 2 3</CODE> to compute the input.  (In this case, the
result output by <CODE>equalp</CODE> will be <CODE>false</CODE>.)  But if the <CODE>print</CODE>
instruction weren't quoted, Logo would evaluate it, too, <EM>before</EM>
invoking <CODE>if</CODE>.  That's not what we want.  We want the instruction list
<EM>itself</EM> to be the second input, so that <CODE>if</CODE> can decide whether
or not to carry out the instructions in the list.  So, as usual, we use
brackets to tell Logo to quote the list.

<P><CENTER><TABLE rules="groups" frame="void" border="2">
<THEAD>
<TR><TH>actual argument expression<TH>--&gt;<TH>actual argument value
<TBODY>
<TR><TD><CODE>equalp 2 3</CODE><TD>--&gt;<TD><CODE>false</CODE>
<TR><TD><CODE>[print &quot;really??]</CODE><TD>--&gt;<TD><CODE>[print &quot;really??]</CODE>
</TABLE></CENTER>

<P><H2>Logical Connectives</H2>

<P>Sometimes the condition under which you want to evaluate an instruction
is complicated.  You want to do it if <EM>both</EM> this <EM>and</EM> that
are true, or if <EM>either</EM> this <EM>or</EM> that is true.  Logo provides
operations for this purpose.

<P><CODE>And</CODE> is a predicate with two inputs.  Each input must be either the
word <CODE>true</CODE> or the word <CODE>false</CODE>.  The output from <CODE>and</CODE> is
<CODE>true</CODE> if both inputs are <CODE>true</CODE>; the output is <CODE>false</CODE> if
either input is <CODE>false</CODE>.  (<CODE>And</CODE> can take more than two inputs if
the entire expression is enclosed in parentheses.  In that case the output
from <CODE>and</CODE> will be <CODE>true</CODE> only if all of its inputs are <CODE>true</CODE>.)

<P><CODE>Or</CODE> is a predicate with two inputs.  Each input must be either the
word <CODE>true</CODE> or the word <CODE>false</CODE>.  The output from <CODE>or</CODE> is
<CODE>true</CODE> if either input is <CODE>true</CODE> (or both inputs are).  The
output is <CODE>false</CODE> if both inputs are <CODE>false</CODE>.  (Extra-input
<CODE>or</CODE> outputs <CODE>true</CODE> if any of its inputs are <CODE>true</CODE>, <CODE>
false</CODE> if all inputs are <CODE>false</CODE>.)

<P><CODE>Not</CODE> is a predicate with one input.  The input must be either the
word <CODE>true</CODE> or the word <CODE>false</CODE>.  The output from <CODE>not</CODE> is
the opposite of its input: <CODE>true</CODE> if the input is <CODE>false</CODE>, or
<CODE>false</CODE> if the input is <CODE>true</CODE>.

<P>

These three procedures are called <EM>logical connectives</EM> because
they connect logical expressions together into bigger ones.  (A <EM>
logical</EM> expression is one whose value is <CODE>true</CODE> or <CODE>
false</CODE>.) They can be useful in defining new predicates:

<P><PRE>to fullp :datum
output not emptyp :datum
end

to realwordp :datum
output and wordp :datum not numberp :datum
end

to digitp :datum
output and numberp :datum equalp count :datum 1
end
</PRE>

<P><H2><CODE>Ifelse</CODE> as an Operation</H2>

<P>So far, we have applied the idea of conditional evaluation only to
complete instructions.  It is also possible to choose between two
expressions to evaluate, by using <CODE>ifelse</CODE> as an
operation.

<P>When used as an operation, <CODE>ifelse</CODE> requires three inputs.  The first input
must be either the word <CODE>true</CODE> or the word <CODE>false</CODE>.  The second and third
inputs must be lists containing Logo expressions.  The output from
<CODE>ifelse</CODE> is the result of evaluating the second input, if the first input
is <CODE>true</CODE>, or the result of evaluating the third input, if the first
input is <CODE>false</CODE>.

<P><PRE>? <U>print sentence &quot;It's ifelse 2=3 [&quot;correct] [&quot;incorrect]</U>
It's incorrect
? <U>print ifelse emptyp [] [sum 2 3] [product 6 7]</U>
5
</PRE>

<P>Here is one of the classic examples of a procedure in which <CODE>ifelse</CODE> is
used as an operation.  This procedure is an operation that takes
a number as its input; it outputs the <EM>absolute value</EM> of the
number:

<P><PRE>to abs :number
output ifelse :number&lt;0 [-:number] [:number]
end
</PRE>

<P><H2>Expression Lists and Plumbing Diagrams</H2>

<P><CODE>If</CODE> and <CODE>ifelse</CODE> require <EM>instruction lists</EM> or <EM>
expression lists</EM> as inputs.  This requirement is part of their semantics,
not part of the syntax of an instruction.  Just as the arithmetic operators
require numbers as inputs (semantics), but those numeric values can be
provided either as explicit numbers in the instruction or as the result of
an arbitrarily complicated subexpression (syntax), the procedures that
require instruction or expression lists as input don't interpret those
inputs until after Logo has set up the plumbing for the instructions that
invoke them.

<P>What does that mean?  Consider the instruction

<P><PRE>ifelse &quot;false [&quot;stupid &quot;list] [print 23]
</PRE>

<P>Even though the second input to <CODE>ifelse</CODE>--that is, the first
of the two literal lists--makes no sense as an instruction list, this
instruction will work correctly without printing an error message.  The Logo
interpreter knows that <CODE>ifelse</CODE> accepts three inputs, and it sees that
the three input expressions provided are a literal (quoted) word and two
literal lists.  It sets up the plumbing without paying any attention to the
semantics of <CODE>ifelse</CODE>; in particular, Logo doesn't care whether the
given inputs are meaningful for use with <CODE>ifelse</CODE>.  Then, once <CODE>
ifelse</CODE> starts running, it examines its first input value.  Since that input
is the word <CODE>false</CODE>, the <CODE>ifelse</CODE> procedure ignores its second input
completely and executes the instruction in its third input.

<P>The use of quotation marks and square brackets to indicate literal inputs is
part of the plumbing syntax, not part of the procedure semantics.  Don't say,
&quot;<CODE>Ifelse</CODE> requires one predicate input and two inputs in square
brackets.&quot;  The instruction

<P><PRE>ifelse last [true false] list &quot;&quot;stupid &quot;&quot;list list bf &quot;sprint 23
</PRE>

<P>has a very different plumbing diagram (syntax) from that of the
earlier example, but provides exactly the same input values to <CODE>ifelse</CODE>.

<P>Consider these two instructions:

<P><CENTER><IMG SRC="https://people.eecs.berkeley.edu/~bh/v1ch4/printfirst.gif" ALT="figure: printfirst"></CENTER>

<P>Since the effect of <CODE>print</CODE> is easy to observe, it's not hard
to see the relationship among the instructions, the plumbing diagrams, and
the effects when these instructions are run.  Why are brackets used around
the <CODE>first</CODE> expression in one case but not in the other?  Because in one
case the expression is how we tell Logo to set up the plumbing diagram,
while in the second case we are giving <CODE>print</CODE> as input a literal list
that just happens to look like an expression.  When the context is something
like <CODE>ifelse</CODE> instead of <CODE>print</CODE>, the syntactic situation is really
quite similar, but may be harder to see.  Consider this instruction:

<P><PRE>print ifelse emptyp :a [emptyp :b] [emptyp :c]
</PRE>

<P>Why do we put brackets around two <CODE>emptyp</CODE> expressions but not
around another similar-looking one?  &raquo; Draw a plumbing diagram
for this instruction, paying no attention to your mental model of the
meaning of the <CODE>ifelse</CODE> procedure, treating it as if it were the
nonsense procedure <CODE>zot3</CODE>.  You will see that the first input to <CODE>
ifelse</CODE> is an expression whose value will be the word <CODE>true</CODE> or the word
<CODE>false</CODE>, because Logo will carry out that first <CODE>emptyp</CODE> computation
before invoking <CODE>ifelse</CODE>.  The remaining two inputs, however, are
literal lists that happen to contain the word <CODE>emptyp</CODE> but do not
involve an invocation of <CODE>emptyp</CODE> in the plumbing diagram.  Once <CODE>
ifelse</CODE> is actually invoked, precisely one of those two list inputs will be
interpreted as a Logo expression, for which a <EM>new</EM> plumbing diagram
is (in effect) drawn by Logo.  The other input list is ignored.

<P><H2>Stopping a Procedure</H2>

<P>I'd like to examine more closely one of the examples from the first
chapter:

<P><PRE>to music.quiz
print [Who is the greatest musician of all time?]
if equalp readlist [John Lennon] [print [That's right!] stop]
print [No, silly, it's John Lennon.]
end
</PRE>

<P>You now know about almost all of the primitive procedures
used in this example.  The only one we haven't discussed is the <CODE>stop</CODE>
command in the second instruction line.

<P><CODE>Stop</CODE> is a command that takes no inputs.  It is only allowed inside
a procedure; you can't type <CODE>stop</CODE> to a top-level prompt.  The effect
of <CODE>stop</CODE> is to finish the evaluation of the procedure in which it is
used.  Later instructions in the same procedure are skipped.

<P>Notice that <CODE>stop</CODE> does not stop <EM>all</EM> active procedures.  If procedure
A invokes procedure B, and there is a <CODE>stop</CODE> command in procedure B,
then procedure A continues after the point where it invoked B.

<P>Recall that the <CODE>output</CODE> command also stops the procedure that invokes
it.  The difference is that if you're writing an operation, which
should have an output, you use <CODE>output</CODE>; if you're writing a command,
which doesn't have an output, you use <CODE>stop</CODE>.

<P>In <CODE>music.quiz</CODE>, the effect of the <CODE>stop</CODE> is that if you get the right
answer, the final <CODE>print</CODE> instruction isn't evaluated.  The same effect
could have been written this way:

<P><PRE>ifelse equalp readlist [John Lennon] ~
    [print [That's right!]] ~
    [print [No, silly, it's John Lennon.]]
</PRE>

<P>The alternative form uses the three-input <CODE>ifelse</CODE> command.  One
advantage of using <CODE>stop</CODE> is precisely that it allows the use of
shorter lines.  But in this example, where there is only one
instruction after the <CODE>if</CODE>, it doesn't matter much.  <CODE>Stop</CODE> is
really useful when you want to stop only in an unusual situation and
otherwise you have a lot of work still to do:

<P><PRE>to quadratic :a :b :c
local &quot;discriminant
make &quot;discriminant (:b * :b)-(4 * :a * :c)
<U>if :discriminant &lt; 0 [print [No solution.] stop]</U>
make &quot;discriminant sqrt :discriminant
local &quot;x1
local &quot;x2
make &quot;x1 (-:b + :discriminant)/(2 * :a)
make &quot;x2 (-:b - :discriminant)/(2 * :a)
print (sentence [x =] :x1 [or] :x2)
end
</PRE>

<P>This procedure applies the quadratic formula to solve the
equation

<P><CENTER><EM>ax</EM>&#178;+<EM>bx</EM>+<EM>c</EM>=0</CENTER>

<P>The only interesting thing about this example for our present purpose
is the fact that sometimes there is no solution.  In that case the
procedure <CODE>stop</CODE>s as soon as it finds out.

<P>Don't forget that you need <CODE>stop</CODE> only if you want to stop a
procedure before its last instruction line.  A common mistake made by
beginners who've just learned about <CODE>stop</CODE> is to use it in every
procedure.  If you look back at the examples so far you'll see that
many procedures get along fine without invoking <CODE>stop</CODE>.

<P><H2>Improving the Quiz Program</H2>

<P>When I first introduced the <CODE>music.quiz</CODE> example in Chapter 1, we
hadn't discussed things like user procedures with inputs.  We are now in a
position to generalize the quiz program:

<P><PRE>to qa :question :answer
print :question
if equalp readlist :answer [print [That's right!] stop]
print sentence [Sorry, it's] :answer
end

to quiz
qa [Who is the best musician of all time?] [John Lennon]
qa [Who wrote &quot;Compulsory Miseducation&quot;?] [Paul Goodman]
qa [What color was George Washington's white horse?] [white]
qa [how much is 2+2?] [5]
end
</PRE>

Procedure <CODE>qa</CODE> is our old friend <CODE>music.quiz</CODE>, with variable
inputs instead of a fixed question and answer.  <CODE>Quiz</CODE> uses <CODE>qa</CODE> several
times to ask different questions.

<P>&raquo;Here are a couple of suggestions for further improvements you should
be able to make to <CODE>quiz</CODE> and <CODE>qa</CODE>:

<P>1.  <CODE>Qa</CODE> is very fussy about getting one particular answer to a
question. If you answer <CODE>Lennon</CODE> instead of <CODE>John Lennon</CODE>,
it'll tell you you're wrong.  There are a couple of ways you might fix
this.  One is to look for a single-word answer <EM>anywhere within</EM>
what the user types.  So if <CODE>:answer</CODE> is the word <CODE>Lennon</CODE>,
the program will accept &quot;<CODE>Lennon</CODE>,&quot; &quot;<CODE>John Lennon</CODE>,&quot; or &quot;<CODE>the
Lennon Sisters</CODE>.&quot;  The second approach would be for <CODE>qa</CODE> to take a
<EM>list</EM> of possible answers as its second input:

<P><PRE>qa [Who is the best musician of all time?] ~
   [[John Lennon] [Lennon] [the Beatles]]
</PRE>

<P><CODE>Qa</CODE> then has to use a different predicate, to see if what
the user types is any of the answers in the list.

<P>2.  By giving <CODE>quiz</CODE> a local variable named <CODE>score</CODE>, you could
have <CODE>quiz</CODE> and <CODE>qa</CODE> cooperate to keep track of how many
questions the user gets right.  At the end the score could be printed.
(This is an opportunity to think about the stylistic virtues and vices
of letting a subprocedure modify a variable that belongs to its
superprocedure.  If you say

<P><PRE>make &quot;score :score+1
</PRE>

<P>inside <CODE>qa</CODE>, doesn't that make <CODE>quiz</CODE> somewhat mysterious
to read?  For an alternative, read the next section.)

<P><H2>Reporting Success to a Superprocedure</H2>

<P>Suppose we want the quiz program to give the user three tries before
revealing the right answer.  There are several ways this could be
programmed.  Here is a way that uses the tools you already know about.

<P>The general idea is that the procedure that asks the question is
written as an <EM>operation,</EM> not as a command.  To be exact, it's a
predicate; it outputs <CODE>true</CODE> if the user gets the right answer.
This asking procedure, <CODE>ask.once</CODE>, is invoked as a subprocedure of
<CODE>ask.thrice</CODE>, which is in charge of allowing three tries.  <CODE>
ask.thrice</CODE> invokes <CODE>ask.once</CODE> up to three times, but stops if
<CODE>ask.once</CODE> reports success.

<P><PRE>to ask.thrice :question :answer
repeat 3 [if ask.once :question :answer [stop]]
print sentence [The answer is] :answer
end

to ask.once :question :answer
print :question
if equalp readlist :answer [print [Right!] output &quot;true]
print [Sorry, that's wrong.]
output &quot;false
end
</PRE>

<P>
You've seen <CODE>repeat</CODE> in the first chapter, but you haven't been formally
introduced.  <CODE>Repeat</CODE> is a command with two inputs.  The first input
must be a non-negative whole number.  The second input must be a list
of Logo instructions.  The effect of <CODE>repeat</CODE> is to evaluate its second
input, the instruction list, the number of times given as the first
input.

<P>The programming style used in this example is a little controversial.
In general, it's considered a good idea not to mix effect and output
in one procedure.  But in this example, <CODE>ask.once</CODE> has an effect (it
prints the question, reads an answer, and comments on its correctness)
and also an output (<CODE>true</CODE> or <CODE>false</CODE>).

<P>I think the general rule I've just cited is a good rule, but there
are exceptions to it.  Using an output of <CODE>true</CODE> or <CODE>false</CODE> to report
the success or failure of some process is one of the situations that
I consider acceptable style.  The real point of the rule, I think,
is to separate <EM>calculating</EM> something from <EM>
printing</EM> it.  For example, it's a mistake to write procedures like this
one:

<P><PRE>to <A NAME="prsecond">prsecond :datum
print first butfirst :datum
end
</PRE>

<P>
A more powerful technique is to write the <CODE>second</CODE> operation
from Chapter 2; instead of

<P><PRE>prsecond [something or other]
</PRE>

<P>you can then say

<P><PRE>print second [something or other]
</PRE>

<P>It may not be obvious from this example why I call <CODE>second</CODE>
more powerful than <CODE>prsecond</CODE>.  But remember that an operation can be
combined with other operations, as in the plumbing diagrams we used
earlier.  For example, the operation <CODE>second</CODE> can extract the word <CODE>
or</CODE> from the list as shown here.  But you can <EM>also</EM> use it as part of
a more complex instruction to extract the letter <CODE>o</CODE>:

<P><PRE>print first second [something or other]
</PRE>

<P>If you'd written the command <CODE>prsecond</CODE> to solve the
first problem, you'd have to start all over again to solve this new
one.  (Of course, both of these examples must seem pretty silly; why
bother extracting a word or a letter from this list?  But I'm trying
to use examples that are simple enough not to obscure this issue with
the kinds of complications we'll see in more interesting programs.)

<P>&raquo;If you made the improvements to <CODE>quiz</CODE> and <CODE>qa</CODE> that I
suggested earlier, you might like to see if they can fit easily with a new
version of <CODE>quiz</CODE> using <CODE>ask.thrice</CODE>.

<P><A HREF="../v1-toc2.html">(back to Table of Contents)</A>
<P><A HREF="../v1ch3/v1ch3.html"><STRONG>BACK</STRONG></A>
chapter thread <A HREF="../v1ch5/v1ch5.html"><STRONG>NEXT</STRONG></A>

<P>
<ADDRESS>
<A HREF="../index.html">Brian Harvey</A>, 
<CODE>bh@cs.berkeley.edu</CODE>
</ADDRESS>
</BODY>
</HTML>