about summary refs log tree commit diff stats
path: root/src/pgp/gpg.h
diff options
context:
space:
mode:
authorMaximilian Wuttke <mwuttke97@posteo.de>2021-03-09 17:48:29 +0100
committerMaximilian Wuttke <mwuttke97@posteo.de>2021-03-09 17:48:29 +0100
commit2b1ada772256a9a661eabedf723702af5f6bfa83 (patch)
tree1a7598c6cbd07300d135254a916a13e3bc2b6d88 /src/pgp/gpg.h
parent68469149cd960a5a8fb9cd6ec4a5dd4ca139a4a7 (diff)
downloadprofani-tty-2b1ada772256a9a661eabedf723702af5f6bfa83.tar.gz
[OMEMO]: Fix bundle publishing
Use the following options in `omemo_bundle_publish()`:

- "pubsub#persist_items" = "true"
- "pubsub#access_model" = "open"

The same options are also used in Gajim.

I've tested this on two different servers. The bundle was successfully
added as a new PEP node. Test cases:

1. Normal use on my main account
2. Log in into a fresh tesst account on a different server
3. `/omemo clear_device_list`. In this case, the client(s) may have to
   be restarted.

Note: In `_omemo_bundle_publish_result`, there's a route that is taken
when the bundle publish stanza failed. In this case, the node is
configured manually, i.e. the access_model is set to 'open'. I have
manually tested this case, but this case didn't naturally occur for me.

