about summary refs log tree commit diff stats
path: root/js/games/nluqo.github.io/~bh/ssch6/true
blob: a5c360c4d03931d6f5dc91befc2413424496987e (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
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
<P>
<A NAME="dumdee"></A>
<P><CENTER><IMG SRC="../ss-pics/tweedle.jpg" ALT="figure: tweedle"></CENTER><P><CENTER>&quot;Contrariwise,&quot; continued Tweedledee, &quot;if it was so,
it might be; and if it were so, it would be; but as it isn't, it ain't.
That's logic.&quot;
</CENTER><P>

<HTML>
<HEAD>
<TITLE>Simply Scheme: Introducing Computer Science ch 6: True and False</TITLE>
</HEAD>
<BODY>
<HR>
<CITE>Simply Scheme:</CITE>
<CITE>Introducing Computer Science</CITE> 2/e Copyright (C) 1999 MIT
<H2>Chapter 6</H2>
<H1>True and False</H1>

<TABLE width="100%"><TR><TD>
<IMG SRC="../simply.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"><CITE><A HREF="http://ccrma.stanford.edu/~matt">Matthew
Wright</A><BR>University of California, Santa Barbara</CITE>
<TR><TD align="right"><BR>
<TR><TD align="right"><A HREF="../pdf/ssch06.pdf">Download PDF version</A>
<TR><TD align="right"><A HREF="../ss-toc2.html">Back to Table of Contents</A>
<TR><TD align="right"><A HREF="../ssch5/words.html"><STRONG>BACK</STRONG></A>
chapter thread <A HREF="../ssch7/variables.html"><STRONG>NEXT</STRONG></A>
<TR><TD align="right"><A HREF="http://mitpress.mit.edu/0262082810">MIT
Press web page for <CITE>Simply Scheme</CITE></A>
</TABLE></TABLE>

<HR>


<P>We still need one more thing before we can write more interesting programs: 
the ability to make decisions.  Scheme has a way to say &quot;if this is true,
then do this thing, otherwise do something else.&quot;

<P>Here's a procedure that greets a person:

<P><PRE>(define (<A NAME="g63"></A>greet name)
  (if (equal? (first name) 'professor)
      (se '(i hope i am not bothering you) 'professor (last name))
      (se '(good to see you) (first name))))

&gt; (greet '(matt wright))
(GOOD TO SEE YOU MATT)

&gt; (greet '(professor harold abelson))
(I HOPE I AM NOT BOTHERING YOU PROFESSOR ABELSON)
</PRE>

<P>The program greets a person by checking to see if that person is a
professor.  If so, it says, &quot;I hope I am not bothering you&quot; and then the
professor's name.  But if it's a regular person, the program just says,
&quot;Good to see you,&quot; and then the person's first name.

<P><CODE>If</CODE> takes three arguments.  The first has to be either true or
false.
<A NAME="spif"></A>
<A NAME="g64"></A>
(We'll talk in a moment about exactly what true and false look like to
Scheme.)  In the above example, the first word of the person's name might or
might not be equal to the word &quot;Professor.&quot; The second and third arguments
are expressions; one or the other of them is evaluated depending on the
first argument.  The value of the entire <CODE>if</CODE> expression is the value of
either the second or the third argument.

<P>
You learned in Chapter 2 that Scheme includes a special data type
called <EM>Booleans</EM> to represent true or false
values.  There are just two of them: <A NAME="g65"></A><CODE>#t</CODE> for &quot;true&quot; and
<A NAME="g66"></A><CODE>#f</CODE> for &quot;false.&quot;<A NAME="dumbfalse"></A><A NAME="text1" HREF="true#ft1">[1]</A>

<P>We said that the first argument to <CODE>if</CODE> has to be true or false.  Of
course, it would be silly to say

<P>

<P><PRE>&gt; (if #t (+ 4 5) (* 2 7))
9
</PRE>

<P>
because what's the point of using <CODE>if</CODE> if we already know
which branch will be followed?  Instead, as in the <CODE>greet</CODE> example, we call
some procedure whose return value will be either true or false, depending on
the particular arguments we give it.

<P><H2>Predicates</H2>

<P>A function that returns either <CODE>#t</CODE> or <CODE>#f</CODE> is called a <EM>predicate.</EM><A NAME="text2" HREF="true#ft2">[2]</A> You've
already seen the <A NAME="g69"></A><CODE>equal?</CODE> predicate.  It takes two arguments, which
can be of any type, and returns <CODE>#t</CODE> if the two arguments are the same
value, or <CODE>#f</CODE> if they're different.  It's a convention in Scheme that
the names of predicates end with a question mark, but that's just a
convention.  Here are some other useful predicates:

<P>
<PRE>&gt; (member? 'mick '(dave dee dozy beaky mick and tich))
#T
&gt; (member? 'mick '(john paul george ringo))
#F
&gt; (member? 'e 'truly)
#F
</PRE>

<P>
<PRE>&gt; (member? 'y 'truly)
#T
&gt; (= 3 4)
#F
&gt; (= 67 67)
#T
&gt; (&gt; 98 97)
#T
&gt; (before? 'zorn 'coleman)
#F
&gt; (before? 'pete 'ringo)
#T
&gt; (empty? '(abbey road))
#F
&gt; (empty? '())
#T
&gt; (empty? 'hi)
#F
&gt; (empty? (bf (bf 'hi)))
#T
&gt; (empty? &quot;&quot;)
#T
</PRE>

<P>

<P><CODE>Member?</CODE> takes two arguments; it checks to see if the first
<A NAME="memq"></A>
<A NAME="g70"></A>
one is a member of the second.  The <A NAME="g71"></A><CODE>=</CODE>, <A NAME="g72"></A><CODE>&gt;</CODE>, <A NAME="g73"></A><CODE>&lt;</CODE>,
<A NAME="g74"></A><CODE>&gt;=</CODE>, and <A NAME="g75"></A><CODE>&lt;=</CODE> functions take two numbers as arguments and do the
obvious comparisons.  (By the way, these are exceptions to the convention about
question marks.)  <CODE>Before?</CODE> is like <CODE>&lt;</CODE>, but it compares two words
<A NAME="g76"></A>
alphabetically.  <CODE>Empty?</CODE> checks to see if its argument
<A NAME="g77"></A>
is either the empty word or the empty sentence.

<P>

<P>Why do we have both <CODE>equal?</CODE> and <CODE>=</CODE> in Scheme?  The first of these
works on any kind of Scheme data, while the second is defined only for
numbers.  You could get away with always using <CODE>equal?</CODE>, but the more
specific form makes your program more self-explanatory; people reading the
program know right away that you're comparing numbers.

<P>

<P>There are also several predicates that can be used to test the type of their
argument:

<P>

<P><PRE>&gt; (<A NAME="g78"></A>number? 'three)
#F
&gt; (number? 74)
#T
&gt; (<A NAME="g79"></A>boolean? #f)
#T
&gt; (boolean? '(the beatles))
#F
</PRE>

<P>
<PRE>&gt; (boolean? 234)
#F
&gt; (boolean? #t)
#T
&gt; (<A NAME="g80"></A>word? 'flying)
#T
&gt; (word? '(dig it))
#F
&gt; (word? 87)
#T
&gt; (<A NAME="g81"></A>sentence? 'wait)
#F
&gt; (sentence? '(what goes on))
#T
</PRE>

<P>Of course, we can also define new predicates:

<P>

<P><PRE>(define (vowel? letter)
  (member? letter 'aeiou))

(define (positive? number)
  (&gt; number 0))
</PRE>

<P><H2>Using Predicates</H2>

<P>Here's a procedure that returns the absolute value of a number:

<P>

<P><PRE>(define (<A NAME="g82"></A>abs num)
  (if (&lt; num 0)
      (- num)
      num))
</PRE>

<P>

<P>(If you call <A NAME="g83"></A><CODE>-</CODE> with just one argument, it returns the
negative of that argument.)  Scheme actually provides <A NAME="g84"></A><CODE>abs</CODE> as a
primitive procedure, but we can redefine it.

<P>Do you remember how to play buzz?  You're all sitting around the campfire
and you go around the circle counting up from one.  Each person says a
number.  If your number is divisible by seven or if one of its digits is a
seven, then instead of calling out your number, you say &quot;buzz.&quot;

<P><PRE>(define (<A NAME="g85"></A>buzz num)
  (if (or (divisible? num 7) (member? 7 num))
      'buzz
      num))

(define (<A NAME="g86"></A>divisible? big little)
  (= (remainder big little) 0))
</PRE>

<P><CODE>Or</CODE> can take any number of arguments, each of which must be
true or false.  It returns true if any of its arguments are true, that is, if
the first argument is true <EM>or</EM> the second argument is true <EM>or</EM>&hellip  (<CODE>Remainder</CODE>, as you know, takes two integers and tells
you what the remainder is when you divide the first by the second.  If the
remainder is zero, the first number is divisible by the second.)

<P><CODE>Or</CODE> is one of three functions in Scheme that combine true or false
values to produce another true or false value.  <CODE>And</CODE> returns true if
<A NAME="g87"></A> all of its arguments are true, that is, the first <EM>and</EM>
second <EM>and</EM>&hellip  Finally, there's a function <A NAME="g88"></A><CODE>not</CODE> that
takes exactly one argument, returning true if that argument is false and
vice versa.

<P>In the last example, the procedure we really wanted to write was <CODE>buzz</CODE>,
but we found it useful to define <CODE>divisible?</CODE> also.  It's quite common
that the easiest way to solve some problem is to write a <EM>helper
procedure</EM> to do part of the work.  In this case the helper procedure
computes a function that's meaningful in itself, but sometimes you'll want
to write procedures with names like <CODE>buzz-helper</CODE> that are useful only
in the context of one particular problem.

<P>Let's write a program that takes a word as its argument and returns the
plural of that word.  Our first version will just put an &quot;s&quot; on the end:

<P><PRE>(define (plural wd)
  (word wd 's))

&gt; (plural 'beatle)
BEATLES

&gt; (plural 'computer)
COMPUTERS

&gt; (plural 'fly)
FLYS
</PRE>

<P>This works for most words, but not those that end in &quot;y.&quot; Here's
version two:

<P><PRE>(define (<A NAME="g89"></A>plural wd)
  (if (equal? (last wd) 'y)
      (word (bl wd) 'ies)
      (word wd 's)))
</PRE>

<P>This isn't exactly right either; it thinks that the plural of
&quot;boy&quot; is &quot;boies.&quot; We'll ask you to add some more rules in Exercise
<A HREF="true.html#plurex">6.12</A>.

<P><H2><CODE>If</CODE> Is a Special Form</H2>

<P>There are a few subtleties that we haven't told you about yet.  First of
all, <A NAME="g90"></A><CODE>if</CODE> is a <A NAME="g91"></A><A NAME="g92"></A>special form.  Remember that we're going to
need the value of only one of its last two arguments.  It would be wasteful
for Scheme to evaluate the other one.  So if you say

<P><PRE>(if (= 3 3)
    'sure
    (factorial 1000))
</PRE>

<P><CODE>if</CODE> won't compute the factorial of 1000 before returning
<CODE>sure</CODE>.

<P>The rule is that <CODE>if</CODE> always evaluates its first argument.  If the value
of that argument is true, then <CODE>if</CODE> evaluates its second argument and
returns its value.  If the value of the first argument is false, then <CODE>if</CODE> evaluates its third argument and returns that value.

<P><H2>So Are <CODE>And</CODE> and <CODE>Or</CODE></H2>

<P><CODE>And</CODE> and <A NAME="g93"></A><CODE>or</CODE> are also <A NAME="g94"></A><A NAME="g95"></A>special forms.  They evaluate
<A NAME="g96"></A> their arguments in order from left to right<A NAME="text3" HREF="true#ft3">[3]</A> and stop as soon as they can.  For <CODE>or</CODE>, this means
returning true as soon as any of the arguments is true.  <CODE>And</CODE> returns
false as soon as any argument is false.  This turns out to be useful in
cases like the following:

<P><PRE>(define (divisible? big small)
  (= (remainder big small) 0))

(define (<A NAME="g97"></A>num-divisible-by-4? x)
  (and (number? x) (divisible? x 4)))

&gt; (num-divisible-by-4? 16)
#T

&gt; (num-divisible-by-4? 6)
#F

&gt; (num-divisible-by-4? 'aardvark)
#F

&gt; (divisible? 'aardvark 4)
ERROR: AARDVARK IS NOT A NUMBER
</PRE>

<P>We want to see if <CODE>x</CODE> is a number, and, if so, if it's
divisible by <CODE>4</CODE>.  It would be an error to apply <CODE>divisible?</CODE> to a
nonnumber.  If <CODE>and</CODE> were an ordinary procedure, the two tests (<CODE>number?</CODE> and <CODE>divisible?</CODE>) would both be evaluated before we would
have a chance to pay attention to the result of the first one.  Instead, if
<CODE>x</CODE> turns out not to be a number, our procedure will return <CODE>#f</CODE>
without trying to divide it by <CODE>4</CODE>.

<P><H2>Everything That Isn't False Is True</H2>

<P><CODE>#T</CODE> isn't the only true value.  In fact, <EM>every</EM> value is
considered true except for <CODE>#f</CODE>.

<P><PRE>&gt; (if (+ 3 4) 'yes 'no)
YES
</PRE>

<P>This allows us to have <EM>semipredicates</EM> that give
slightly more information than just true or false.  For example, we can
write an integer quotient procedure.  That is to say, our procedure will
divide its first argument by the second, but only if the first is evenly
divisible by the second.  If not, our procedure will return <CODE>#f</CODE>.

<P><PRE>(define (<A NAME="g98"></A>integer-quotient big little)
  (if (divisible? big little)
      (/ big little)
      #f))

&gt; (integer-quotient 27 3)
9

&gt; (integer-quotient 12 5)
#F
</PRE>

<P><CODE>And</CODE> and <CODE>or</CODE> are also semipredicates.  We've already explained
that <CODE>or</CODE> returns a true result as soon as it evaluates a true
argument.  The particular true value that <CODE>or</CODE> returns is the value of
that first true argument:

<P><PRE>&gt; (or #f 3 #f 4)
3
</PRE>

<P><CODE>And</CODE> returns a true value only if all of its arguments are
true.  In that case, it returns the value of the last argument:

<P><PRE>&gt; (and 1 2 3 4 5)
5
</PRE>

<P>As an example in which this behavior is useful, we can rewrite
<CODE>integer-quotient</CODE> more tersely:

<P><PRE>(define (integer-quotient big little)        ;; alternate version
  (and (divisible? big little)
       (/ big little)))
</PRE>

<P><H2>Decisions, Decisions, Decisions</H2>

<P><CODE>If</CODE> is great for an either-or choice.  But sometimes there are several
possibilities to consider:

<P><PRE>(define (roman-value letter)
  (if (equal? letter 'i)
      1
      (if (equal? letter 'v)
          5
          (if (equal? letter 'x)
              10
              (if (equal? letter 'l)
                  50
                  (if (equal? letter 'c)
                      100
                      (if (equal? letter 'd)
                          500
                          (if (equal? letter 'm)
                              1000
                              'huh?))))))))
</PRE>

<P>That's pretty hideous.  Scheme provides a shorthand notation for
situations like this in which you have to choose from among several
possibilities: the <A NAME="g99"></A><A NAME="g100"></A>special form <A NAME="g101"></A><CODE>cond</CODE>.
<A NAME="cond"></A>

<P><PRE>(define (<A NAME="g102"></A>roman-value letter)
  (cond ((equal? letter 'i) 1)
        ((equal? letter 'v) 5)
        ((equal? letter 'x) 10)
        ((equal? letter 'l) 50)
        ((equal? letter 'c) 100)
        ((equal? letter 'd) 500)
        ((equal? letter 'm) 1000)
        (else 'huh?)))
</PRE>

<P>The tricky thing about <CODE>cond</CODE> is that it doesn't use parentheses in quite
<A NAME="g103"></A> the same way as the rest
of Scheme.  Ordinarily, parentheses mean procedure invocation.  In <CODE>cond</CODE>, <EM>most</EM> of the parentheses still mean that, but <EM>some</EM> of
them are used to group pairs of tests and results.  We've reproduced the
same <CODE>cond</CODE> expression below, indicating the funny ones in boldface.

<P><PRE>(define (roman-value letter)
  (cond <STRONG><BIG>(</BIG></STRONG>(equal? letter 'i) 1<STRONG><BIG>)</BIG></STRONG>
        <STRONG><BIG>(</BIG></STRONG>(equal? letter 'v) 5<STRONG><BIG>)</BIG></STRONG>
        <STRONG><BIG>(</BIG></STRONG>(equal? letter 'x) 10<STRONG><BIG>)</BIG></STRONG>
        <STRONG><BIG>(</BIG></STRONG>(equal? letter 'l) 50<STRONG><BIG>)</BIG></STRONG>
        <STRONG><BIG>(</BIG></STRONG>(equal? letter 'c) 100<STRONG><BIG>)</BIG></STRONG>
        <STRONG><BIG>(</BIG></STRONG>(equal? letter 'd) 500<STRONG><BIG>)</BIG></STRONG>
        <STRONG><BIG>(</BIG></STRONG>(equal? letter 'm) 1000<STRONG><BIG>)</BIG></STRONG>
        <STRONG><BIG>(</BIG></STRONG>else 'huh?<STRONG><BIG>)</BIG></STRONG> ))
</PRE>

<P><CODE>Cond</CODE> takes any number of arguments, each of which is <EM>two
expressions</EM> inside a pair of parentheses.  Each argument is called a <EM><A NAME="g104"></A><A NAME="g105"></A>cond clause.</EM> In the example above, one typical clause is

<P><PRE><STRONG><BIG>(</BIG></STRONG>(equal? letter 'l) 50<STRONG><BIG>)</BIG></STRONG>
</PRE>

<P>The outermost parentheses on that line enclose two expressions.
The first of the two expressions (the <EM>condition</EM>) is taken as
true or false, just like the first argument to <CODE>if</CODE>.  The second
expression of each pair (the <EM>consequent</EM>) is a candidate for
the return value of the entire <CODE>cond</CODE> invocation.

<P><CODE>Cond</CODE> examines its arguments from left to right.  Remember that since
<CODE>cond</CODE> is a special form, its arguments are not evaluated ahead of time.
For each argument, <CODE>cond</CODE> evaluates the first of the two expressions
within the argument.  If that value turns out to be true, then <CODE>cond</CODE>
evaluates the second expression in the same argument, and returns that value
without examining any further arguments.  But if the value is false, then
<CODE>cond</CODE> does <EM>not</EM> evaluate the second expression; instead, it goes
on to the next argument.

<P>By convention, the last argument always starts with the word <A NAME="g106"></A><CODE>else</CODE>
instead of an expression.  You can think of this as representing a true
value, but <CODE>else</CODE> doesn't mean true in any other context; you're only
allowed to use it as the condition of the last clause of a <CODE>cond</CODE>.<A NAME="text4" HREF="true#ft4">[4]</A>

<P>Don't get into bad habits of thinking about the appearance of
<CODE>cond</CODE> clauses in terms of &quot;two parentheses in a row.&quot;
That's often the case, but not always.  For example, here is a procedure that
translates Scheme true or false values (<CODE>#t</CODE> and <CODE>#f</CODE>)
into more human-readable words <CODE>true</CODE> and <CODE>false</CODE>.

<P><PRE>(define (<A NAME="g107"></A>truefalse value)
  (cond (value 'true)
	(else 'false)))

&gt; (truefalse (= 2 (+ 1 1)))
TRUE

&gt; (truefalse (= 5 (+ 2 2)))
FALSE
</PRE>

<P>When a <CODE>cond</CODE> tests several possible conditions, they might not
be <A NAME="g108"></A><A NAME="g109"></A>mutually exclusive.<A NAME="text5"
HREF="true#ft5">[5]</A> This can be either a source of error or an advantage in
writing efficient programs.  The trick is to make the <EM>most
restrictive</EM> test first.  For example, it would be an error to say

<P><PRE>(cond ((number? (first sent)) &hellip)           ;; wrong
      ((empty? sent) &hellip)
      &hellip)
</PRE>

<P>because the first test only makes sense once you've already
established that there <EM>is</EM> a first word of the sentence.
On the other hand, you don't have to say

<P><PRE>(cond ((empty? sent) &hellip)
      ((and (not (empty? sent)) (number? (first sent))) &hellip)
      &hellip)
</PRE>

<P>because you've already established that the sentence is nonempty
if you get as far as the second clause.

<P><H2><CODE>If</CODE> Is Composable</H2>

<P>Suppose we want to write a <CODE>greet</CODE> procedure that works like this:

<P><PRE>&gt; (greet '(brian epstein))
(PLEASED TO MEET YOU BRIAN - HOW ARE YOU?)

&gt; (greet '(professor donald knuth))
(PLEASED TO MEET YOU PROFESSOR KNUTH - HOW ARE YOU?)
</PRE>

<P>The response of the program in these two cases is almost the same;
the only difference is in the form of the person's name.

<P>This procedure could be written in two ways:

<P><PRE>(define (greet name)
  (if (equal? (first name) 'professor)
      (se '(pleased to meet you)
	  'professor
	  (last name)
	  '(- how are you?))
      (se '(pleased to meet you)
	  (first name)
	  '(- how are you?))))

(define (greet name)
  (se '(pleased to meet you)
      (if (equal? (first name) 'professor)
	  (se 'professor (last name))
	  (first name))
      '(- how are you?)))
</PRE>

<P>The second version avoids repeating the common parts of the
response by using <CODE>if</CODE> within a larger expression.

<P>Some people find it counterintuitive to use <CODE>if</CODE> as we did in the second
version.  Perhaps the reason is that in some other programming languages,
<CODE>if</CODE> is a &quot;command&quot; instead of a function like any other.  A mechanism
that selects one part of a program to run, and leaves out another part, may
seem too important to be a mere argument subexpression.  But in Scheme, the
value returned by <EM>every</EM> function can be used as part of a larger
expression.<A NAME="text6" HREF="true#ft6">[6]</A>

<P>We aren't saying anything new here.  We've already explained the idea of
composition of functions, and we're just making the same point again about
<CODE>if</CODE>.  But we've learned that many students expect <CODE>if</CODE> to be an
exception, so we're taking the opportunity to emphasize the point: There are
no exceptions to this rule.

<P><H2>Pitfalls</H2>

<P>The biggest pitfall in this chapter is the unusual notation of <CODE>cond</CODE>.  Keeping track of the parentheses that mean function invocation, as
usual, and the parentheses that just group the parts of a <CODE>cond</CODE> clause
is tricky until you get accustomed to it.

<P>Many people also have trouble with the asymmetry of the <A NAME="g110"></A><CODE>member?</CODE>
predicate.  The first argument is something small; the second is something
big.  (The order of arguments is the same as the order of a typical English
sentence about membership:  &quot;Is Mick a member of the Beatles?&quot;)
It seems pretty obvious when you look at an example in which both
arguments are quoted constant values, but you can get in trouble when you
define a procedure and use its parameters as the arguments to <CODE>member?</CODE>.
Compare writing a procedure that says, &quot;does the letter E appear in this
word?&quot; with one that says, &quot;is this letter a vowel?&quot;

<P>Many people try to use <CODE>and</CODE> and <CODE>or</CODE> with the full flexibility
of the corresponding English words.  Alas, Scheme is not English.  For
example, suppose you want to know whether the argument to a procedure is
either the word <CODE>yes</CODE> or the word <CODE>no</CODE>.  You can't say

<P>
<PRE>(equal? argument (or 'yes 'no))              ; wrong!
</PRE>

<P>This sounds promising:  &quot;Is the <CODE>argument</CODE> <CODE>equal</CODE> to
the word <CODE>yes</CODE> <CODE>or</CODE> the word <CODE>no</CODE>?&quot; But the arguments to <CODE>or</CODE> must be true-or-false values, not things you want to check for equality
with something else.  You have to make two separate equality tests:

<P><PRE>(or (equal? argument 'yes) (equal? argument 'no))
</PRE>

<P>In this particular case, you could also solve the problem by saying

<P><PRE>(member? argument '(yes no))
</PRE>

<P>but the question of trying to use <CODE>or</CODE> as if it were English
comes up in other cases for which <CODE>member?</CODE> won't help.

<P>This isn't exactly a pitfall, because it won't stop your program from
working, but programs like

<P><PRE>(define (odd? n)
  (if (not (even? n)) #t #f))
</PRE>

<P>are redundant.  Instead, you could just say

<P><PRE>(define (odd? n)
  (not (even? n)))
</PRE>

<P>since the value of <CODE>(not (even? n))</CODE> is already <CODE>#t</CODE> or
<CODE>#f</CODE>.

<P><H2>Boring Exercises</H2>

<P><B>6.1</B>&nbsp;&nbsp;What values are printed when you type these expressions to Scheme?  (Figure
it out in your head before you try it on the computer.)

<P><PRE>(cond ((= 3 4) '(this boy))
      ((&lt; 2 5) '(nowhere man))
      (else '(two of us)))

(cond (empty? 3)
      (square 7)
      (else 9))

(define (<A NAME="g111"></A>third-person-singular verb)
  (cond ((equal? verb 'be) 'is)
        ((equal? (last verb) 'o) (word verb 'es))
        (else (word verb 's))))

(third-person-singular 'go)
</PRE>


<P> 

<B>6.2</B>&nbsp;&nbsp;What values are printed when you type these expressions to Scheme?  (Figure
it out in your head before you try it on the computer.)

<P><PRE>(or #f #f #f #t)

(and #f #f #f #t)

(or (= 2 3) (= 4 3))

(not #f)

(or (not (= 2 3)) (= 4 3))

(or (and (= 2 3) (= 3 3)) (and (&lt; 2 3) (&lt; 3 4)))
</PRE>

<P><B>6.3</B>&nbsp;&nbsp;Rewrite the following procedure using a <CODE>cond</CODE> instead of the <CODE>if</CODE>s:

<P><PRE>(define (<A NAME="g112"></A>sign number)
  (if (&lt; number 0)
      'negative
      (if (= number 0)
	  'zero
	  'positive)))
</PRE>

<P>
<B>6.4</B>&nbsp;&nbsp;Rewrite the following procedure using an <CODE>if</CODE> instead of the <CODE>cond</CODE>:

<P><PRE>(define (<A NAME="g113"></A>utensil meal)
  (cond ((equal? meal 'chinese) 'chopsticks)
	(else 'fork)))
</PRE>

<P>
<P>
<H2>Real Exercises</H2>
<P>
Note: Writing helper procedures may be useful in solving some of these
problems.

<P><B>6.5</B>&nbsp;&nbsp;Write a procedure <A NAME="g114"></A><CODE>european-time</CODE> to convert a time from American
AM/PM notation into European 24-hour notation.  Also
write <A NAME="g115"></A><CODE>american-time</CODE>, which does the opposite:

<P><PRE>&gt; (european-time '(8 am))
8

&gt; (european-time '(4 pm))
16

&gt; (american-time 21)
(9 PM)

&gt; (american-time 12)
(12 PM)

&gt; (european-time '(12 am))
24
</PRE>

<P>Getting noon and midnight right is tricky.


<P>
<B>6.6</B>&nbsp;&nbsp;Write a predicate <A NAME="g116"></A><CODE>teen?</CODE> that returns true if its argument is between
13 and 19.


<P>
<B>6.7</B>&nbsp;&nbsp;Write a procedure <A NAME="g117"></A><CODE>type-of</CODE> that takes anything as its argument and
returns one of the words <CODE>word</CODE>, <CODE>sentence</CODE>, <CODE>number</CODE>, or
<CODE>boolean</CODE>:

<P><PRE>&gt; (type-of '(getting better))
SENTENCE

&gt; (type-of 'revolution)
WORD

&gt; (type-of (= 3 3))
BOOLEAN
</PRE>

<P>(Even though numbers are words, your procedure should return <CODE>number</CODE> if its argument is a number.)

<P>Feel free to check for more specific types, such as &quot;positive integer,&quot;
if you are so inclined.


<P>
<B>6.8</B>&nbsp;&nbsp;Write a procedure <A NAME="g118"></A><CODE>indef-article</CODE> that works like this:
<PRE>&gt; (indef-article 'beatle)
(A BEATLE)

&gt; (indef-article 'album)
(AN ALBUM)
</PRE>

<P>Don't worry about silent initial consonants like the <CODE>h</CODE> in <CODE>hour</CODE>.


<P>
<B>6.9</B>&nbsp;&nbsp;Sometimes you must choose the singular or the plural of a word:  <CODE>1 book</CODE> but <CODE>2 books</CODE>.  Write a procedure <A NAME="g119"></A><CODE>thismany</CODE> that takes
two arguments, a number and a singular noun, and combines them appropriately:

<P><PRE>&gt; (thismany 1 'partridge)
(1 PARTRIDGE)

&gt; (thismany 3 'french-hen)
(3 FRENCH-HENS)
</PRE>


<P>
<P>
<B>6.10</B>&nbsp;&nbsp;Write a procedure <A NAME="g120"></A><CODE>sort2</CODE> that takes as its argument a sentence
containing two numbers.  It should return a sentence containing the same two
numbers, but in ascending order:

<P><PRE>&gt; (sort2 '(5 7))
(5 7)

&gt; (sort2 '(7 5))
(5 7)
</PRE>

<P>
<B>6.11</B>&nbsp;&nbsp;Write a predicate <A NAME="g121"></A><CODE>valid-date?</CODE> that takes three numbers as arguments,
representing a month, a day of the month, and a year.  Your procedure should
return <CODE>#t</CODE> if the numbers represent a valid date (e.g., it isn't the
31st of September).  February has 29 days if the year is divisible by 4,
except that if the year is divisible by 100 it must also be divisible by 400.

<P><PRE>&gt; (valid-date? 10 4 1949)
#T

&gt; (valid-date? 20 4 1776)
#F

&gt; (valid-date? 5 0 1992)
#F

&gt; (valid-date? 2 29 1900)
#F

&gt; (valid-date? 2 29 2000)
#T
</PRE>

<P>
<B>6.12</B>&nbsp;&nbsp;Make <A NAME="g122"></A><CODE>plural</CODE> handle correctly words that end in <CODE>y</CODE> but have a
vowel before the <CODE>y</CODE>, such as <CODE>boy</CODE>.  Then teach it about words that
end in <CODE>x</CODE> (box).  What other special cases can you find?

<P><A NAME="plurex"></A>


<P>
<B>6.13</B>&nbsp;&nbsp;Write a better <A NAME="g123"></A><CODE>greet</CODE> procedure that understands as many different
kinds of names as you can think of:

<P><PRE>&gt; (greet '(john lennon))
(HELLO JOHN)

&gt; (greet '(dr marie curie))
(HELLO DR CURIE)

&gt; (greet '(dr martin luther king jr))
(HELLO DR KING)

&gt; (greet '(queen elizabeth))
(HELLO YOUR MAJESTY)

&gt; (greet '(david livingstone))
(DR LIVINGSTONE I PRESUME?)
</PRE>


<P>
<B>6.14</B>&nbsp;&nbsp;Write a procedure <A NAME="g124"></A><CODE>describe-time</CODE> that takes a number of seconds as its
argument and returns a more useful description of that amount of time:
<A NAME="desctime"></A>

<P><PRE>&gt; (describe-time 45)
(45 SECONDS)

&gt; (describe-time 930)
(15.5 MINUTES)

&gt; (describe-time 30000000000)
(9.506426344208686 CENTURIES)
</PRE>

<P>

<HR>
<A NAME="ft1" HREF="true#text1">[1]</A> In <EM>some</EM>
versions of Scheme, the <A NAME="g67"></A><A NAME="g68"></A>empty sentence is considered false.  That
is, <CODE>()</CODE> and <CODE>#f</CODE> may be the same thing.  The reason that we can't
be definite about this point is that older versions of Scheme follow the
traditional Lisp usage, in which the empty sentence is false, but since then
a standardization committee has come along and insisted that the two values
should be different.  In this book we'll consider them as different, but
we'll try to avoid examples in which it matters.  The main point is that you
shouldn't be surprised if you see something like this:

<P><PRE>&gt; (= 3 4)
()
</PRE>

<P>in the particular implementation of Scheme that you're using.
<P>
<A NAME="ft2" HREF="true#text2">[2]</A> Why is it called that?  Think about an English
sentence, such as &quot;Ringo is a drummer.&quot; As you may remember from elementary
school, &quot;Ringo&quot; is the <EM>subject</EM> of that sentence, and &quot;is a
drummer&quot; is the <EM>predicate.</EM> That predicate could be truthfully
attached to some subjects but not others.  For example, it's true of &quot;Neil
Peart&quot; but not of &quot;George Harrison.&quot; So the predicate &quot;is a drummer&quot;
can be thought of as a function whose value is true or false.<P>
<A NAME="ft3" HREF="true#text3">[3]</A> Since you
can start a new line in the middle of an expression, in some cases the
arguments will be &quot;top to bottom&quot; rather than &quot;left to right,&quot; but don't
forget that Scheme doesn't care about line breaks.  That's why Lisp
programmers always talk as if their programs were written on one enormously
long line.<P>
<A NAME="ft4" HREF="true#text4">[4]</A> What if you don't use an <CODE>else</CODE>
clause at all?  If none of the clauses has a true condition, then the return
value is unspecified.  In other words, always use <CODE>else</CODE>.<P>
<A NAME="ft5" HREF="true#text5">[5]</A> Conditions are mutually
exclusive if only one of them can be true at a time.<P>
<A NAME="ft6" HREF="true#text6">[6]</A> Strictly speaking, since the argument expressions to a
special form aren't evaluated, <CODE>if</CODE> is a function whose domain is
expressions, not their values.  But many special forms, including <CODE>if</CODE>,
<CODE>and</CODE>, and <CODE>or</CODE>, are designed to act as if they were ordinary
functions, the kind whose arguments Scheme evaluates in advance.  The only
difference is that it is sometimes possible for Scheme to figure out the
correct return value after evaluating only some of the arguments.  Most of
the time we'll just talk about the domains and ranges of these special forms
as if they were ordinary functions.<P>
<P><A HREF="../ss-toc2.html">(back to Table of Contents)</A><P>
<A HREF="../ssch5/words.html"><STRONG>BACK</STRONG></A>
chapter thread <A HREF="../ssch7/variables.html"><STRONG>NEXT</STRONG></A>

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