about summary refs log tree commit diff stats
path: root/js/games/nluqo.github.io/~bh/v3ch1/v3ch1.html
diff options
context:
space:
mode:
authorelioat <elioat@tilde.institute>2023-08-23 07:52:19 -0400
committerelioat <elioat@tilde.institute>2023-08-23 07:52:19 -0400
commit562a9a52d599d9a05f871404050968a5fd282640 (patch)
tree7d3305c1252c043bfe246ccc7deff0056aa6b5ab /js/games/nluqo.github.io/~bh/v3ch1/v3ch1.html
parent5d012c6c011a9dedf7d0a098e456206244eb5a0f (diff)
downloadtour-562a9a52d599d9a05f871404050968a5fd282640.tar.gz
*
Diffstat (limited to 'js/games/nluqo.github.io/~bh/v3ch1/v3ch1.html')
-rw-r--r--js/games/nluqo.github.io/~bh/v3ch1/v3ch1.html1977
1 files changed, 1977 insertions, 0 deletions
diff --git a/js/games/nluqo.github.io/~bh/v3ch1/v3ch1.html b/js/games/nluqo.github.io/~bh/v3ch1/v3ch1.html
new file mode 100644
index 0000000..5f94725
--- /dev/null
+++ b/js/games/nluqo.github.io/~bh/v3ch1/v3ch1.html
@@ -0,0 +1,1977 @@
+<HTML>
+<HEAD>
+<TITLE>Computer Science Logo Style vol 3 ch 1: Automata Theory</TITLE>
+</HEAD>
+<BODY>
+<CITE>Computer Science Logo Style</CITE> volume 3:
+<CITE>Beyond Programming</CITE> 2/e Copyright (C) 1997 MIT
+<H1>Automata Theory</H1>
+
+<TABLE width="100%"><TR><TD>
+<IMG SRC="../csls3.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/v3ch01.pdf">Download PDF version</A>
+<TR><TD align="right"><A HREF="../v3-toc2.html">Back to Table of Contents</A>
+<TR><TD align="right"><A HREF="../v3ch0/v3ch0.html"><STRONG>BACK</STRONG></A>
+chapter thread <A HREF="../v3ch2/v3ch2.html"><STRONG>NEXT</STRONG></A>
+<TR><TD align="right"><A HREF="https://mitpress.mit.edu/books/computer-science-logo-style-second-edition-volume-3">MIT
+Press web page for <CITE>Computer Science Logo Style</CITE></A>
+</TABLE></TABLE>
+
+<HR><P>Program file for this chapter: <A HREF="fsm.lg"><CODE>fsm</CODE></A>
+
+
+
+<P>As I explained in the preface to the first volume, one of my purposes in
+writing this series of books has been to urge computer hobbyists away from
+the view of computer expertise as the knowledge of obscure characteristics
+of some particular computer--how to program it in machine language, what
+magic numbers can be found where in its memory, how to overcome the copy
+protection schemes on its disks, and so on.  The trouble with this sort of
+machine-specific expertise is that it becomes obsolete when your favorite
+computer does.  From my point of view, one of the virtues of Logo as a
+programming language is that its high level data structures direct your
+attention away from questions about what goes where in memory,
+allowing you to focus instead on a more abstract description of your problem.
+
+<P>Automata theory is a further step in abstracting your attention away from any
+particular kind of computer or particular programming language.  In automata
+theory we consider a <EM>mathematical model</EM> of computing.  Such a model
+strips the computational machinery--the &quot;programming language&quot;--down to
+the bare minimum, so that it's easy to manipulate these
+theoretical machines
+(there are several such models, for different purposes, as you'll soon see)
+mathematically to prove things about their capabilities.  For the most part,
+these mathematical models are not used for practical programming problems.
+Real programming languages are much more convenient to use.  But the very
+flexibility that makes real languages easier to use also makes them harder
+to talk about in a formal way.  The stripped-down theoretical machines are
+designed to be examined mathematically.
+
+<P>What's a mathematical model?  You'll see one shortly, called a
+&quot;finite-state machine.&quot;
+
+<P>The point of this study is that the mathematical models are, in some
+important ways, <EM>equivalent</EM> to real computers and real programming
+languages.  What this means is that any problem that can be solved on a real
+computer can be solved using these models, and vice versa.  Anything we can
+prove about the models sheds light on the real problems of computer
+programming as well.
+
+<P>The questions asked in automata theory include these:  Are there any
+problems that no computer can solve, no matter how much time and memory it
+has?  Is it possible to <EM>prove</EM> that a particular computer program
+will actually solve a particular problem?  If a computer can use two
+different external storage devices (disks or tapes) at the same time,
+does that extend the range of problems it can solve compared to a
+machine with only one such device?
+
+<P>There is also a larger question lurking in the background of automata
+theory:  Does the human mind solve problems in the same way that a
+computer does?  Are people subject to the same limitations as computers?
+Automata theory does not actually answer this question, but the insights
+of automata theory can be helpful in trying to work out an answer.
+We'll have more to say about this in the chapter on artificial intelligence.
+
+<P><H2>What is a Computation?</H2>
+
+<P>What kinds of problems can we give to our abstract computers?  In
+automata theory we want to focus our attention on computation itself,
+not on details of input and output devices.  So we won't try creating
+a mathematical model of a video game.
+
+<P>We will play a game, though.  In this game the computer has a rule in mind.
+You type in strings of letters, using only the letters <CODE>A</CODE>, <CODE>B</CODE>, and
+<CODE>C</CODE>.  The computer tells you whether each string follows the rule or
+not.  Your job is to guess the rule.  For example, suppose you have done
+these experiments:
+
+<P><TABLE><TR><TH align="left"><U>accepted</U>
+<TH align="left">&nbsp;&nbsp;&nbsp;&nbsp;<U>rejected</U>
+<TR><TD><CODE>ABC</CODE><TD>&nbsp;&nbsp;&nbsp;&nbsp;<CODE>CBA</CODE>
+<TR><TD><CODE>AAA</CODE><TD>&nbsp;&nbsp;&nbsp;&nbsp;<CODE>BBB</CODE>
+<TR><TD><CODE>ABCABCABC</CODE><TD>&nbsp;&nbsp;&nbsp;&nbsp;<CODE>BCABCABC</CODE>
+<TR><TD><CODE>A</CODE><TD>&nbsp;&nbsp;&nbsp;&nbsp;<CODE>BBBBBBB</CODE>
+<TR><TD><CODE>ACCCCCCCCC</CODE><TD>&nbsp;&nbsp;&nbsp;&nbsp;<CODE>CAAAAAAAAA</CODE>
+</TABLE>
+
+<P>You might guess, from these examples, that the rule is
+&quot;The string must begin with <CODE>A</CODE>.&quot;  Once you've made a guess you can
+test it out by trying more examples.
+
+<P>The program to play the game is called <CODE>game</CODE>.  It takes one input,
+a number from 1 to 10.  I've provided ten different rules.  Rules 1 to 3
+should be pretty easy to guess; rules 8 to 10 should be nearly impossible.
+(Don't feel too frustrated if you don't get them.)
+
+<P>A string can be any length, including length zero (the empty string).  Each
+time you type a letter the program lets you know whether the string you've
+typed so far obeys the rule.  The program indicates whether the string is
+accepted or rejected by displaying the word <CODE>accept</CODE> or <CODE>reject</CODE> on
+the screen.  In particular, as soon
+as you start <CODE>game</CODE> the program will tell you whether or not the empty
+string is accepted by this rule.  If you type the string <CODE>ABC</CODE> you'll
+really be testing three strings: <CODE>A</CODE>, <CODE>AB</CODE>, and <CODE>ABC</CODE>.  You
+should type one letter at a time to make sure the program has a chance to
+respond to it before going on to the next letter.  To start over again with
+a different string, press the Return key.
+
+<P>You should stop reading now and try the game.  In the following paragraphs
+I'm going to talk about some of the answers, so this is your last
+chance.  After you've figured out at least some of the rules, come
+back to the book.
+
+<P><H2>Finite-State Machines</H2>
+
+<P>The point of studying this game is that we're going to look at a way to design
+a special-purpose abstract computer that understands one particular
+rule.  We can then ask questions about how much information the computer
+needs to handle the job.
+
+<P>You've seen the word <EM>state</EM> before in connection with the Logo
+turtle.  Its state includes its position and its heading.  So one turtle
+state might be &quot;position <CODE>[17 82]</CODE>, heading <CODE>90</CODE>.&quot; In principle,
+the turtle has an <EM>infinite</EM> number of possible states, because its
+position and heading don't have to be integers.  Its position might be <CODE>
+[14.142 14.142]</CODE>, for instance.
+
+<P>Anything that holds information can be in different states.  As another
+example, an on-off light switch has two states.  Some lamps have four states:
+off, low, medium, and high.  A computer, too, has a certain number of states.
+The state of a computer includes all the information in its memory at some
+particular time.
+
+<P>A machine that has only a limited number of states, like the example of the
+light switch, is called a <EM>finite-state machine.</EM>  For almost all of
+this chapter we'll be dealing with finite-state machines.  You might think
+that that imposes a very severe limit on the kinds of computations we can
+do.  But note that in the game I asked you to play, a rule can accept an
+infinite number of possible strings and reject an infinite number of
+others.  The accepted or rejected strings can be of any length.  (Some rules
+restrict the length of a string, but others allow any length at all.)  In
+some sense, a finite-state machine can still perform infinitely varied
+computations.
+
+<P>Consider the third game as an example.  The rule is &quot;Accept
+any string that starts with <CODE>AB</CODE>.&quot;  Here is a picture of a finite-state
+machine that implements that rule:
+
+<P><CENTER><IMG SRC="https://people.eecs.berkeley.edu/~bh/v3ch1/fsm3.gif" ALT="figure: fsm3"></CENTER>
+
+<P>Each numbered circle represents a state.  This machine has three
+states.  The <CODE>start</CODE> arrow indicates that the machine starts out in state
+1.  State 3 is shown with a <EM>double</EM> circle to indicate that it is an
+<EM>accepting</EM> state.  In other words, when the machine is in state 3 the
+screen says <CODE>accept</CODE>.  The other two states are not
+accepting states.
+Every time you type a character the machine switches from one state to
+another.  The arrow from state 1 to state 2 has an <CODE>A</CODE> next to its
+tail.  This indicates that when the machine is in state 1, an input of <CODE>
+A</CODE> switches it to state 2.  (The arrow from state 3 to itself has the
+three letters <CODE>ABC</CODE> at its tail.  This is a shorthand notation for
+three separate arrows with heads and tails in the same place, one for each
+letter.)
+
+<P>This picture is actually incomplete.  For a full description of the machine
+we have to indicate what happens on any input in any state.  In other words,
+each circle should have <EM>three</EM> arrows coming out from it, one each
+for <CODE>A</CODE>, <CODE>B</CODE>, and <CODE>C</CODE>.  I've chosen to adopt the convention that
+every machine has an unmarked state called <CODE>reject</CODE>.  Any missing arrow
+goes to that state; once the machine is in the reject state it stays
+there forever.  Here, then, is the complete diagram of the machine for game
+3:
+
+<P><CENTER><IMG SRC="fsm3-reject.gif" ALT="figure: fsm3-reject"></CENTER>
+
+<P>From now on I won't draw the <CODE>reject</CODE> state, but you should
+remember that it's really part of the machine description.  So this machine
+requires four states, not three.
+
+<P>If the first input letter isn't <CODE>A</CODE>, the machine goes to the <CODE>reject</CODE>
+state.  If the first letter is <CODE>A</CODE>, the machine goes to state 2.  Then,
+if the second letter is <CODE>B</CODE>, the machine ends up in state 3 and accepts
+the string <CODE>AB</CODE>.  This is the shortest acceptable string.
+
+<P>Each of the three arrows from state 3 loops right back into state
+3 itself.  (Remember, although only one arrow appears in the picture,
+it is labeled with three letters, so officially it represents three
+arrows.)  This means that once the machine is in state 3 it stays
+there no matter what inputs it gets.  Any string that starts <CODE>AB</CODE> is
+acceptable.
+
+<P>Here is a machine for game number 2:
+
+<P><CENTER><IMG SRC="fsm2.gif" ALT="figure: fsm2"></CENTER>
+
+<P>In this machine the <EM>start state</EM> is also an <EM>accepting
+state.</EM>  (Every machine has exactly one start state, but it may have any
+number of accepting states.)  This machine never gets into the <CODE>reject</CODE>
+state.  That doesn't mean it doesn't reject any strings; all odd-length
+strings are rejected in state 2.  But a rejected string can redeem itself by
+adding another input character, so state 2 allows a return to the accepting
+state 1.
+
+<P>Here is a machine for game number 5.  (Notice that I'm saying &quot;a
+machine&quot; and not &quot;the machine&quot;; it is always possible to design
+other machines that would follow the same rule.)
+
+<P><CENTER><IMG SRC="fsm5.gif" ALT="figure: fsm5"></CENTER>
+
+<P>You probably had more trouble discovering rule 5 than rule
+2, and it takes longer to say the rule in English words.  But the
+<EM>machines</EM> for the two rules are almost identical.  (Remember,
+though, that the rule-5 machine really has a third state, the <CODE>reject</CODE>
+state, which is not shown in the diagram.)
+
+<P>Here are machines for rules 7 and 9.  With these machines as hints,
+can you figure out the rules?  Go back to the <CODE>game</CODE> program to test
+your hypotheses.
+
+<P><CENTER><IMG SRC="fsm79.gif" ALT="figure: fsm79"></CENTER>
+
+<P>You should also get some practice translating in the other direction, from
+English rules to machine diagrams.  Here are a couple to work on:  Rule 4 is
+&quot;To be accepted a string must be composed of doubled letters (<CODE>AA</CODE>,
+<CODE>BB</CODE>, and <CODE>CC</CODE>) strung together.&quot; Rule 8 is &quot;To be accepted a
+string must contain an even number of <CODE>A</CODE>s.&quot;
+
+<P><H2>Nondeterministic Machines</H2>
+
+
+<P>Here is rule 6: &quot;To be accepted a string must begin with <CODE>A</CODE> and end
+with <CODE>C</CODE>.&quot; Strings accepted by this rule include <CODE>AC</CODE> (the shortest
+possible), <CODE>ABC</CODE>, <CODE>AACC</CODE>, <CODE>ACAC</CODE>, <CODE>ABCABC</CODE>, and so on.
+Between the initial <CODE>A</CODE> and the final <CODE>C</CODE> an accepted string can
+have any combination of <CODE>A</CODE>s, <CODE>B</CODE>s, and <CODE>C</CODE>s.  It's natural to
+think of the string as having three parts: a fixed beginning, a variable
+middle, and a fixed end.  The three parts of the input strings can be
+represented conveniently with three states in the machine, like this:
+
+<P><CENTER><IMG SRC="fsm6nd.gif" ALT="figure: fsm6nd"></CENTER>
+
+<P>The machine starts in state 1.  To be accepted a string must start
+with <CODE>A</CODE>.  Therefore, an <CODE>A</CODE> arrow leads from state 1 to state 2.  Any
+other input at state 1 leads to the <CODE>reject</CODE> state.
+
+<P>Once the machine is in state 2 it is ready for the middle part of
+the string.  In this middle part any combination of letters is allowed.
+Therefore, there are three arrows from state 2 to itself, one for
+every possible letter.
+
+<P>Finally, a <CODE>C</CODE> arrow leads from state 2 to state 3, signaling the end
+of an acceptable string.  A string must end with <CODE>C</CODE> to be accepted.
+
+<P>There is a problem with this machine:  There are <EM>two</EM> <CODE>C</CODE> arrows
+leading out from state 2.  One is a loop back into state 2; the other
+goes on to state 3.  This situation reflects the fact that <CODE>C</CODE> serves
+two different functions in this rule: <CODE>C</CODE> is an optional part of the
+middle section of the string, and it's also the required final input
+in the string.
+
+<P>A machine with two arrows from the same state for the same input is
+called a <EM>nondeterministic</EM> machine.  Here is how such a machine
+could work:  Whenever there are two choices for the machine's
+current state and input, the machine clones itself.  One of the copies
+follows each arrow.  From then on, if <EM>either</EM> machine is in an
+accepting state the string is accepted.
+
+<P>Nondeterministic finite-state machines are more complicated
+than deterministic ones.  Does the added complexity &quot;buy&quot; any added
+power?  In other words, can a nondeterministic machine solve problems
+that a deterministic machine can't?  It turns out that the answer
+to this question is no.  Deterministic machines are just as powerful
+as nondeterministic ones.  This is an important theorem in automata
+theory.  I'm not going to prove it formally in this book, but to illustrate
+the theorem, here is a deterministic machine that carries out game
+6:
+
+<P><CENTER><IMG SRC="https://people.eecs.berkeley.edu/~bh/v3ch1/fsm6d.gif" ALT="figure: fsm6d"></CENTER>
+
+<P>This machine is similar to the nondeterministic version.  It has the
+same number of states and some of the connections are identical.
+State 3 is more complicated, though.  Also, in this machine, it is
+no longer the case that each state of the machine corresponds exactly
+to one of three parts of the input string.  Specifically, when the machine is
+in state 3 the string may or may not be finished.
+
+<P><H2>Representing Machines as Logo Lists</H2>
+
+<P>The <CODE>game</CODE> program uses finite-state machines to represent the rules
+by which it accepts or rejects strings.  (The machines must be deterministic
+for the program to work.)  Logo programs can't read circles and arrows,
+so a machine is represented as a list.  What information is actually
+contained in an FSM diagram?  The diagram shows that there are a certain
+number of states (the circles), that there are certain transitions from one
+state to another (the arrows), that one particular state is the start state
+(the start arrow), and that certain states are accepting ones (the double
+circles).  As in any programming project, I could have chosen many different
+ways to represent that information in the program.
+
+<P>In the particular representation I chose, the list form of a machine
+has three members.  The first member is the number of the start state.
+The second member is a list of arrows; each arrow is itself a list,
+as I'll explain in a moment.  The third member of a machine list is
+a list of the accepting states of the machine.  For example, here
+is the machine for game 3 again, in both forms:
+
+<P><CENTER><IMG SRC="https://people.eecs.berkeley.edu/~bh/v3ch1/fsm3.gif" ALT="figure: fsm3"></CENTER>
+<PRE>[1 [[1 A 2] [2 B 3] [3 ABC 3]] [3]]
+</PRE>
+
+<P>The number <CODE>1</CODE> is the start state; the list <CODE>[3]</CODE> is the
+list of accepting states.  (This machine happens to have only one accepting
+state.)  Everything else is the list of arrows.  Each arrow is also a list
+with three members: the initial state (the tail of the arrow), the input
+letter or letters, and the final state (the head of the arrow).  The first arrow in
+this machine is
+
+<P><PRE>[1 A 2]
+</PRE>
+
+<P>This is the arrow from state 1 to state 2 associated with
+the input <CODE>A</CODE>.
+
+<P>The list <CODE>[3 ABC 3]</CODE> in this machine represents three arrows, using
+the same shorthand as in the circle-and-arrow diagrams.  I could equally
+well have represented these arrows separately:
+
+<P><PRE>[1 [[1 A 2] [2 B 3] <U>[3 A 3] [3 B 3] [3 C 3]</U>] [3]]
+</PRE>
+
+<P>As in the circle-and-arrow diagrams, I haven't explicitly represented the
+transitions to the <CODE>reject</CODE> state in these lists.  The program is
+written so that if it doesn't find a transition for the current state and
+input in the list of transitions, it goes into state number &minus;1, its
+representation for the <CODE>reject</CODE> state.
+
+<P>Here are some more machine lists:
+
+<P><PRE>Game 2:  [1 [[1 ABC 2] [2 ABC 1]] [1]]
+Game 7:  [1 [[1 AB 1] [1 C 2] [2 C 1]] [1]]
+Game 9:  [1 [[1 AB 1] [1 C 2] [2 A 3] [2 B 1] [3 A 1]] [1]]
+</PRE>
+
+<P>At this point you should stop and play with the program.  Make up
+your own rules.  The procedure <CODE>fsm</CODE> takes a machine list as input
+and accepts strings based on that machine.  (<CODE>Game</CODE> uses <CODE>fsm</CODE>
+with particular
+machines as inputs.)  Try out your new rules to make sure you've designed
+the machines correctly.  Then get a friend to play with your rules.
+If both of you are reading this book together you can have a competition.
+(It's easy to design rules that are impossible to guess because there
+are too many details.  If you have a competition you should limit
+yourselves to three states per machine.)
+
+<P>You might be interested in reading through the
+<A HREF="v3ch1.html#fsm"><CODE>fsm</CODE></A> program, which
+simulates a finite-state machine when given the machine's description
+as its input.  It's a pretty simple program.  If you think of a machine's
+state diagram as a kind of &quot;wiring diagram&quot; that might be used
+in building a real version of that particular machine, this Logo program
+is a kind of <EM>universal</EM> finite-state machine implementation.
+
+<P><H2>Text Editors: a Use for Acceptors</H2>
+
+<P>It may seem to you that accepting or rejecting strings isn't much
+like what you usually do with computers.  You may wonder how this
+mathematical model is related to real computer programming.  There
+are two answers to this question.  One is that it's possible to design
+finite-state machines that have more versatile outputs than simply
+yes or no.  I'll give an example shortly.  But the other answer is
+that there are real situations in which accepting or rejecting a string
+of symbols does come up in practical computation.
+
+<P>One example is in the implementation of programming languages.  When
+you say that
+
+<P><PRE>print 2+2
+</PRE>
+
+<P>is a legal Logo instruction but
+
+<P><PRE>print 2+
+</PRE>
+
+<P>is illegal, you're doing a more complicated version of what
+a finite-state acceptor does.
+
+<P>The <EM>search</EM> command in a good text editor uses
+finite-state machines.  Most text editors have a command that allows
+you to look through a file for a particular string of characters.  Fancier
+editors allow searching not just for one particular string, but for any
+string that follows a rule the user can provide.  The editor finds a string that
+matches the rule using a finite-state machine.  Of course, people who use
+editors don't have to specify their search rules in the <EM>form</EM> of a
+finite-state machine!  The editing program accepts search rules in a simpler
+form and translates them into FSM form.  Here is an example, the notation
+used by <EM>ed,</EM> a standard editor in the Unix operating system.
+
+<P>A string like
+
+<P><PRE>spaghetti
+</PRE>
+
+<P>just matches an identical string in the file you're editing.  A
+slightly more interesting case is
+
+<P><PRE>[Ss]paghetti
+</PRE>
+
+<P>which matches either &quot;Spaghetti&quot; or &quot;spaghetti&quot;
+(with a capital or lower case &quot;s&quot;).  The square brackets indicate that
+<EM>any</EM> of the letters inside the brackets will be accepted.
+In the expression
+
+<P><PRE>[Ss]paghet*i
+</PRE>
+
+<P>the asterisk matches <EM>any number</EM> (including zero) of the
+letter before it (in this case, the letter <CODE>t</CODE>).  This example
+would match any of these:
+
+<P><PRE>Spaghei
+Spaghettttti
+spaghetti
+spagheti
+</PRE>
+
+<P>You might use this in a search command if you're a bad speller!
+The bracket and asterisk can be combined;
+
+<P><PRE>C[AD]*R
+</PRE>
+
+<P>will match any of
+
+<P><PRE>CAR
+CDR
+CADDR
+CR
+</PRE>
+
+<P>Or you could use
+
+<P><PRE>M[is]*p*i
+</PRE>
+
+<P>to match the name of a famous river.
+
+<P>Some of the rules from the game I presented earlier can be represented as
+<EM>ed</EM> search strings according to these rules.  In the first game the
+machine accepted any string made up of <CODE>A</CODE>s and <CODE>B</CODE>s.  The
+corresponding <EM>ed</EM> expression is
+
+<P><PRE>[AB]*
+</PRE>
+
+<P>The third game called for strings beginning with the sequence
+<CODE>AB</CODE>, followed by whatever you like.  This can be represented as
+
+<P><PRE>AB[ABC]*
+</PRE>
+
+<P>Game 10, which I'm sure you didn't solve, accepts any string that
+includes the sequence <CODE>ABCBA</CODE> within it.  In <EM>ed</EM> terms, that's
+
+<P><PRE>[ABC]*ABCBA[ABC]*
+</PRE>
+
+<P>I haven't given you a complete description of the <EM>ed</EM> search rules.
+I included this much only because I want you to see how a &quot;real&quot; program
+uses the idea of finite-state machines.  But in the remaining part of this
+chapter I want to use a different notation based on Logo words and lists.
+
+<P><H2>Regular Expressions</H2>
+
+<P>The notation I'm about to describe allows an acceptance rule, like the rules
+in the <CODE>game</CODE> program or the rules for <EM>ed</EM> searches, to be
+represented in Logo.  The representation of such a rule is called a <EM>
+regular expression.</EM>  I'm going to tell you some rules for what a regular
+expression can look like.  Don't be confused:  Any particular regular
+expression is a rule that accepts strings of letters.  I'm giving you rules
+that accept regular expressions--rules about rules.  As a rough analogy,
+&quot;one player is <CODE>X</CODE> and the other is <CODE>O</CODE>&quot; is a rule about the
+specific game Tic Tac Toe; &quot;each player should have a fair chance to win&quot;
+is a rule about what kinds of game rules are acceptable.
+
+<P> <EM>Alphabet rule.</EM> Any symbol in a machine's
+alphabet is a regular expression.  We represent the symbol as a one-letter
+Logo word.  In our guessing game the alphabet contains three symbols: <CODE>
+A</CODE>, <CODE>B</CODE>, and <CODE>C</CODE>.  So
+
+<P><PRE>B
+</PRE>
+
+<P>is a regular expression.
+
+<P>
+<EM>Concatenation rule.</EM>  A list whose members are regular expressions
+represents those expressions one after another.  For example, since <CODE>A</CODE>
+is a regular expression and <CODE>B</CODE> is a regular expression,
+
+<P><PRE>[A B]
+</PRE>
+
+<P>is a regular expression representing the string <CODE>AB</CODE>.  (Notice
+that the Logo word <CODE>AB</CODE> does <EM>not</EM> represent that string; the
+alphabet rule requires that each letter be represented as a separate word.)
+
+<P>
+<EM>Alternatives rule.</EM>  A list whose first member is the word <CODE>or</CODE> and
+whose remaining members are regular expressions represents any string that
+matches <EM>any</EM> of those expressions.  For example,
+
+<P><PRE>[OR [A A] B]
+</PRE>
+
+<P>matches either the sequence <CODE>AA</CODE> or the single symbol <CODE>B</CODE>.
+As a convenience, a Logo word containing more than one letter (other
+than the word <CODE>or</CODE>) is taken as an abbreviation for the <CODE>or</CODE>ing
+of the individual letters.  For example, <CODE>ABC</CODE> is equivalent to
+<CODE>[OR A B C]</CODE>.
+
+<P>
+<EM>Repetition rule.</EM>  A list containing exactly two members, in which the
+first is the asterisk (<CODE>*</CODE>) symbol and the second is a regular
+expression, represents a string containing any number (including zero) of
+substrings that match the regular expression.  So
+
+<P><PRE>[* [OR [A A] B]]
+</PRE>
+
+<P>matches any of these:
+
+<P><TABLE>
+<TR><TD><CODE>B</CODE>
+<TR><TD><CODE>BB</CODE>
+<TR><TD><CODE>BAAB</CODE>
+<TR><TD><CODE>AAAAAA</CODE>
+<TR><TD><CODE>AABAA</CODE>
+<TR><TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(the empty string)
+<TR><TD><CODE>AABBBBBAA</CODE>
+</TABLE>
+
+<P>The number of consecutive <CODE>A</CODE>s must be even for a string of
+<CODE>A</CODE>s and <CODE>B</CODE>s to match this expression.
+
+<P>These four rules constitute the definition of a regular expression.
+It's a <EM>recursive definition.</EM>  Just as the effect of a recursive
+Logo procedure is defined in terms of a simpler case of the same procedure,
+a complex regular expression is defined in terms of simpler ones.
+
+<P>Here are the ten game rules from the beginning of this chapter in
+the form of regular expressions:
+
+<P><P>
+<TABLE><TR><TH align="right">1.<TD>&nbsp;&nbsp;&nbsp;&nbsp;<CODE>[* AB]</CODE>
+<TR><TH align="right">2.<TD>&nbsp;&nbsp;&nbsp;&nbsp;<CODE>[* [ABC ABC]]</CODE>
+<TR><TH align="right">3.<TD>&nbsp;&nbsp;&nbsp;&nbsp;<CODE>[A B [* ABC]]</CODE>
+<TR><TH align="right">4.<TD>&nbsp;&nbsp;&nbsp;&nbsp;<CODE>[* [OR [A A] [B B] [C C]]]</CODE>
+<TR><TH align="right">5.<TD>&nbsp;&nbsp;&nbsp;&nbsp;<CODE>[* [ABC B]]</CODE>
+<TR><TH align="right">6.<TD>&nbsp;&nbsp;&nbsp;&nbsp;<CODE>[A [* ABC] C]</CODE>
+<TR><TH align="right">7.<TD>&nbsp;&nbsp;&nbsp;&nbsp;<CODE>[* [OR A B [C C]]]</CODE>
+<TR><TH align="right">8.<TD>&nbsp;&nbsp;&nbsp;&nbsp;<CODE>[[* BC] [* [A [* BC] A [* BC]]]]</CODE>
+<TR><TH align="right">9.<TD>&nbsp;&nbsp;&nbsp;&nbsp;<CODE>[[* AB] [* [C [OR B [A A]]] [* AB]]]</CODE>
+<TR><TH align="right">10.<TD>&nbsp;&nbsp;&nbsp;&nbsp;<CODE>[[* ABC] A B C B A [* ABC]]</CODE>
+</TABLE>
+
+<P><TD>&nbsp;&nbsp;&nbsp;&nbsp;<P>
+
+<P>You should go through these examples carefully, making sure
+you understand how the regular expression represents the same idea
+as the English description or the machine diagram you saw earlier.
+
+<P><H2>Rules That Aren't Regular</H2>
+
+<P>You may be thinking that <EM>any</EM> rule for accepting or rejecting
+strings of symbols can be represented as a regular expression.  But
+that's not so.  For example, consider the rules for recognizing ordinary
+arithmetic expressions:
+
+<P><TABLE><TR><TH align="left"><U>accepted</U>
+<TH align="left">&nbsp;&nbsp;&nbsp;&nbsp;<U>rejected</U>
+<TR><TD><CODE>2+3</CODE><TD>&nbsp;&nbsp;&nbsp;&nbsp;<CODE>23+</CODE>
+<TR><TD><CODE>2*(3+4)</CODE><TD>&nbsp;&nbsp;&nbsp;&nbsp;<CODE>2*)3+4(</CODE>
+<TR><TD><CODE>-5</CODE><TD>&nbsp;&nbsp;&nbsp;&nbsp;<CODE>/6</CODE>
+</TABLE>
+
+<P>Think for a moment just about the matter of
+balancing parentheses.
+Sometimes you have parentheses within parentheses, as in
+
+<P><PRE>((3+4)/(5+6))
+</PRE>
+
+<P>How would you represent this part of the arithmetic expression
+rule in the form of a regular expression?  You can't just say something like
+
+<P><PRE>[[* (] something-or-other [* )]]
+</PRE>
+
+<P>to mean &quot;any number of open parentheses, something, then
+any number of close parentheses.&quot;  That would allow strings like
+
+<P><PRE>(((7)))))
+</PRE>
+
+<P>But this string should be rejected because it has too many close
+parentheses.  You're not allowed to use a close parenthesis unless you've
+already used a matching open parenthesis.  You can have any number of nested
+parentheses you want as long as they're balanced.
+
+<P>It is possible to invent other kinds of formal notation, more powerful than
+regular expressions, that will allow us to give the rules for well-formed
+arithmetic expressions.  In this section I'll introduce briefly a formal
+notation called <EM>production rules</EM> that's powerful enough to describe
+arithmetic expressions.  For now, in this chapter, I don't want to discuss
+production rules in great detail; my only reason for introducing them at
+this point is to give you a sense of how regular expressions fit into a
+larger universe of possible formal systems.  In the following sections I'll
+have more to say about regular expressions and finite-state machines.  But
+we'll return to production rules in Chapters 5 and 6, in which we'll need
+formal notations with which to discuss more interesting languages than the
+<CODE>A</CODE>-<CODE>B</CODE>-<CODE>C</CODE> language of this chapter.  (In Chapter 5 we'll be
+talking about Pascal; in Chapter 6 we'll take on English.)
+
+<P>The key ingredient that's missing from regular expression notation is a way
+to <EM>name</EM> a kind of sub-expression so that the name can be used in
+defining more complex expressions.  In particular, a sub-expression name can
+be used in its own definition to allow a <EM>recursive</EM> definition of the
+rule.
+
+<P>A production rule has the form
+
+<P><PRE>name      :  expansion
+</PRE>
+
+<P>Each rule is a definition of the name on the left in terms of
+smaller units, analogous to the definition of a Logo procedure in terms
+of subprocedures.  The expansion part of the rule is a string of symbols
+including both members of the &quot;alphabet&quot; of the system (like the alphabet
+that underlies a regular expression language) and names defined by
+production rules.
+
+<P>As an example, here is a set of production rules that defines the language of
+arithmetic expressions.  These rules take into account the &quot;order of
+operations&quot; for arithmetic that you learned in elementary school:
+multiplication before addition.  An expression like
+
+<P><PRE>2/3+1/6
+</PRE>
+
+<P>is ordinarily interpreted as the sum of two <EM>terms,</EM> namely
+two thirds and one sixth.  An expression can be a single term, a sum of
+terms, or a difference of terms.  Here's how that idea is expressed in a set
+of production rules; I'll discuss the notation in more detail in a moment.
+
+<P><CENTER><IMG SRC="xx1.gif"></CENTER>
+
+<P>The vertical bars separate alternatives.  The first rule, the one
+that defines <CODE>expr</CODE>, contains three alternatives.  First, an expression
+can be just a single term.  Second, an expression can be a smaller
+expression plus a term.  Third, an expression can be a smaller expression
+minus a term.  The symbols inside boxes are the members of the alphabet of
+the arithmetic expression language.  (I've put them in boxes to make it
+easier not to confuse them with the punctuation characters--the colons and
+vertical bars--that are part of the production rule notation itself.)
+
+<P>Do you see how parentheses fit in?  If a string like <CODE>4+5</CODE> is an
+expression, then <CODE>(4+5)</CODE> is a factor, so <CODE>3*(4+5)</CODE> is a term,
+and so on.  Since a factor is a kind of term, and a term is a kind of
+expression, the factor <CODE>(4+5)</CODE> can be considered an expression, and
+so it too can be put inside parentheses.  So <CODE>((4+5))</CODE> is also
+acceptable as a factor.
+
+<P><H2>Regular Expressions and Finite-State Machines</H2>
+
+<P>I've hinted at something that I haven't actually made explicit:  Regular
+expressions are equivalent to finite-state machines.  In other words,
+if you can express a rule as a regular expression, you can design
+a finite-state machine that carries out the rule.  If you can't write
+a regular expression for the rule, you can't design a finite-state
+machine either.
+
+<P>You may be thinking, &quot;so what?&quot;  I've introduced two different formal
+notations, finite-state machines and regular expressions, and now I'm
+telling you that the two are equivalent.  So why didn't I just pick one in
+the first place and forget about the other?  I have a general answer and a
+specific answer to these questions.
+
+<P>The general answer is that comparing different formal systems is what
+automata theory is all about.  By the end of this book you'll have been
+introduced to half a dozen or so different formal systems.  Some are more
+powerful than others.  The bare assertion that one formal system is
+equivalent to another, or more powerful than another, isn't very interesting;
+but if we can understand the <EM>reasons</EM> behind those assertions then
+we may be able to put the knowledge to work in practical situations.  At the
+very end of this book, in Chapter 6, we'll talk about a particular formal
+system that's often used in artificial intelligence programs to recognize
+English sentences.  By then you should know enough about formal systems to
+be able to understand why that particular one is a good choice.
+
+<P>The specific answer is that finite-state machines and regular expressions
+are <EM>different</EM> from each other in an interesting way.  A finite-state
+machine is an <EM>algorithm,</EM> a sequence of steps, or a procedure that can
+be followed to test whether some string matches a given rule.  It says,
+&quot;start here, then if this happens do this, then...&quot; just like a procedure
+in Logo or most other programming languages.  (But we've seen that a
+finite-state machine is like a procedure written in a restricted programming
+language that isn't as flexible as Logo.)  A regular expression, though, is
+<EM>not</EM> a sequence of steps.  It's more like a description of the <EM>
+result</EM> that we want, leaving open the precise recipe for how to get there.
+People often pose problems in a similar way.  They call the plumber and say,
+&quot;the drain in my bathtub is backing up.&quot;  Part of the plumber's expertise is
+to be able to translate that <EM>declarative</EM> problem statement into a
+<EM>procedural</EM> form, a sequence of steps needed to clear up the problem.
+An early stumbling block in artificial intelligence research was the seeming
+gulf between the procedural knowledge embodied in a computer program and the
+declarative knowledge needed for human-like behavior.  Recently people have
+invented <EM>declarative programming languages</EM> (the best known
+is Prolog, but any commercial spreadsheet program is also
+in this category) that
+allow the user to state a problem in declarative form.  The programming
+language interpreter then automatically translates this problem statement
+into a sequence of steps for the computer to perform.
+
+<P>Writing a Prolog interpreter raises many issues beyond the scope of this
+book.  But we can take a smaller step in the realm of translation from
+a declarative notation to a procedural one.  I've written a Logo program,
+listed at the end of the chapter, that translates from a regular
+expression to an equivalent finite-state machine.  Its top-level procedure,
+<CODE>machine</CODE>, takes a regular expression as input and outputs a machine
+list in the format I showed earlier.
+
+<P><H2>How to Translate</H2>
+
+<P>The general claim that regular expressions are equivalent in power
+to finite-state machines is called Kleene's Theorem, named after the
+mathematician Stephen C. Kleene, its discoverer.  You can find a proof
+of this theorem in any textbook on automata theory.  I'm not going
+to give a proof here, but I'll indicate how the translation is done
+in my program.  The same kinds of ideas are used in the proof.
+
+<P>Remember that there are four parts to the definition of a regular expression.
+The alphabet rule provides the fundamental building blocks; the
+concatenation, alternatives, and repetition rules build large regular
+expressions recursively out of smaller ones.  The translation process
+follows the same pattern:  We start with a procedure to build a trivial
+two-state machine that only accepts a single letter, then we add three
+rules for combining smaller machines into a large machine.  In the following
+paragraphs I'll show how each rule is reflected in the
+<A HREF="v3ch1.html#machine"><CODE>machine</CODE></A> program.
+
+<P>This construction process often produces machines with more states than
+necessary.  The <CODE>machine</CODE> program eliminates redundant states as its
+final step.
+
+<P>The alphabet rule says that any member of the machine's alphabet is
+a regular expression.  In the program, a symbol can be any one-letter word other
+than <CODE>*</CODE>.  The symbol <CODE>X</CODE> is translated into the machine
+
+<P><PRE>[1 [[1 X 2]] [2]]
+</PRE>
+
+<P>(You'll see that the program works by combining little machines
+into bigger ones.  Every time the program has to invent a new machine
+state it uses the next free number.  So the state numbers might not
+be 1 and 2 in a real example.)  The procedure
+<A HREF="v3ch1.html#ndletter"><CODE>ndletter</CODE></A> handles this
+rule.
+
+<P>Next comes the <EM>concatenation rule.</EM>  The regular expression
+
+<P><PRE>[A B]
+</PRE>
+
+<P>matches a string with two parts; the
+first substring matches the <CODE>A</CODE> and the second matches the <CODE>
+B</CODE>.  In this simple example each &quot;substring&quot; matches only a single
+letter.  In a more complicated concatenation like
+
+<P><PRE>[[OR A C] [* B]]
+</PRE>
+
+<P>there are different choices for each substring.  For example, that
+regular expression is matched by the string
+
+<P><PRE>CBBB
+</PRE>
+
+<P>in which the letter <CODE>C</CODE> matches the first part of the
+expression and the substring <CODE>BBB</CODE> matches the second part.
+
+<P>To translate a regular expression of this kind (a concatenation) into a
+finite-state machine, we begin by recursively translating the subexpressions
+into smaller machines.  Then we have to &quot;splice&quot; the two machines together.
+Procedure <A HREF="v3ch1.html#ndconcat"><CODE>ndconcat</CODE></A> does this splicing.
+
+<P>We'll begin with the simplest possible example.  Suppose we want to
+translate the regular expression
+
+<P><PRE>[A B]
+</PRE>
+
+<P>We have already translated the two symbols <CODE>A</CODE> and <CODE>B</CODE> into
+machines:
+
+<P><CENTER><IMG SRC="concat-before.gif" ALT="figure: concat-before"></CENTER>
+
+<P>The combined machine must start at the start state of the first
+component machine, state 1.  The combined machine should be in an accepting
+state when <EM>both</EM> component machines have been satisfied; in other
+words, the accepting states of the combined machine should be those of the
+<EM>second</EM> component machine.  In this case that means only state 4.
+
+<P>To splice the component machines together we must add transitions (arrows)
+between them.  Specifically, whenever the first component machine gets into
+an accepting state, the combined machine should follow the same transitions
+that apply to the start state of the second component machine.  In this
+case, when the combined machine gets into state 2 (the accepting state of
+the first component machine) it should follow the same transitions that
+apply to state 3 (the start state of the second machine).  There is only one
+such transition, a <CODE>B</CODE> arrow into state 4.  That means we must add the
+arrow
+
+<P><PRE>[2 B 4]
+</PRE>
+
+<P>to the combined machine.
+
+<P><CENTER><IMG SRC="concat-after.gif" ALT="figure: concat-after"></CENTER>
+
+<P>State 3, although it is still in the machine, is now useless.
+There is no way for the machine to get into state 3.  Later
+in the translation process another procedure removes
+such &quot;orphaned&quot; states from the machine.
+
+<P>As a slightly more complicated example, consider the translation of the
+regular expression
+
+<P><PRE>[[OR A C] [* B]]
+</PRE>
+
+<P>We start by supposing that we've already translated the two
+subexpressions separately:
+
+<P><CENTER><IMG SRC="concat2-before.gif" ALT="figure: concat2-before"></CENTER>
+
+<P>(We haven't yet discussed the alternatives rule or the repetition
+rule, so I haven't yet explained how these subexpressions are translated.
+For now, please just take on faith that this picture is correct.  We'll get
+to those other rules shortly.)
+
+<P>The start state of the combined machine is the start state of the first
+component, state 1.  At every accepting state of the first machine we must
+duplicate the transitions from the start state of the second machine.  In
+this example the start state of the second machine has only the transition
+
+<P><PRE>[4 B 5]
+</PRE>
+
+<P>but there are two accepting states in the first machine, so we
+must add two new arrows:
+
+<P><PRE>[2 B 5]    [3 B 5]
+</PRE>
+
+<P>A final detail is that in this example the start state of the
+second component machine, state 4, is an accepting state.  That means that
+the second substring can be empty.  Therefore the accepting states of the
+first component machine should also be accepting states of the combined
+machine.  Here is the result:
+
+<P><CENTER><IMG SRC="concat2-after.gif" ALT="figure: concat2-after"></CENTER>
+
+<P>Again, state 4 is now an &quot;orphan&quot; and will be eliminated
+later in the program.
+
+<P>The <EM>alternatives rule</EM> combines two machines in parallel, so to speak,
+rather than in series.  It works by inventing a new state
+that becomes the start state of the combined machine.  Arrows leaving
+from the new state duplicate the arrows from the start states of the
+component machines.  Procedure <A HREF="v3ch1.html#ndor"><CODE>ndor</CODE></A> handles this rule.
+
+<P>As an example, here is the translation process for
+
+<P><PRE>[OR A B]
+</PRE>
+
+<P>(or its abbreviation <CODE>AB</CODE>).  We start with two separate machines:
+
+<P><CENTER><IMG SRC="https://people.eecs.berkeley.edu/~bh/v3ch1/alter-before.gif" ALT="figure: alter-before"></CENTER>
+
+<P>We combine them by inventing a new state 5:
+
+<P><CENTER><IMG SRC="alter-after.gif" ALT="figure: alter-after"></CENTER>
+
+<P>I haven't explained all the details of the construction process.
+For example, should the new state, state 5, be an accepting state?  In this
+example it shouldn't be.  See if you can think of a case where it might be;
+then read the program listing to see the exact algorithm that makes this
+decision.  Again, this construction process may leave unused states for
+later cleanup.
+
+<P>A much more serious problem is that an <CODE>or</CODE> construction is likely to
+produce a nondeterministic machine.  For example, here is the machine
+for
+
+<P><PRE>[OR [A B] [A C]]
+</PRE>
+
+<P><CENTER><IMG SRC="or-nondet.gif" ALT="figure: or-nondet"></CENTER>
+
+<P>Like the unused states, the problem of nondeterminism is
+left for the end of the program, when procedure <CODE>determine</CODE> translates
+the nondeterministic machine into a deterministic one.
+(The concatenation rule can also make nondeterministic machines, although
+it's not as likely.)
+
+<P>The final case to be considered is the <EM>repetition rule.</EM>  This rule
+acts on only one smaller machine, not two machines as in the previous
+two cases.  The rule doesn't require any new states.  It has two effects.
+One is to add the start state to the list of accepting states.  The
+second is to add arrows from the (old) accepting states that mimic
+the arrows from the start state.  (This is exactly like the splicing
+of two machines in the concatenation rule, but in this case we concatenate
+a single machine with itself!)  Procedure <A HREF="v3ch1.html#ndmany"><CODE>ndmany</CODE></A>
+makes this transformation.
+It, too, can result in a nondeterministic machine.
+
+<P>Here is an example of the rule:
+
+<P><CENTER><IMG SRC="repetition.gif" ALT="figure: repetition"></CENTER>
+
+<P>These four rules are combined by <A HREF="v3ch1.html#nondet"><CODE>nondet</CODE></A>,
+a procedure whose input is
+a regular expression and whose output is a (possibly nondeterministic) machine.
+
+<P><PRE>to nondet :regexp
+if and (wordp :regexp) (equalp count :regexp 1) [output ndletter :regexp]
+if wordp :regexp [output ndor reduce &quot;sentence :regexp]
+if equalp first :regexp &quot;or [output ndor butfirst :regexp]
+if equalp first :regexp &quot;* [output ndmany last :regexp]
+output ndconcat :regexp
+end
+</PRE>
+
+<P>The top-level procedure <A HREF="v3ch1.html#machine"><CODE>machine</CODE></A>
+does a little initialization
+and then does its work with the instruction
+
+<P><PRE>output optimize determine nondet :regexp
+</PRE>
+
+<P>That is, first it creates what may be a
+nondeterministic machine,
+then if necessary it translates that into a deterministic one (eliminating
+orphan states in the process), then it gets
+rid of any redundant states that may have been created.
+
+<P><H2>Making the Machine Deterministic</H2>
+
+<P>In the first volume of this series we explored the techniques of depth-first
+and breadth-first tree traversal.  Given a tree structure, these algorithms
+allow us to &quot;visit&quot; every node of the tree once.
+
+<P>A finite state machine can be viewed as a structure almost like a tree.
+The machine's start state corresponds to the root node; the states that
+can be reached by an arrow from a given state are the children of that state.
+But there is one important difference between trees and machines:  In a tree,
+every node (except for the root node) has exactly one parent.  The tree
+search algorithms depend on that fact to ensure that each node is visited
+only once.  In a machine, arrows from several different states can lead to
+the same state, so a state may have several &quot;parents.&quot;  The technical name
+for an arbitrary collection of nodes with connections among them is a
+<EM>graph.</EM>  If the connections are one-way, as in the finite
+state machine diagrams, it's called a <EM>directed graph.</EM>
+
+<P>Searching a graph is just like searching a tree, except that we have to
+keep track of which nodes we've already visited, to avoid examining the
+same node twice.  Procedure <A HREF="v3ch1.html#determine"><CODE>determine</CODE></A>
+creates a list named <CODE>states</CODE>, initially
+empty, into which each state number is added as the
+program examines that state.  The depth first traversal of the machine
+is carried out by procedure <A HREF="v3ch1.html#nd.traverse"><CODE>nd.traverse</CODE></A>;
+although this procedure looks different from the
+<A HREF="../v1ch14/v1ch14.html#depth.first"><CODE>depth.first</CODE></A>
+procedure in Volume 1, it
+uses the same basic algorithm.  Given a state as input, it processes
+that state and invokes itself recursively for all of the children of
+that state--the states reachable by arrows from the input state.  Unlike
+<CODE>depth.first</CODE>, though, <CODE>nd.traverse</CODE> is an operation.  It
+outputs a new list of moves (arrows) for the deterministic version of
+the machine.
+
+<P>What does it mean to process a state?  <CODE>Nd.traverse</CODE> first checks
+whether this state has already been processed; if so, it outputs an empty
+list, because this state will contribute no new moves to the machine.
+Otherwise, it remembers this state number as having been processed, finds
+all the moves starting from this state, and calls
+<A HREF="v3ch1.html#check.nd"><CODE>check.nd</CODE></A> to look for
+nondeterminism.  <CODE>Check.nd</CODE> takes the first available arrow whose tail
+is at the state we're processing, and looks for all arrows with the same
+tail and with the same letter.<SUP>*</SUP>
+The local variable <CODE>heads</CODE> will contain a list of all the state numbers
+reachable by these arrows.  (The state numbers are sorted into increasing
+order, and duplicates eliminated.  If the machine has two completely
+identical arrows, that doesn't result in nondeterminism.)
+
+<P><SMALL><BLOCKQUOTE><SMALL><SUP>*</SUP>By the way, <CODE>nondet</CODE> always
+creates arrows with only a single letter; if two or more letters lead from
+the same state to the same state, a separate arrow is created for each of
+them.  This makes for a longer machine list, but makes steps like this
+one--looking for two arrows with the same letter--easier.  Once the
+deterministic machine has been created, procedure <CODE>optimize</CODE> will combine
+such arrows into the abbreviated form with
+more than one letter per arrow.</SMALL></BLOCKQUOTE></SMALL>
+
+<P>There are
+three cases for what <CODE>check.nd</CODE> must do.  First, if there is
+only one state number in <CODE>:heads</CODE>, then there is no nondeterminism for
+this letter, and <CODE>check.nd</CODE> includes the arrow from the original
+machine as part of the deterministic machine.  Second, if there is more
+than one state number, <CODE>check.nd</CODE> looks to see if we've already seen
+the same combination of result states.  If so, then we've already created
+a new state equivalent to that combination of old states, and <CODE>check.nd</CODE>
+creates a new arrow pointing to that existing new state.  Finally, the third
+case is that this combination of states is one we haven't seen before.  In
+that case, <CODE>check.nd</CODE> must create a new state, with arrows duplicating
+those from all of the original states.
+
+<P>In other words, if there are arrows
+
+<P><PRE>[[3 B 4] [3 B 7]]
+</PRE>
+
+<P>then <CODE>check.nd</CODE> will invent a new state that is an &quot;alias&quot;
+for &quot;four-and-seven.&quot;  If the same machine also contains arrows
+
+<P><PRE>[[8 C 4] [8 C 7]]
+</PRE>
+
+<P>then <CODE>check.nd</CODE> will use the <EM>same</EM> alias state for this
+pair, not inventing a new one.  The new
+state is given arrows matching those of all its component states (4
+and 7 in this example).  The new state might itself contain a nondeterministic
+branch, but that's okay because the new state will eventually be processed
+as we continue to traverse the machine graph.
+
+<P>You might think that this process could go on forever: that each new
+state <CODE>check.nd</CODE> invents will turn out to include nondeterminism, which
+will require yet another new state to resolve.  Fortunately, that
+doesn't happen; the process does always end eventually.  (In the next
+chapter we'll see what the limit is on the number of necessary states
+for the deterministic machine.)
+
+<P>Because <CODE>determine</CODE> uses a graph traversal algorithm to examine
+the original machine's states, it will never find &quot;orphan&quot; states
+that can't be reached by arrows from some other state.  That's why
+the process of making the machine deterministic also eliminates orphan
+states, with no extra effort.
+
+<P><H2>Eliminating Redundant States</H2>
+
+<P>The machines produced by <CODE>determine</CODE> are runnable, but often ugly;
+they contain many more states than necessary.  Procedure
+<A HREF="v3ch1.html#optimize"><CODE>optimize</CODE></A>
+eliminates many redundancies and also combines arrows with the same
+head and tail but with different letters.
+First it goes through the machine's arrow list,
+creating a list for each state representing the exits from that state:
+
+<P><CENTER><IMG SRC="optimize.gif" ALT="figure: optimize"></CENTER>
+<PRE>   [[* [A B]] C]
+State 1: [[A 2] [C 4]]
+State 2: [[B 3]]
+State 3: [[A 2] [C 4]]
+State 4: []
+</PRE>
+
+<P>In this machine, states 1 and 3 have the same exit list.
+(In these lists, each arrow is represented with only two members; the
+arrow's tail is not included.  That's because states 1 and 3 would <EM>
+not</EM> have identical lists if the tails were included.  State 1's list
+would be
+
+<P><PRE>[[1 A 2] [1 C 4]]
+</PRE>
+
+<P>and state 3's list would have arrows starting with 3.  In the
+program, the two-member form of an arrow is called a <EM>stub.</EM>)
+
+<P>The program must be careful about the order in which it puts stubs
+in each state's list, so it doesn't end up with
+
+<P><PRE>[[C 4] [A 2]]
+</PRE>
+
+<P>for one of the states.  That's why <A HREF="v3ch1.html#stub.add"><CODE>stub.add</CODE></A>
+takes trouble
+to insert each stub in a well-defined position, rather than just adding
+each new stub at the beginning or end of the list.  It's also in
+<CODE>stub.add</CODE> that arrows connecting the same two states but with different
+letters are combined into a single arrow.
+
+<P>Since states 1 and 3 also agree in their acceptingness (namely they aren't
+accepting states), they can be combined into one state.  <CODE>
+Optimize.state</CODE> can replace every reference to state 3 with a reference to
+state 1.
+
+<P><H2>A Finite-State Adder</H2>
+
+
+<P>I promised earlier to show you a use for finite-state machines other
+than accepting or rejecting strings.  In this section I'll fulfill
+that promise by designing a machine to add two numbers.  We'll represent
+the numbers in binary notation, in which each digit represents a power
+of 2 instead of a power of 10.
+
+<P>If you've come across binary numbers before, you can skip this paragraph.
+Just as the ordinary notation for numbers is based on the ten digits 0 to 9,
+binary notation is based on <EM>two</EM> digits, 0 and 1.  In ordinary
+(&quot;decimal&quot;) notation, the amount that each digit contributes to the total
+depends on where it is in the number.  For example, in the number 247, the
+digit 2 contributes two hundred, not just two, because it's in the third
+position counting from the right.  Each digit's contribution is the value of
+the digit itself multiplied by a power of ten:
+<P><CENTER>2&times;10<SUP><SMALL>2</SMALL></SUP>
++ 4&times;10<SUP><SMALL>1</SMALL></SUP>
++ 7&times;10<SUP><SMALL>0</SMALL></SUP></CENTER><P>
+(10<SUP><SMALL>2</SMALL></SUP> is 100; 10<SUP><SMALL>1</SMALL></SUP> is 10; 10<SUP><SMALL>0</SMALL></SUP> is just 1.)  In binary, the
+contribution of each digit is multiplied by a power of <EM>two,</EM> so the
+binary number 10101 represents
+<P><CENTER>1&times;2<SUP><SMALL>4</SMALL></SUP>
++ 0&times;2<SUP><SMALL>3</SMALL></SUP>
++ 1&times;2<SUP><SMALL>2</SMALL></SUP>
++ 0&times;2<SUP><SMALL>1</SMALL></SUP>
++ 1&times;2<SUP><SMALL>0</SMALL></SUP></CENTER><P>
+which is 16+4+1 (2<SUP><SMALL>4</SMALL></SUP>+2<SUP><SMALL>2</SMALL></SUP>+2<SUP><SMALL>0</SMALL></SUP>) or 21.  Computers use binary notation
+because it's easy to build electrical circuits in which each wire is either
+on or off.  In Chapter 2 we'll talk about an example.  Right now I want to
+show something different--not an actual electronic machine but an abstract
+machine based on the ideas we've been using in this chapter.
+
+<P>The machine will add two binary numbers, one digit position at a time, just
+the way you add multi-digit numbers yourself.  When you see a problem like
+<P><CENTER><TABLE><TR><TD align="right">376
+<TR><TD align="right"><U>+572</U></TABLE></CENTER><P>
+you start at the right and say, &quot;6 plus 2 is 8; 7 plus 7 is 14, which is
+4 carry 1; 1 plus 3 plus 5 is 9.&quot;  The finite-state adder works the same
+way except that the digits are always 0 or 1.
+
+<P>The machine will add any numbers, but to explain how it works I want to
+consider a specific example.  Let's say we want to add 52 and 21.  (By the
+way, I didn't pick these numbers because they name card games, but because
+the pattern of digits in their binary forms is convenient for the
+explanation I want to give.)  52 in binary is 110100 (32+16+4) and 21 is
+10101 (16+4+1).  I'm going to write these one above the other, with a couple
+of extra zeros on the left to leave room for a possible carry:
+
+<P><PRE>          0 0 1 1 0 1 0 0
+          0 0 0 1 0 1 0 1
+</PRE>
+
+<P>Remember how a finite-state machine works:  At a given moment it's
+in some <EM>state,</EM> then it reads some <EM>input</EM> symbol and goes to
+another state.  In this problem, since we have two numbers to add, the most
+natural way to think about it would be to give the machine <EM>two</EM> inputs
+at a time.  This idea doesn't quite fit in with the formal definition of a
+finite-state machine, but we can let the machine's &quot;alphabet&quot; consist of
+<EM>pairs</EM> of digits, so something like <CODE>01</CODE> would be a single input.
+(By the way, the word <EM>bit</EM> is commonly used as an abbreviation for
+&quot;binary digit.&quot;)  Just as you added vertical pairs of digits (first 6 and 2,
+then 7 and 7, and so on) in the earlier example, we'll use vertical pairs of
+bits as the inputs to the finite-state adder, starting from the right end.
+So the first input will be 01, then 00, then 11, then 00, then 11 again,
+then 10, and then 00 twice.  From now on, in this section, when you see
+something like 10 you should remember that it is a <EM>single</EM> input to
+the finite-state machine, a single symbol, not two in a row.
+(In the diagram below, an arrow labeled <CODE>01/10</CODE> represents two
+arrows, one for the input <CODE>01</CODE> and one for the input <CODE>10</CODE>.  These
+two arrows will always go to the same state because 0+1=1+0.)
+
+<P>We need to make one change in the notation used in machine diagrams.
+We no longer want to mark each state as accepting (double circle)
+or rejecting (single circle).  Instead, each state produces an <EM>
+output</EM> that can be any arbitrary symbol.  In this machine the outputs
+will be 0 or 1, representing the binary digits of the sum.  Inside
+each state circle, instead of just a state number you'll see something
+like &quot;3/1&quot;; this means that it's state number 3 and that the output
+from that state is 1.
+
+<P>Here is the machine:
+
+<P><CENTER><IMG SRC="fsm-add.gif" ALT="figure: fsm-add"></CENTER>
+
+<P>State 1, the start state, has no output.  When the machine is in start
+state it hasn't seen any digits of the addends yet, so it can't compute
+a digit of the sum.  States 2 and 4 output a zero digit, while states
+3 and 5 output a one.  (Like the inputs, the number that the machine
+outputs is presented with its rightmost bit first.  The machine works
+this way for the same reason that <EM>you</EM> add numbers from right
+to left:  That's the direction in which a &quot;carry&quot; digit moves from
+one column to another.)
+
+<P>Why are there <EM>two</EM> zero-output states and <EM>two</EM> one-output
+states?  The reason is that the machine is in state 4 or 5 when there
+is a carry into the next digit of the sum.
+
+<P>Let's trace through my example.  We start in state 1.  The first input
+symbol is 01, representing a 0 in the rightmost (binary) digit of 52
+and a 1 in the rightmost digit of 21.  The machine enters state 3
+and outputs a 1.
+
+<P>The next input is 00 because both numbers have zero as the second
+digit.  The machine enters state 2 and outputs 0.
+
+<P>The next input is 11.  The machine enters state 4 and outputs 0.  Being in
+state 4 means that there is a carry from this position into the next.
+
+<P>You can finish the example yourself.  The sum should be 01001001,
+or 73.
+
+<P><H2>Counting and Finite-State Machines</H2>
+
+<P>Earlier we saw that you can't write a regular expression for a rule
+that requires balanced parentheses.  Since regular expressions are
+equivalent to finite-state machines, you won't be surprised to learn
+that finite-state machines can't count.
+
+<P>
+Actually, they can count up to a point; it's just that each finite-state
+machine can only count up to a fixed limit.  For example, here is
+a finite-state machine that accepts strings of balanced parentheses
+up to four deep:
+
+<P><CENTER><IMG SRC="https://people.eecs.berkeley.edu/~bh/v3ch1/fourdeep.gif" ALT="figure: fourdeep"></CENTER>
+
+<P>This machine will accept strings like these:
+
+<P><PRE>          ()        (())      ()()
+          (()())    (((())))  (((())))(())
+</PRE>
+
+<P>There is no limit to the <EM>length</EM> of the string this
+machine can handle.  For example, it will accept this:
+
+<P><PRE>          ()()()()()()()()()()()()()()
+</PRE>
+
+<P>But there can be no more than four parentheses open <EM>
+at once</EM>; the machine will reject
+
+<P><PRE>          ((((()))))
+</PRE>
+
+<P>Even this limited counting ability of finite-state machines is of great
+practical value.  Real computers, after all, are finite-state
+machines.  Any real computer has a finite amount of memory, and this
+memory can be in a finite number of states.  But the number is quite
+huge.  If a real computer includes a parenthesis-counting program
+that is limited to, say, 20,000 levels of parentheses, nobody will
+ever notice that the limit isn't infinite.
+
+<P>(The number of states in a real computer may be even larger than you're
+thinking.  Each bit of computer memory isn't a state.  Instead, if
+a computer has <EM>n</EM> bits of memory it has 2<SUP><SMALL>n</SMALL></SUP> states!  For
+example, a computer with three bits of memory can use those bits to
+represent <EM>eight</EM> states:
+
+<P><PRE>0 0 0
+0 0 1
+0 1 0
+0 1 1
+1 0 0
+1 0 1
+1 1 0
+1 1 1
+</PRE>
+
+<P>The number of possible states in a typical large computer
+is greater than the number of atoms in the galaxy.)
+
+<P>In a moment I'm going to talk about a theoretical model of a machine
+with infinite memory.  You might wonder why it pays to study such
+machines, since any real machine has to be limited in memory.  The
+answer has to do with my example about the 20,000 levels of parentheses.
+It is theoretically possible to write a regular expression for such
+strings.  To show you how it's done, here is a regular expression
+for up to three levels:
+
+<P><CENTER><IMG SRC="xx2.gif"></CENTER>
+
+<P>(I've drawn boxes around the actual alphabet-rule symbols just to
+make it a little easier for you to distinguish between the parentheses,
+which are symbols in the input strings, and the brackets, which are part of
+the glue that holds a regular expression together.)
+
+<P>There is no theoretical problem about extending this regular expression
+to allow up to 20,000 parentheses.  But a machine based on this technique
+would be very large and complicated.  Instead, it makes more sense to
+<EM>pretend</EM> that the computer has an infinite amount of memory available
+and use a formal system (like the production rules I mentioned briefly)
+that depends on an infinite memory.  Such a formal system leads to
+a shorter, more elegant expression of the balanced parentheses rule.
+In practice, we can provide enough memory for any of the strings our
+program will actually meet.
+
+<P><H2>Turing Machines</H2>
+
+<P>One way we might explore infinite machines is to imagine that they're
+represented by state diagrams, like those of finite-state machines,
+but with an infinite number of states.  For example, here is a picture
+of an infinite-capacity parenthesis counter:
+
+<P><CENTER><IMG SRC="waydeep.gif" ALT="figure: waydeep"></CENTER>
+
+<P>The trouble with this idea is that it's hard to model precisely what's
+meant by that row of dots on the right.  There's no way we can have
+a <EM>complete</EM> formal description of an infinitely complex machine.
+
+<P>Instead, consider what <EM>you</EM> do when you have to solve a problem
+too complex to fit in your own memory.  You don't build yourself a
+bigger brain; you get a pencil and some paper.  That is, you use <EM>
+external</EM> storage.  You can imagine that your brain is a finite-state
+machine but that it has access to an infinite supply of paper.
+
+<P>Of course, this division of a problem's necessary information into
+a finite <EM>internal</EM> state and an infinite <EM>external</EM> memory
+also models actual computers in an obvious way.  The internal state
+in the model represents the internal memory of the computer, while
+the external memory in the model represents such storage devices as
+disks and tapes.  To solve a bigger problem you don't have to buy
+a bigger computer; you just have to switch floppy disks occasionally.
+
+<P>You might think that the mathematical model I'm talking about was
+based on the analogy with real computers and that my story about the finite-state
+brain is just a coincidence.  But in fact this model was invented
+by Alan M. Turing in 1936, before there were any computers!  It was
+<EM>human</EM> problem-solving that Turing wanted to model with a machine.
+
+<P>What is a Turing machine?  Start by imagining a finite-state machine
+with different possible outputs, like the adder we saw earlier.  Attached
+to this machine is a tape of limitless length.  Symbols from some
+alphabet, like the machine's input and output symbols, can be written
+on the tape.  There is a reading and writing mechanism, like the heads
+of a magnetic tape recorder, that can travel along the tape.
+
+<P>Just as each state of the machine can have an output associated with
+it, each state can also take action to affect the tape:  It can move
+the head by one symbol in either direction and it can change the
+symbol at the head's current position.
+
+<P>In fact, we simplify the formal description of the machine by
+using the tape as the input/output device as well as the storage device.
+That is, we can start with some sequence of symbols already written
+on the tape.  That sequence serves as the input to the machine; state
+transitions are based on the symbol under the tape head, not a symbol
+from some other source.  Likewise, the output from a state (if any)
+is written on the tape.
+
+<P>Somewhat analogous to the concept of an accepting state in our earlier
+examples, a Turing machine can have <EM>halting</EM> states.  When the
+machine enters a halting state it stops its operation.  There are
+no more state transitions.  The output from the machine is whatever
+sequence of symbols it leaves written on the tape.
+
+<P><H2>Turing's Thesis</H2>
+
+
+<P>Turing invented his abstract machine because he was trying to formalize
+the idea of an <EM>effective procedure</EM>:  What does it mean to specify
+a technique for solving some problem well enough that we can be sure
+it will really work?  As an analogy, think about directions for driving
+from here to somewhere.  Someone can hand you a piece of paper with
+a list of instructions like &quot;When you get to the gas station
+on the left, turn right.&quot;  But sometimes you get directions that
+weren't careful enough.  There may be a sharp right turn and a mild
+right turn available near the gas station.  There may be a fork in
+the road before you even get to the gas station.
+
+<P>Turing's idea is that any problem for which there is <EM>any</EM> effective
+procedure can be modeled by a Turing machine.  The phrase &quot;any effective
+procedure&quot; is taken to include the workings of the human mind.  If
+Turing is right, any problem that a person can solve can be programmed
+for a computer.
+
+<P>This claim isn't something that can be proved or disproved mathematically
+because there is no prior formal definition of &quot;effective procedure&quot;
+to which Turing machines can be compared.  Also, it may be that the
+idea of a procedure somehow doesn't cover all the different kinds
+of thinking that people do.  Maybe it's true, for example, that computers
+are potentially as powerful as people at solving problems, but &quot;solving
+problems&quot; might not turn out to be an appropriate description of
+what's going on when we feel emotions.  If that turned
+out to be true, we <EM>should</EM> expect a computer to become the world's
+chess champion someday, but we <EM>shouldn't</EM> expect one to become
+the world's champion poet.
+
+<P>But this possible conclusion has been attacked from both sides.  Some
+people think that emotions really <EM>are</EM> a matter of computable
+procedures.  Kenneth Colby's program called Parry attempts to model
+the behavior of a paranoid human being by manipulating variables
+for emotions like anger and fear.  On the other hand, some people
+think that even chess doesn't fall within the realm of things that
+people do by carrying out effective procedures in Turing's sense.
+A chess master, these people say, doesn't analyze the chess board
+in a step-by-step fashion like a computer.  He looks at the board
+as a single, whole entity, and the important features just spring
+to mind by some process that is still rather mysterious.
+
+<P>What <EM>is</EM> known is that several other mathematical models of effective
+procedures have been shown to be equivalent to Turing machines, in
+the same sense in which regular expressions are equivalent to finite-state
+machines.  For example, all of the popular programming languages are
+Turing-equivalent.  There's no such thing as a computation that can
+be done in Logo but not in Pascal, or vice versa.  (Of course, one
+language may be more <EM>convenient</EM> than another for a given problem.)
+
+<P><H2>The Halting Theorem</H2>
+
+
+<P>I'm not going to get into specific examples of Turing machine programming
+here.  That would take too much space for a single chapter; if you're
+interested you should pursue the topic in a book on automata theory.
+But I want to give one example of the theoretical value of Turing machines.
+
+<P>You've undoubtedly had the experience of writing a Logo program with a bug
+that causes an &quot;infinite loop&quot;--you run the program and it just sits there
+forever, when instead it's supposed to compute and print some results.
+That's a frustrating kind of bug because you're never quite sure if the
+program is really broken or if it's just very slow.  Maybe if you waited
+another minute it would come up with the answer.  Wouldn't it be great if,
+when you started the program running, Logo could print an error message like
+<CODE>This program has an infinite loop</CODE>, just as it does for other errors?
+
+<P>It turns out that infinite loops can't, in general, be detected
+automatically.  Certainly <EM>some</EM> infinite loops are very easy to spot,
+and we can write programs that catch certain categories of infinite loop.
+But we can't write a program that's <EM>guaranteed</EM> to catch infinite
+loops in programs, in Logo or any other Turing-equivalent language.  The
+fact that it's impossible is called the <EM>halting theorem.</EM>
+
+<P>It's a little tricky understanding just what the halting theorem says because
+it involves Turing machines that manipulate Turing machines as data, which
+is a kind of self-reference akin to recursion.  Self-reference is always hard
+to talk about and can lead to paradoxes like the classic &quot;This statement
+is false.&quot; (Is the sentence in quotes true or false?  If it's true, then it
+must be false, because it says so.  But if it's false, and it <EM>says</EM>
+it's false, it must really be true!)  So let's proceed carefully.
+
+<P>The data recorded on a Turing machine's tape is a string of symbols.
+Generally we choose the symbols to represent something meaningful; for
+example, a string of digits can represent a number.  Earlier in this chapter
+we used strings of symbols like
+
+<P><PRE>[1 [[1 A 2] [2 B 3] [3 A 2]] [1 3]]
+</PRE>
+
+<P>to represent a finite-state machine.  There's no reason we
+couldn't put <EM>that</EM> string of symbols on the tape of a Turing machine
+as its input.  For example, we could build a Turing machine that would work
+like my <CODE>fsm</CODE> program, simulating the finite-state machine that it found
+written on its tape when it started.
+
+<P>Letting a Turing machine simulate a finite-state machine doesn't raise
+questions of self-reference.  But a Turing machine, too, is a formal
+structure; it, too, can be represented as a string of symbols.
+
+<P>Because a representation of a Turing machine can be the input to another
+Turing machine, we can design Turing machines that answer questions about
+Turing machines.  For example, we can write a <EM>universal</EM> Turing
+machine, one that simulates any Turing machine the way <CODE>fsm</CODE> simulates
+any finite-state machine.
+
+<P>A universal Turing machine (a Turing machine simulator) sort of half-solves
+the halting problem.  Suppose we want to know whether a given machine will
+halt after it is started with a given input.  (This is like asking whether a
+certain Logo procedure will terminate if it's invoked with a particular
+input.)  We can use the universal Turing machine to simulate the one we're
+interested in.  If the machine <EM>does</EM> halt, we'll find out about it.
+But if the machine in question <EM>doesn't</EM> halt, then the simulator
+won't halt either.  We'll still have the problem we had in the first
+place--how can we be sure it won't finally halt if we give it another
+minute?
+
+<P>To solve the halting problem, what we need is a Turing machine that accepts
+a representation of any Turing machine as input, just like the universal
+Turing machine.  But this one has to be guaranteed to halt, even if the
+input machine wouldn't halt.  That's what the halting theorem says we can't
+do.
+
+<P><H2>Proving the Halting Theorem in Logo</H2>
+
+<P>What makes it possible to raise the question of whether a Turing machine can
+decide whether another Turing machine would halt for a given input tape is
+the fact that one Turing machine's &quot;program&quot; can be represented as data
+for another Turing machine.  This is also true of Logo procedures.  In
+particular, the higher-order procedures like <CODE>map</CODE> and <CODE>filter</CODE>
+manipulate other procedures by accepting their names as inputs.
+We can, therefore, use Logo
+procedures to illustrate the proof of the halting theorem.
+
+<P>We'll consider a Logo procedure with an input as analogous to a Turing
+machine with its input tape.  We want to prove that there can't be a Logo
+procedure that could tell whether such a procedure stops for a given input.
+The technique we use is called <EM>proof by contradiction.</EM>  In this
+technique we assume that there <EM>is</EM> such a procedure, then show that
+this assumption leads to a paradox.
+
+<P>So let's imagine that someone has written a Logo predicate <CODE>haltp</CODE> that
+takes two inputs: the name of a procedure and an input value for that
+procedure.  <CODE>Haltp</CODE> will output <CODE>true</CODE> if the procedure it's testing
+would eventually stop, given the specified input; <CODE>haltp</CODE> outputs <CODE>
+false</CODE> if the procedure it's testing would get into an infinite loop, like a
+recursive procedure without a stop rule.  (In practice, if you think about
+your own experience debugging programs, it's easy to tell if a procedure
+doesn't have a stop rule at all, but not so easy to be sure that the stop
+rule will always eventually be satisfied.  Think about a Pig Latin program
+given a word of all consonants as input.  We want
+
+<P><PRE>to piglatin :word
+if memberp first :word [a e i o u] [output word :word &quot;ay]
+output piglatin word bf :word first :word
+end
+
+? <U>print haltp &quot;piglatin &quot;salami</U>
+true
+? <U>print haltp &quot;piglatin &quot;mxyzptlk</U>
+false
+</PRE>
+
+<P>Remember that <CODE>haltp</CODE> itself must <EM>always</EM> stop, even
+in the case where <CODE>piglatin</CODE> wouldn't stop.)
+
+<P>Now consider this Logo procedure:
+
+<P><PRE>to try :proc
+if haltp :proc :proc [loop]
+end
+
+to loop
+loop
+end
+</PRE>
+
+<P>Since <CODE>haltp</CODE> works, we're assuming, on <EM>any</EM> Logo
+procedure with one input, it must work on <CODE>try</CODE> in particular.
+What happens if we say
+
+<P><PRE>? <U>try &quot;try</U>
+</PRE>
+
+<P>Does this stop or loop?  Suppose it stops.  <CODE>try</CODE> begins its
+work by evaluating the expression
+
+<P><PRE>haltp &quot;try &quot;try
+</PRE>
+
+<P>Since we've said <CODE>try</CODE> will stop, given <CODE>try</CODE> as input,
+<CODE>haltp</CODE> will output <CODE>true</CODE>.  It follows, from the definition of <CODE>
+try</CODE>, that <CODE>try</CODE> will invoke <CODE>loop</CODE> and will <EM>not</EM> stop.
+Similarly, if we start with the assumption that <CODE>try</CODE> will loop, then
+<CODE>haltp</CODE> must output <CODE>false</CODE> and so, from the definition of <CODE>
+try</CODE>, you can see that <CODE>try</CODE> <EM>will</EM> stop.  Whatever value <CODE>
+haltp</CODE> outputs turns out to be incorrect.
+
+<P>It was the assumption that we could write an infallible <CODE>haltp</CODE> that led
+us into this contradiction, so that assumption must be wrong.  We can't write
+a Logo procedure that will automatically detect infinite loops in our
+programs.  A similar proof could be made in any language in which one program
+can manipulate another program as data--that is, in any Turing-equivalent
+language.
+
+<P>
+<TABLE width="100%"><TR><TD><A HREF="../v3-toc2.html">(back to Table of Contents)</A>
+<TD align="right"><A HREF="../v3ch0/v3ch0.html"><STRONG>BACK</STRONG></A>
+chapter thread <A HREF="../v3ch2/v3ch2.html"><STRONG>NEXT</STRONG></A>
+</TABLE>
+
+<P><H2>Program Listing</H2>
+
+<P><P>
+<P><PRE>
+;;; Finite State Machine Interpreter (<A NAME="fsm">FSM</A>)
+
+to game :which
+fsm thing word "mach :which
+end
+
+to fsm :machine
+cleartext
+setcursor [0 3]
+localmake "start startpart :machine
+localmake "moves movepart :machine
+localmake "accept acceptpart :machine
+fsm1 :start
+end
+
+to fsm1 :here
+ifelse memberp :here :accept [accept] [reject]
+fsm1 (fsmnext :here readchar)
+end
+
+to fsmnext :here :input
+blank
+if memberp :input (list char 13 char 10) ~
+   [print ifelse memberp :here :accept ["| ACCEPT|] ["| REJECT|]
+    output :start]
+type :input
+catch "error [output last find [fsmtest :here :input ?] :moves]
+output -1
+end
+
+to fsmtest :here :input :move
+output and (equalp :here arrowtail :move) ~
+           (memberp :input arrowtext :move)
+end
+
+;; Display machine state
+
+to accept
+display "accept
+end
+
+to reject
+display "reject
+end
+
+to blank
+display "|      |
+end
+
+to display :text
+localmake "oldpos cursor
+setcursor [15 1]
+type :text
+setcursor :oldpos
+end
+
+;; Data abstraction for machines
+
+to startpart :machine
+output first :machine
+end
+
+to movepart :machine
+output first bf :machine
+end
+
+to acceptpart :machine
+output last :machine
+end
+
+to make.machine :start :moves :accept
+output (list :start :moves :accept)
+end
+
+;; Data abstraction for arrows
+
+to arrowtail :arrow
+output first :arrow
+end
+
+to arrowtext :arrow
+output first butfirst :arrow
+end
+
+to arrowhead :arrow
+output last :arrow
+end
+
+to make.arrow :tail :text :head
+output (list :tail :text :head)
+end
+
+;; Machine descriptions for the guessing game
+
+make "mach1 [1 [[1 AB 1]] [1]]
+make "mach2 [1 [[1 ABC 2] [2 ABC 1]] [1]]
+make "mach3 [1 [[1 A 2] [2 B 3] [3 ABC 3]] [3]]
+make "mach4 [1 [[1 A 2] [1 B 3] [1 C 4] [2 A 1] [3 B 1] [4 C 1]] [1]]
+make "mach5 [1 [[1 ABC 2] [2 B 1]] [1]]
+make "mach6 [1 [[1 A 2] [2 AB 2] [2 C 3] [3 AB 2] [3 C 3]] [3]]
+make "mach7 [1 [[1 AB 1] [1 C 2] [2 C 1]] [1]]
+make "mach8 [1 [[1 A 2] [1 BC 1] [2 A 1] [2 BC 2]] [1]]
+make "mach9 [1 [[1 AB 1] [1 C 2] [2 A 3] [2 B 1] [3 A 1]] [1]]
+make "mach10 [1 [[1 A 2] [1 BC 1] [2 A 2] [2 B 3] [2 C 1]
+                 [3 A 2] [3 B 1] [3 C 4] [4 A 2] [4 B 5] [4 C 1]
+                 [5 A 6] [5 BC 1] [6 ABC 6]]
+              [6]]
+
+
+;;; Regular Expression to FSM Translation (<A NAME="machine">MACHINE</A>)
+
+to machine :regexp
+localmake "nextstate 0
+output optimize determine nondet :regexp
+end
+
+;; First step: make a possibly <A NAME="nondet">nondeterministic</A> machine
+
+to nondet :regexp
+if and (wordp :regexp) (equalp count :regexp 1) ~
+   [output ndletter :regexp]
+if wordp :regexp [output ndor reduce "sentence :regexp]
+if equalp first :regexp "or [output ndor butfirst :regexp]
+if equalp first :regexp "* [output ndmany last :regexp]
+output ndconcat :regexp
+end
+
+;; <A NAME="ndletter">Alphabet</A> rule
+
+to ndletter :letter
+localmake "from newstate
+localmake "to newstate
+output (make.machine :from
+                     (list (make.arrow :from :letter :to))
+                     (list :to))
+end
+
+;; <A NAME="ndconcat">Concatenation</A> rule
+
+to ndconcat :exprs
+output reduce "string (map "nondet :exprs)
+end
+
+to string :machine1 :machine2
+output (make.machine (startpart :machine1)
+                     (sentence (movepart :machine1)
+                               (splice acceptpart :machine1 :machine2)
+                               (movepart :machine2))
+                     (stringa (acceptpart :machine1)
+                              (startpart :machine2)
+                              (acceptpart :machine2)))
+end
+
+to stringa :accept1 :start2 :accept2
+if memberp :start2 :accept2 [output sentence :accept1 :accept2]
+output :accept2
+end
+
+;; <A NAME="ndor">Alternatives</A> rule
+
+to ndor :exprs
+localmake "newstart newstate
+localmake "machines (map "nondet :exprs)
+localmake "accepts map.se "acceptpart :machines
+output (make.machine :newstart
+                     (sentence map.se "movepart :machines
+                               map.se "or.splice :machines)
+                     ifelse not emptyp find [memberp (startpart ?)
+                                                     (acceptpart ?)]
+                                            :machines
+                            [fput :newstart :accepts]
+                            [:accepts])
+end
+
+to or.splice :machine
+output map [newtail ? :newstart] (arrows.from.start :machine)
+end
+
+;; <A NAME="ndmany">Repetition</A> rule
+
+to ndmany :regexp
+localmake "machine nondet :regexp
+output (make.machine (startpart :machine)
+                     sentence (movepart :machine)
+                              (splice (acceptpart :machine) :machine)
+                     fput (startpart :machine) (acceptpart :machine))
+end
+
+;; <A NAME="splice">Generate</A> moves from a bunch of given states (:accepts) duplicating
+;; the moves from the start state of some machine (:machine).
+;; Used for concatenation rule to splice two formerly separate machines;
+;; used for repetition rule to "splice" a machine to itself.
+
+to splice :accepts :machine
+output map.se [copy.to.accepts ?] (arrows.from.start :machine)
+end
+
+to arrows.from.start :machine
+output filter [equalp startpart :machine arrowtail ?] movepart :machine
+end
+
+to copy.to.accepts :move
+output map [newtail :move ?] :accepts
+end
+
+to newtail :arrow :tail
+output make.arrow :tail (arrowtext :arrow) (arrowhead :arrow)
+end
+
+;; <A NAME="newstate">Make</A> a new state number
+
+to newstate
+make "nextstate :nextstate+1
+output :nextstate
+end
+
+;; Second step: Turn nondeterministic FSM into a <A NAME="determine">deterministic</A> one
+;; Also eliminates "orphan" (unreachable) states.
+
+to determine :machine
+localmake "moves movepart :machine
+localmake "accepts acceptpart :machine
+localmake "states []
+localmake "join.state.list []
+localmake "newmoves nd.traverse (startpart :machine)
+output make.machine (startpart :machine) ~
+                    :newmoves ~
+                    filter [memberp ? :states] :accepts
+end
+
+to <A NAME="nd.traverse">nd.traverse</A> :state
+if memberp :state :states [output []]
+make "states fput :state :states
+localmake "newmoves (check.nd filter [equalp arrowtail ? :state] :moves)
+output sentence :newmoves map.se "nd.traverse (map "arrowhead :newmoves)
+end
+
+to <A NAME="check.nd">check.nd</A> :movelist
+if emptyp :movelist [output []]
+localmake "letter arrowtext first :movelist
+localmake "heads sort map "arrowhead ~
+                          filter [equalp :letter arrowtext ?] :movelist
+if emptyp butfirst :heads ~
+   [output fput first :movelist
+                check.nd filter [not equalp :letter arrowtext ?]
+                                :movelist]
+localmake "check.heads member :heads :join.state.list
+if not emptyp :check.heads ~
+   [output fput make.arrow :state :letter first butfirst :check.heads ~
+                check.nd filter [not equalp :letter arrowtext ?]
+                                :movelist]
+localmake "join.state newstate
+make "join.state.list fput :heads fput :join.state :join.state.list
+make "moves sentence :moves ~
+                     map [make.arrow :join.state
+                                     arrowtext ?
+                                     arrowhead ?] ~
+                         filter [memberp arrowtail ? :heads] :moves
+if not emptyp find [memberp ? :accepts] :heads ~
+   [make "accepts sentence :accepts :join.state]
+output fput make.arrow :state :letter :join.state ~
+            check.nd filter [not equalp :letter arrowtext ?] :movelist
+end
+
+to sort :list
+if emptyp :list [output []]
+output insert first :list sort butfirst :list
+end
+
+to insert :value :sorted
+if emptyp :sorted [output (list :value)]
+if :value = first :sorted [output :sorted]
+if :value < first :sorted [output fput :value :sorted]
+output fput first :sorted insert :value butfirst :sorted
+end
+
+;; Third step: <A NAME="optimize">Combine</A> redundant states.
+;; Also combines arrows with same head and tail: 
+;;   [1 A 2] [1 B 2] -> [1 AB 2].
+
+to optimize :machine
+localmake "stubarray array :nextstate
+foreach (movepart :machine) "array.save
+localmake "states sort fput (startpart :machine) ~
+                            map "arrowhead movepart :machine
+localmake "start startpart :machine
+foreach reverse :states [optimize.state ? ?rest]
+output (make.machine :start
+                     map.se [fix.arrows ? item ? :stubarray] :states
+                     filter [memberp ? :states] acceptpart :machine)
+end
+
+to array.save :move
+setitem (arrowtail :move) :stubarray ~
+        stub.add (arrow.stub :move) (item (arrowtail :move) :stubarray)
+end
+
+to <A NAME="stub.add">stub.add</A> :stub :stublist
+if emptyp :stublist [output (list :stub)]
+if (stub.head :stub) < (stub.head first :stublist) ~
+   [output fput :stub :stublist]
+if (stub.head :stub) = (stub.head first :stublist) ~
+   [output fput make.stub letter.join (stub.text :stub)
+                                      (stub.text first :stublist)
+                          stub.head :stub
+                butfirst :stublist]
+output fput first :stublist (stub.add :stub butfirst :stublist)
+end
+
+to letter.join :this :those
+if emptyp :those [output :this]
+if beforep :this first :those [output word :this :those]
+output word (first :those) (letter.join :this butfirst :those)
+end
+
+to optimize.state :state :others
+localmake "candidates ~
+          filter (ifelse memberp :state acceptpart :machine
+                         [[memberp ? acceptpart :machine]]
+                         [[not memberp ? acceptpart :machine]]) ~
+                 :others
+localmake "mymoves item :state :stubarray
+localmake "twin find [equalp (item ? :stubarray) :mymoves] :candidates
+if emptyp :twin [stop]
+make "states remove :state :states
+if equalp :start :state [make "start :twin]
+foreach :states ~
+        [setitem ? :stubarray 
+                 (cascade [emptyp ?2]
+                          [stub.add (change.head :state :twin first ?2)
+                                    ?1]
+                          filter [not equalp stub.head ? :state]
+                                 item ? :stubarray
+                          [butfirst ?2]
+                          filter [equalp stub.head ? :state]
+                                 item ? :stubarray)]
+end
+
+to change.head :from :to :stub
+if not equalp (stub.head :stub) :from [output :stub]
+output list (stub.text :stub) :to
+end
+
+to fix.arrows :state :stublist
+output map [stub.arrow :state ?] :stublist
+end
+
+;; Data abstraction for "stub" arrow (no tail)
+
+to arrow.stub :arrow
+output butfirst :arrow
+end
+
+to make.stub :text :head
+output list :text :head
+end
+
+to stub.text :stub
+output first :stub
+end
+
+to stub.head :stub
+output last :stub
+end
+
+to stub.arrow :tail :stub
+output fput :tail :stub
+end
+</PRE><P>
+
+<P><A HREF="../v3-toc2.html">(back to Table of Contents)</A>
+<P><A HREF="../v3ch0/v3ch0.html"><STRONG>BACK</STRONG></A>
+chapter thread <A HREF="../v3ch2/v3ch2.html"><STRONG>NEXT</STRONG></A>
+
+<P>
+<ADDRESS>
+<A HREF="../index.html">Brian Harvey</A>, 
+<CODE>bh@cs.berkeley.edu</CODE>
+</ADDRESS>
+</BODY>
+</HTML>