Note: The option "pubsub#max_items=max" is REQUIRED for the bundle
publication, as per XEP-0384. However, this is not done in other clients
(I've checked the source code of Gajim and Conversations), and it is
also not supported by Prosody. Cf. <https://github.com/xsf/xeps/pull/988>.
Diffstat (limited to 'src/pgp/gpg.h')
0 files changed, 0 insertions, 0 deletions
n80'>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



























































































































































































































































































































































































































































































































































































































































































































































































































































































                                                                                                                                                                                                                                                                     
<P>

<P> <A NAME="hands"></A>
<CENTER><IMG SRC="../ss-pics/hands.jpg" ALT="figure: hands"></CENTER><P><CENTER><EM>Drawing Hands,</EM> by M. C. Escher (lithograph,
1948)
</CENTER><P>

<HTML>
<HEAD>
<TITLE>Simply Scheme: Introducing Computer Science ch 12: The Leap of Faith</TITLE>
</HEAD>
<BODY>
<HR>
<CITE>Simply Scheme:</CITE>
<CITE>Introducing Computer Science</CITE> 2/e Copyright (C) 1999 MIT
<H2>Chapter 12</H2>
<H1>The Leap of Faith</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/ssch12.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="../ssch11/recursion.html"><STRONG>BACK</STRONG></A>
chapter thread <A HREF="../ssch13/convince-recur.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>In the combining method, we build up to a recursive procedure by writing a
number of special-case nonrecursive procedures, starting with small arguments
and working toward larger ones.  We find a generalizable way to use a
smaller version in writing a larger one.  As a result, all our procedures
end up looking nearly the same, so we combine them into one procedure.  

<P>The combining method is a good way to begin thinking about recursion because
each step of a solution is clearly justified by earlier steps.  The sequence
of events by which we get from a problem statement to a Scheme procedure is
clear and straightforward.  The disadvantage of the combining method,
though, is that it involves a lot of drudgery, not all of which really helps
toward the ultimate solution.  In this chapter we're going to develop a new
method called <EM>the leap of faith</EM> that overcomes this difficulty.

<P><H2>From the Combining Method to the Leap of Faith</H2>

<P>Let's look again at the way we developed the <CODE>letter-pairs</CODE> procedure in
the last chapter.  We went through several steps:

<P><P><TABLE><TR><TH align="right" valign="top">&bull;<TD>&nbsp;&nbsp;&nbsp;&nbsp;<TD valign="top">We wrote specific versions for zero-, one-, two-, and three-letter words.
</TABLE><TABLE><TR><TH align="right" valign="top">&bull;<TD>&nbsp;&nbsp;&nbsp;&nbsp;<TD valign="top">We wrote <CODE>letter-pairs4</CODE>, decided it was too complicated, and looked
for a way to use <CODE>letter-pairs3</CODE> to help.
</TABLE><TABLE><TR><TH align="right" valign="top">&bull;<TD>&nbsp;&nbsp;&nbsp;&nbsp;<TD valign="top">Having rewritten <CODE>letter-pairs4</CODE>, we tried to write <CODE>letter-pairs5</CODE> using the same pattern.  Since it didn't quite work, we
revised the pattern.
</TABLE><TABLE><TR><TH align="right" valign="top">&bull;<TD>&nbsp;&nbsp;&nbsp;&nbsp;<TD valign="top">We generalized the pattern to write an unnumbered, recursive <CODE>letter-pairs</CODE>.
</TABLE><TABLE><TR><TH align="right" valign="top">&bull;<TD>&nbsp;&nbsp;&nbsp;&nbsp;<TD valign="top">We checked to make sure that the recursive pattern would work for
two-letter and three-letter words.
</TABLE><TABLE><TR><TH align="right" valign="top">&bull;<TD>&nbsp;&nbsp;&nbsp;&nbsp;<TD valign="top">Since the pattern doesn't work for zero- or one-letter words, we made
those the base cases.

</TABLE>
<P>
Although we needed the lowest numbered procedures in order to make
the entire collection of numbered procedures work, those low-numbered ones
didn't contribute to the critical step of finding a generalizable pattern.
Once you understand the idea of recursion, writing the individual procedures
is wasted effort.

<P>In the leap of faith method, we short-circuit this process in two ways.
First, we don't bother thinking about small examples; we begin with, for
example, a seven-letter word.  Second, we don't use our example to write a
particular numbered procedure; we write the recursive version directly.

<P><H2>Example: <CODE><B>Reverse</B></CODE></H2>

<P>We're going to write, using the leap of faith method, a recursive procedure
to reverse the letters of a word:

<P><PRE>&gt; (reverse 'beatles)
SELTAEB
</PRE>

<P>Is there a <CODE>reverse</CODE> of a smaller argument lurking within
that return value?  Yes, many of them.  For example, <CODE>LTA</CODE> is the
<CODE>reverse</CODE> of the word <CODE>ATL</CODE>.  But it will be most helpful if we
find a smaller subproblem that's only <EM>slightly</EM> smaller.  (This idea
corresponds to writing <CODE>letter-pairs7</CODE> using <CODE>letter-pairs6</CODE> in the
combining method.)  The closest smaller subproblem to our original problem
is to find the <CODE>reverse</CODE> of a word one letter shorter than <CODE>beatles</CODE>.

<P><PRE>&gt; (reverse 'beatle)
ELTAEB
</PRE>

<P>This result is pretty close to the answer we want for <CODE>reverse</CODE> of <CODE>beatles</CODE>.  What's the relationship between <CODE>ELTAEB</CODE>,
the answer to the smaller problem, and <CODE>SELTAEB</CODE>, the answer to the
entire problem?  There's one extra letter, <CODE>S</CODE>, at the beginning.  Where
did the extra letter come from?  Obviously, it's the last letter of <CODE>beatles</CODE>.<A NAME="text1" HREF="leap#ft1">[1]</A>

<P>This may seem like a sequence of trivial observations leading nowhere.  But
as a result of this investigation, we can translate what we've learned
directly into Scheme.  In English:  &quot;the <CODE>reverse</CODE> of a word consists
of its last letter followed by the <CODE>reverse</CODE> of its <CODE>butlast</CODE>.&quot; In
Scheme:

<P><PRE>(define (reverse wd)                    ;; unfinished
  (word (last wd)
	(reverse (bl wd))))
</PRE>

<P><H2>The Leap of Faith</H2>

<P>If we think of this Scheme fragment merely as a statement of a true fact
about <CODE>reverse</CODE>, it's not very remarkable.  The amazing part is that
this fragment is <EM>runnable!</EM><A NAME="text2" HREF="leap#ft2">[2]</A> It doesn't <EM>look</EM> runnable because it invokes itself as a
helper procedure, and&mdash;if you haven't already been through the combining
method&mdash;that looks as if it can't work.  &quot;How can you use <CODE>reverse</CODE>
when you haven't written it yet?&quot;

<P>The leap of faith method is the assumption that the procedure we're in the
middle of writing already works.  That is, if we're thinking about writing a
<CODE>reverse</CODE> procedure that can compute <CODE>(reverse 'paul)</CODE>, we
assume that <CODE>(reverse 'aul)</CODE> will work.

<P>Of course it's not <EM>really</EM> a leap of faith, in the sense of something
accepted as miraculous but not understood.  The assumption is justified
by our understanding of the combining method.  For example, we understand
that the four-letter <CODE>reverse</CODE> is relying on the three-letter version of
the problem, not really on itself, so there's no circular reasoning involved.
And we know that if we had to, we could write <CODE>reverse1</CODE> through <CODE>reverse3</CODE> &quot;by hand.&quot;

<P>The reason that our technique in this chapter may seem more mysterious than
the combining method is that this time we are thinking about the problem
top-down.  In the combining method, we had already written <CODE>whatever3</CODE>
before we even raised the question of <CODE>whatever4</CODE>.  Now we start by
thinking about the larger problem and assume that we can rely on the
smaller one.  Again, we're entitled to that assumption because we've gone
through the process from smaller to larger so many times already.

<P>The leap of faith method, once you understand it, is faster than the
combining method for writing new recursive procedures, because we can write
the recursive solution immediately, without bothering with many individual
cases.  The reason we showed you the combining method first is that the leap
of faith method seems too much like magic, or like &quot;cheating,&quot; until
you've seen several believable recursive programs.  The combining method is
the way to learn about recursion; the leap of faith method is the way to
write recursive procedures once you've learned.

<P><H2>The Base Case</H2>

<P>Of course, our definition of <CODE>reverse</CODE> isn't finished yet: As always, we
need a base case.  But base cases are the easy part.  Base cases transform
simple arguments into simple answers, and you can do that transformation in
your head.

<P>For example, what's the simplest argument to <CODE>reverse</CODE>?  If you
answered &quot;a one-letter word&quot; then pick a one-letter word and decide what
the result should be:

<P><PRE>&gt; (reverse 'x)
X
</PRE>

<P><CODE>reverse</CODE> of a one-letter word should just be that same word:

<P><PRE>(define (reverse wd)
  (if (= (count wd) 1)
      wd
      (word (last wd)
	    (reverse (bl wd)))))
</PRE>

<P><H2>Example: <CODE><B>Factorial</B></CODE></H2>

<P>We'll use the leap of faith method to solve another problem that
we haven't already solved with the combining method.

<P>The factorial of a number <EM>n</EM> is defined as 1&#x00d7;2&#x00d7;&#x00b7;&#x00b7;&#x00b7;&#x00d7;<EM>n</EM>.  So the factorial of 5 (written &quot;5!&quot;) is 1&#x00d7;2&#x00d7;3&#x00d7;4&#x00d7;5.  Suppose you want Scheme to figure out the factorial of
some large number, such as 843.  You start from the definition:  843! is 1&#x00d7;2&#x00d7;&#x00b7;&#x00b7;&#x00b7;&#x00d7;842&#x00d7;843.  Now you have to look for
another factorial problem whose answer will help us find the answer to
843!.  You might notice that 2!, that is, 1&#x00d7;2, is part of 843!,
but that doesn't help very much because there's no simple relationship
between 2! and 843!.  A more fruitful observation would be that 842!
is 1&#x00d7;&#x00b7;&#x00b7;&#x00b7;&#x00d7;842&mdash;that is, all but the last number in the
product we're trying to compute.  So 843! = 843&#x00d7;842!.  In general,
<EM>n</EM>! is <EM>n</EM>&#x00d7;(<EM>n</EM>-1)!.  We can embody this idea in a Scheme procedure:

<P><PRE>(define (factorial n)                        ;; first version
  (* n (factorial (- n 1))))
</PRE>

<P>Asking for (<EM>n</EM>-1)! is the leap of faith.  We're expressing an
answer we don't know, 843!, in terms of another answer we don't know,
842!.  But since 842! is a smaller, similar subproblem, we are confident
that the same algorithm will find it.<A NAME="text3" HREF="leap#ft3">[3]</A>

<P>Remember that in the <CODE>reverse</CODE> problem we mentioned that we could have
chosen either the <CODE>butfirst</CODE> or the <CODE>butlast</CODE> of the argument as the
smaller subproblem?  In the case of the <CODE>factorial</CODE> problem we don't
have a similar choice.  If we tried to subdivide the problem as

<P><P ALIGN="center">6! = 1&#x00d7;(2&#x00d7;3&#x00d7;4&#x00d7;5&#x00d7;6)</P>
<P>

then the part in
parentheses would <EM>not</EM> be the factorial of a smaller
number.<A NAME="text4" HREF="leap#ft4">[4]</A>

<P>As the base case for <CODE>factorial</CODE>, we'll use 1! = 1.

<P><PRE>(define (<A NAME="g1"></A>factorial n)
  (if (= n 1)
      1
      (* n (factorial (- n 1)))))
</PRE>

<P><H2>Likely Guesses for Smaller Subproblems</H2>

<P>To make the leap of faith method work, we have to find a smaller, similar
subproblem whose solution will help solve the given problem.  How do we find
such a smaller subproblem?

<P>In the examples so far, we've generally found it by finding a smaller,
similar <EM>return value</EM> within the return value we're trying to
achieve.  Then we worked backward from the smaller solution to figure out
what smaller argument would give us that value.  For example, here's how we
solved the <CODE>reverse</CODE> problem:

<P><TABLE><TR><TD>original argument<TD>&nbsp;&nbsp;<CODE>beatles</CODE>
<TR><TD>desired return value<TD>&nbsp;&nbsp;<CODE>SELTAEB</CODE>
<TR><TD>smaller return value<TD>&nbsp;&nbsp;<CODE>ELTAEB</CODE>
<TR><TD>corresponding argument<TD>&nbsp;&nbsp;<CODE>beatle</CODE>
<TR><TD>relationship of arguments
<TD>&nbsp;&nbsp;<CODE>beatle </CODE>is<CODE> (bl 'beatles)</CODE>
<TR><TD>Scheme expression<TD>&nbsp;&nbsp;<CODE>(word (last arg)
<TR><TD>&nbsp;<TD>&nbsp;&nbsp;<CODE>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(reverse (bl arg)))
</TABLE>


<P>Similarly, we looked at the definition of 843! and noticed within it
the factorial of a smaller number, 842.

<P>But a smaller return value won't necessarily leap out at us in every case.
If not, there are some likely guesses we can try.  For example, if the
problem is about integers, it makes sense to try <EM>n</EM>&minus;1 as a smaller
argument.  If the problem is about words or sentences, try the <CODE>butfirst</CODE> or the <CODE>butlast</CODE>.  (Often, as in the <CODE>reverse</CODE> example,
either will be helpful.)  Once you've guessed at a smaller argument, see
what the corresponding return value should be, then compare that with the
original desired return value as we've described earlier.

<P>In fact, these two argument-guessing techniques would have suggested the same
subproblems that we ended up using in our two examples so far.  The reason we
didn't teach these techniques from the beginning is that we don't want you
to think they're essential parts of the leap of faith method.  These are
just good guesses; they don't always work.  When they don't, you have to be
prepared to think more flexibly.

<P><H2>Example: <CODE><B>Downup</B></CODE></H2>

<P>Here's how we might rewrite <CODE><A NAME="g2"></A>downup</CODE> using the leap of faith
method.  Start by looking at the desired return value for a medium-sized
example:

<P><PRE>&gt; (downup 'paul)
(PAUL PAU PA P PA PAU PAUL)
</PRE>

<P>Since this is a procedure whose argument is a word, we guess that
the <CODE>butfirst</CODE> or the <CODE>butlast</CODE> might be helpful.

<P><PRE>&gt; (downup 'aul)
(AUL AU A AU AUL)

&gt; (downup 'pau)
(PAU PA P PA PAU)
</PRE>

<P>This is a case in which it matters which we choose; the solution for the
<CODE>butfirst</CODE> of the original argument doesn't help, but the solution for
the <CODE>butlast</CODE> is most of the solution for the original word.  All we
have to do is add the original word itself at the beginning and end:

<P><PRE>(define (downup wd)                          ;; no base case
  (se wd (downup (bl wd)) wd))
</PRE>

<P>As before, this is missing the base case, but by now you know how
to fill that in.

<P><H2>Example: <CODE><B>Evens</B></CODE></H2>

<P>Here's a case in which mindlessly guessing <CODE>butfirst</CODE> or <CODE>butlast</CODE>
doesn't lead to a very good solution.  We want a procedure that takes a
sentence as its argument and returns a sentence of the even-numbered words
of the original sentence:

<P><PRE>&gt; (<A NAME="g3"></A>evens '(i want to hold your hand))
(WANT HOLD HAND)
</PRE>

<P>We look at <CODE>evens</CODE> of the <CODE>butfirst</CODE> and <CODE>butlast</CODE> of
this sentence:

<P><PRE>&gt; (evens '(want to hold your hand))
(TO YOUR)

&gt; (evens '(i want to hold your))
(WANT HOLD)
</PRE>

<P><CODE>Butfirst</CODE> is clearly not helpful; it gives all the wrong
words.  <CODE>Butlast</CODE> looks promising.  The relationship between <CODE>evens</CODE>
of the bigger sentence and <CODE>evens</CODE> of the smaller sentence is that the
last word of the larger sentence is missing from <CODE>evens</CODE> of the smaller
sentence.

<P><PRE>(define (losing-evens sent)                  ;; no base case
  (se (losing-evens (bl sent))
      (last sent)))
</PRE>

<P>For a base case, we'll take the empty sentence:

<P><PRE>(define (losing-evens sent)
  (if (empty? sent)
      '()
      (se (losing-evens (bl sent))
	  (last sent))))

&gt; (losing-evens '(i want to hold your hand))
(I WANT TO HOLD YOUR HAND)
</PRE>

<P>This isn't quite right.

<P>It's true that <CODE>evens</CODE> of <CODE>(i want to hold your hand)</CODE> is the same
as <CODE>evens</CODE> of <CODE>(i want to hold your)</CODE> plus the word <CODE>hand</CODE> at
the end.  But what about <CODE>evens</CODE> of <CODE>(i want to hold your)</CODE>?  By the
reasoning we've been using, we would expect that to be <CODE>evens</CODE> of <CODE>(i want to hold)</CODE> plus the word <CODE>your</CODE>.  But since the word <CODE>your</CODE>
is the fifth word of the argument sentence, it shouldn't be part of the
result at all.  Here's how <CODE>evens</CODE> should work:

<P><PRE>&gt; (evens '(i want to hold your))
(WANT HOLD)

&gt; (evens '(i want to hold))
(WANT HOLD)
</PRE>

<P>When the sentence has an odd number of words, its <CODE>evens</CODE> is
the same as the <CODE>evens</CODE> of its <CODE>butlast</CODE>.<A NAME="text5" HREF="leap#ft5">[5]</A> So here's our
new procedure:

<P><PRE>(define (evens sent)                         ;; better version
  (cond ((empty? sent) '())
	((odd? (count sent))
	 (evens (bl sent)))
	(else (se (evens (bl sent))
		  (last sent)))))
</PRE>

<P>This version works, but it's more complicated than necessary.  What makes it
complicated is that on each recursive call we switch between two kinds of
problems: even-length and odd-length sentences.  If we dealt with the words
two at a time, each recursive call would see the same kind of problem.

<P>Once we've decided to go through the sentence two words at a time, we can
reopen the question of whether to go right-to-left or left-to-right.  It
will turn out that the latter gives us the simplest procedure:

<P><PRE>(define (evens sent)                         ;; best version
  (if (&lt;= (count sent) 1)
      '()
      (se (first (bf sent))
	  (evens (bf (bf sent))))))
</PRE>

<P>Since we go through the sentence two words at a time, an
odd-length argument sentence always gives rise to an odd-length recursive
subproblem.  Therefore, it's not good enough to check for an empty sentence
as the only base case.  We need to treat both the empty sentence and one-word
sentences as base cases.

<P><H2>Simplifying Base Cases</H2>
<A NAME="basecasereduce"></A>
<A NAME="g4"></A>
<A NAME="g5"></A>

<P>The leap of faith is mostly about recursive cases, not base cases.  In the
examples in this chapter, we've picked base cases without talking about them
much.  How do you pick a base case?

<P>In general, we recommend using the smallest possible base case argument,
because that usually leads to the simplest procedures.  For example,
consider using the empty word, empty sentence, or zero instead of one-letter
words, one-word sentences, or one.

<P>How can you go about finding the simplest possible base case?  Our first
example in this chapter was <CODE>reverse</CODE>.  We arbitrarily chose to use
one-letter words as the base case:

<P><PRE>(define (reverse wd)
  (if (= (count wd) 1)
      wd
      (word (last wd)
	    (reverse (bl wd)))))
</PRE>

<P>Suppose we want to consider whether a smaller base case would work.  One
approach is to pick an argument that would be handled by the current base
case, and see what would happen if we tried to let the recursive step handle
it instead.  (To go along with this experiment, we pick a smaller base case,
since the original base case should now be handled by the recursive step.)
In this example, we pick a one-letter word, let's say <CODE>m</CODE>, and use that
as the value of <CODE>wd</CODE> in the expression

<P><PRE>(word (last wd)
      (reverse (bl wd)))
</PRE>

<P>The result is

<P><PRE>(word (last 'm)
      (reverse (bl 'm)))
</PRE>

<P>which is the same as

<P><PRE>(word 'm
      (reverse &quot;&quot;))
</PRE>

<P>We want this to have as its value the word <CODE>M</CODE>.  This will
work out provided that <CODE>(reverse &quot;&quot;)</CODE> has the empty word as its value.
So we could rewrite the procedure this way:

<P><PRE>(define (reverse wd)
  (if (empty? wd)
      &quot;"
      (word (last word)
	    (reverse (bl word)))))
</PRE>

<P>We were led to this empty-word base case by working downward from the needs
of the one-letter case.  However, it's also important to ensure that the
return value used for the empty word is the correct value, not only to make
the recursion work, but for an empty word in its own right.  That is, we
have to convince ourselves that <CODE>(reverse &quot;&quot;)</CODE> should return an empty
word.  But it should; the <CODE>reverse</CODE> of any word is a word containing the
same letters as the original word.  If the original has no letters, the <CODE>reverse</CODE> must have no letters also.  This exemplifies a general principle:
Although we choose a base case argument for the sake of the recursive step,
we must choose the corresponding return value for the sake of the argument
itself, not just for the sake of the recursion.

<P>We'll try the base case reduction technique on <CODE>downup</CODE>:

<P><PRE>(define (downup wd)
  (if (= (count wd) 1)
      (se wd)
      (se wd (downup (bl wd)) wd)))
</PRE>

<P>If we want to use the empty word as the base case, instead of
one-letter words, then we have to ensure that the recursive case can return
a correct answer for a one-letter word.  The behavior we want is

<P><PRE>&gt; (downup 'a)
(A)
</PRE>

<P>But if we substitute <CODE>'a</CODE> for <CODE>wd</CODE> in the recursive-case
expression we get

<P><PRE>(se 'a (downup &quot;&quot;) 'a)
</PRE>

<P>which will have two copies of the word <CODE>A</CODE> in its value no
matter what value we give to <CODE>downup</CODE> of the empty word.  We can't
avoid treating one-letter words as a base case.

<P>In writing <CODE>factorial</CODE>, we used <CODE>1</CODE> as the base case.

<P><PRE>(define (factorial n)
  (if (= n 1)
      1
      (* n (factorial (- n 1)))))
</PRE>

<P>Our principle of base case reduction suggests that we try for <CODE>0</CODE>.  To do this, we substitute <CODE>1</CODE> for <CODE>n</CODE> in the recursive case
expression:

<P><PRE>(* 1 (factorial 0))
</PRE>

<P>We'd like this to have the value <CODE>1</CODE>; this will be true only
if we define 0! = 1.  Now we can say

<P><PRE>(define (factorial n)
  (if (= n 0)
      1
      (* n (factorial (- n 1)))))
</PRE>

<P>In this case, the new procedure is no simpler than the previous
version.  Its only advantage is that it handles a case, 0!, that
mathematicians find useful.

<P>Here's another example in which we can't reduce the base case to an empty
word.  In Chapter 11 we used the combining method to write <CODE>letter-pairs</CODE>:

<P><PRE>(define (letter-pairs wd)
  (if (&lt;= (count wd) 1)
      '()
      (se (first-two wd)
	  (letter-pairs (bf wd)))))

(define (first-two wd)
  (word (first wd) (first (bf wd))))
</PRE>

<P>It might occur to you that one-letter words could be handled
by the recursive case, and the base case could then handle only the empty
word.  But if you try to evaluate the expression for the recursive case
as applied to a one-letter word, you find that

<P><PRE>(first-two 'a)
</PRE>

<P>is equivalent to

<P><PRE>(word (first 'a) (first (bf 'a)))
</PRE>

<P>which is an error.  There is no second letter of a one-letter
word.  As soon as you see the expression <CODE>(first (bf wd))</CODE> within
this program, you know that one-letter words must be part of the base case.
The same kind of reasoning can be used in many problems; the base case must
handle anything that's too small to fit the needs of the recursive case.

<P>
<H2>Pitfalls</H2>

<P>One possible pitfall is a recursive case that doesn't make progress,
that is, one that doesn't reduce the size of the problem in the recursive call.
For example, let's say we're trying to write the procedure <CODE>down</CODE> that
works this way:

<P><PRE>&gt; (down 'town)
(TOWN TOW TO T)
</PRE>

<P>Here's an incorrect attempt:

<P><PRE>(define (down wd)                            ;; wrong!
  (if (empty? wd)
      '()
      (se wd (down (first wd)))))
</PRE>

<P>The recursive call looks as if it reduces the size of the problem,
but try it with an actual example.  What's <CODE>first</CODE> of the word <CODE>splat</CODE>?  What's <CODE>first</CODE> of that result?  What's <CODE>first</CODE> of <EM>that</EM> result?

<P>A pitfall that sounds unlikely in the abstract but is actually
surprisingly common is to try to do the second step of the procedure &quot;by
hand&quot; instead of trusting the recursion to do it.  For example, here's
another attempt at that <CODE>down</CODE> procedure:

<P><PRE>(define (down wd)                            ;; incomplete
  (se wd &hellip;))
</PRE>

<P>You know the first word in the result has to be the argument
word.  Then what?  The next thing is the same word with its last letter
missing:

<P><PRE>(define (down wd)                            ;; wrong!
  (se wd (bl wd) &hellip;))
</PRE>

<P>Instead of taking care of the entire rest of the problem with a
recursive call, it's tempting to take only one more step, figuring out how
to include the second word of the required solution.  But that approach
won't get you to a general recursive solution.  Just take the first step
and then trust the recursion for the rest:

<P><PRE>(define (<A NAME="g6"></A>down wd)
  (if (empty? wd)
      '()
      (se wd (down (bl wd)))))
</PRE>

<P>The value returned in the base case of your procedure must be in the
range of the function you are representing.  If your function is supposed to
return a number, it must return a number all the time, even in the base
case.  You can use this idea to help you check the correctness of the
base case expression.

<P>For example, in <CODE>downup</CODE>, the base case returns <CODE>(se wd)</CODE> for the
base case argument of a one-letter word.  How did we think to enclose the
word in a sentence?  We know that in the recursive cases <CODE>downup</CODE> always
returns a sentence, so that suggests to us that it must return a sentence in
the base case also.

<P>If your base case doesn't make sense in its own right, it probably
means that you're trying to compensate for a mistake in the recursive case.

<P>For example, suppose you've fallen into the pitfall of trying to handle the
second word of a sentence by hand, and you've written the following
procedure:

<P><PRE>(define (square-sent sent)                   ;; wrong
  (if (empty? sent)
      '()
      (se (square (first sent))
	  (square (first (bf sent)))
	  (square-sent (bf sent)))))

&gt; (square-sent '(2 3))
ERROR: Invalid argument to FIRST:  ()
</PRE>

<P>After some experimentation, you find that you can get this example
to work by changing the base case:

<P><PRE>(define (square-sent sent)                   ;; still wrong
  (if (= (count sent) 1)
      '()
      (se (square (first sent))
	  (square (first (bf sent)))
	  (square-sent (bf sent)))))

&gt; (square-sent '(2 3))
(4 9)
</PRE>

<P>The trouble is that the base case doesn't make sense on its own:

<P><PRE>&gt; (square-sent '(7))
()
</PRE>

<P>In fact, this procedure doesn't work for any sentences of length
other than two.  The moral is that it doesn't work to correct an error in the
recursive case by introducing an absurd base case.

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

<P><B>12.1</B>&nbsp;&nbsp;Here is a definition of a procedure that returns the sum of the numbers in
its argument sentence:

<P><PRE>(define (addup nums)
  (if (empty? (bf nums))
      (first nums)
      (+ (first nums) (addup (bf nums)))))
</PRE>

<P>Although this works, it could be simplified by changing the base
case.  Do that.


<P>
<B>12.2</B>&nbsp;&nbsp;Fix the bug in the following definition:

<P><PRE>(define (acronym sent)                       ;; wrong
  (if (= (count sent) 1)
      (first sent)
      (word (first (first sent))
	    (acronym (bf sent)))))
</PRE>

<P>
<B>12.3</B>&nbsp;&nbsp;Can we reduce the <CODE>factorial</CODE> base case argument from <CODE>0</CODE> to <CODE>-1</CODE>?
If so, show the resulting procedure.  If not, why not?

<P>

<P>
<B>12.4</B>&nbsp;&nbsp;Here's the definition of a function <EM>f</EM>:

<P><P><CENTER><IMG SRC="math1.gif" ALT="math display"></CENTER><P>

<P>Implement <EM>f</EM> as a Scheme procedure.  What does <EM>f</EM> do?


<P>

<H2>Real Exercises</H2>

<P><EM>Solve all of the following problems with recursive procedures.  If
you've read Part III, do not use any higher-order functions such as <CODE>every</CODE>, <CODE>keep</CODE>, or <CODE>accumulate</CODE>.</EM>

<P><B>12.5</B>&nbsp;&nbsp;[<A HREF="../ssch8/higher.html#exagg">8.8</A>]
Write an <CODE><A NAME="g7"></A>exaggerate</CODE> procedure which exaggerates sentences:
<A NAME="exaggrec"></A>

<P><PRE>&gt; (exaggerate '(i ate 3 potstickers))
(I ATE 6 POTSTICKERS)

&gt; (exaggerate '(the chow fun is good here))
(THE CHOW FUN IS GREAT HERE)
</PRE>

<P>It should double all the numbers in the sentence, and it should replace
&quot;good&quot; with &quot;great,&quot; &quot;bad&quot; with &quot;terrible,&quot; and anything else you
can think of.


<P>
<B>12.6</B>&nbsp;&nbsp;[<A HREF="../ssch8/higher.html#gpa">8.11</A>]
Write a GPA procedure.  It should take a sentence of grades as its argument
and return the corresponding grade point average:
<A NAME="gparec"></A>

<P><PRE>&gt; (<A NAME="g8"></A>gpa '(A A+ B+ B))
3.67
</PRE>

<P>Hint: write a helper procedure <CODE><A NAME="g9"></A>base-grade</CODE> that takes
a grade as argument and returns 0, 1, 2, 3, or 4, and another helper
procedure <CODE>grade-modifier</CODE> that returns &minus;.33, 0, or .33, depending on
whether the grade has a minus, a plus, or neither.


<P>
<B>12.7</B>&nbsp;&nbsp;Write a procedure <A NAME="g10"></A><CODE>spell-number</CODE> that spells out the digits of
a number:

<P><PRE>&gt; (spell-number 1971)
(ONE NINE SEVEN ONE)
</PRE>

<P>Use this helper procedure:

<P><PRE>(define (spell-digit digit)
  (item (+ 1 digit)
	'(zero one two three four five six seven eight nine)))
</PRE>


<P>
<B>12.8</B>&nbsp;&nbsp;Write a procedure <CODE><A NAME="g11"></A>numbers</CODE> that takes a sentence as its argument
and returns another sentence containing only the numbers in the argument:

<P><PRE>&gt; (numbers '(76 trombones and 110 cornets))
(76 110)
</PRE>

<P>
<B>12.9</B>&nbsp;&nbsp;Write a procedure <CODE><A NAME="g12"></A>real-words</CODE> that takes a sentence as argument
and returns all the &quot;real&quot; words of the sentence, using the same rule as
the <CODE>real-word?</CODE> procedure from Chapter 1.


<P>
<B>12.10</B>&nbsp;&nbsp;Write a procedure <CODE><A NAME="g13"></A>remove</CODE> that takes a word and a sentence as
arguments and returns the same sentence, but with all copies of the given
word removed:

<P><PRE>&gt; (remove 'the '(the song love of the loved by the beatles))
(SONG LOVE OF LOVED BY BEATLES)
</PRE>

<P>
<B>12.11</B>&nbsp;&nbsp;Write the procedure <CODE>count</CODE>, which returns the number of words in a
sentence or the number of letters in a word.


<P>
<B>12.12</B>&nbsp;&nbsp;Write a procedure <CODE><A NAME="g14"></A>arabic</CODE> which converts Roman numerals into
Arabic numerals:

<P><PRE>&gt; (arabic 'MCMLXXI)
1971

&gt; (arabic 'MLXVI)
1066
</PRE>

<P>You will probably find the <CODE>roman-value</CODE> procedure from Chapter
6 helpful.  Don't forget that a letter can <EM>reduce</EM> the overall
value if the letter that comes after it has a larger value, such as the <CODE>C</CODE> in <CODE>MCM</CODE>.


<P>
<B>12.13</B>&nbsp;&nbsp;Write a new version of the <CODE><A NAME="g15"></A>describe-time</CODE> procedure from Exercise
.  Instead of returning a decimal number, it should behave like
this:

<P><PRE>&gt; (describe-time 22222)
(6 HOURS 10 MINUTES 22 SECONDS)

&gt; (describe-time 4967189641)
(1 CENTURIES 57 YEARS 20 WEEKS 6 DAYS 8 HOURS 54 MINUTES 1 SECONDS)
</PRE>

<P>Can you make the program smart about saying <CODE>1 CENTURY</CODE> instead of
<CODE>1 CENTURIES</CODE>?


<P>

<HR>
<A NAME="ft1" HREF="leap#text1">[1]</A> There's also a relationship between <CODE>(reverse 'eatles)</CODE>
and <CODE>(reverse 'beatles)</CODE>, with the extra letter <CODE>b</CODE> at the end.  We
could take either of these subproblems as a starting point and end up with a
working procedure.<P>
<A NAME="ft2" HREF="leap#text2">[2]</A> Well, almost.  It needs a base
case.<P>
<A NAME="ft3" HREF="leap#text3">[3]</A> What makes us confident?  We
imagine that we've worked on this problem using the combining method, so
that we've written procedures like these:

<P><PRE>(define (factorial1 n)
  1)

(define (factorial2 n)
  (* 2 (factorial1 (- n 1))))

(define (factorial3 n)
  (* 3 (factorial2 (- n 1))))

;; ...

(define (factorial842 n)
  (* 842 (factorial841 (- n 1))))
</PRE>

<P>and therefore we're entitled to use those lower-numbered versions
in finding the factorial of 843.  We haven't actually written them, but we
could have, and that's what justifies using them.  The reason we can take
842! on faith is that 842 is smaller than 843; it's the smaller values
that we're pretending we've already written. 
<P>
<A NAME="ft4" HREF="leap#text4">[4]</A> As it happens, the part in parentheses does equal the
factorial of a number, 6 itself.  But expressing the solution for 6 in terms
of the solution for 6 doesn't lead to a recursive procedure; we have to
express this solution in terms of a <EM>smaller</EM> one.<P>
<A NAME="ft5" HREF="leap#text5">[5]</A> It may feel
strange that in the case of an odd-length sentence, the answer to the
recursive subproblem is the same as the answer to the original problem,
rather than a smaller answer.  But remember that it's the argument, not the
return value, that has to get smaller in each recursive step.<P>
<P><A HREF="../ss-toc2.html">(back to Table of Contents)</A><P>
<A HREF="../ssch11/recursion.html"><STRONG>BACK</STRONG></A>
chapter thread <A HREF="../ssch13/convince-recur.html"><STRONG>NEXT</STRONG></A>

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