perm filename TEXC.PUB[206,LMM] blob sn#096395 filedate 1974-04-05 generic text, type C, neo UTF8
C00001 00001
C00003 00002	.device xgp
C00005 00003	.sec                  INTRODUCTION TO LISP
C00009 00004	.ss Atoms.
C00011 00005	.ss List structures.
C00015 00006	.ss S-expressions.
C00021 00007	.ss The basic functions and predicates of LISP.
C00029 00008	.ss Conditional expressions.
C00032 00009	.ss Boolean expressions.
C00035 00010	.ss Recursive function definitions.
C00051 00011	.ss Lambda expressions and functions with functions as arguments.
C00060 00012	.ss Label.
C00067 00014	.ss Simple list recursion.
C00075 00015	.ss Simple S-expression recursion.
C00078 00016	.ss Other structural recursions.
C00081 00017	.AT "\J" ⊂FILL⊃ 
C00096 00018	.ss Game trees.
C00108 00019	.STANDARD BACK
C00109 ENDMK
.device xgp
.require "pubmac[206, NXL]" source_file
.standard front(I, 1)
.font 1 "basl30" <<text>>
.font 2 "bdr30" <<sym>>
.font 3 "basi30" <<var>>
.font 4 "basb30" <<bold>>
.font 5 "bdr30" <<const>>
.font 6 "sub"
.font 7 "sup"
.font A "fix40"
.font B "fix30"
.turn on "%#π" ;
.<<TURN ON "@" FOR "∂" ;>>
.every heading(, {SECNAME}, {page}) ;
.AT 8 ⊂"%1        %*"⊃ ;
.AT 16 ⊂"%1                %*"⊃ ;
.<<AT "\→" KK "." ; ⊂KK ← CHAR⊃ ;>>
.sec                  INTRODUCTION TO LISP

.ss Lists.

	Symbolic information in LISP is  expressed  by  S-expressions
and  these  are  represented  in  the  memory of the computer by list
structures. Before giving formal  definitions,  we  shall  give  some

	The most common form of S-expression is the  list,  and  here
are some lists:

The list
	%5(A B C E)
%1has four elements.

The list
	%5(A B (C D) E)
%1has four elements one of which is itself a list.

The list
%1has one element.

The list
	%5((A B C D))
%1also has one element which itself is a list.

The list
%1has no elements; it is also written
%1The list
	%5(PLUS X Y)
%1has three elements and may be used to represent the expression
	%3x%2 + %3y.

%1The list
	%5(PLUS (TIMES X Y) X 3)
%1has four elements and may be used to represent the expression
	%3xy%2 + %3x%2 + %53.

%1The list
	%5(EXIST X (ALL Y (IMPLIES (P X) (P Y))))
%1may be used to represent the logical expression

%1The list
%1may be used to represent the expression


%1The list
	%5((A B) (B A C D) (C B D E) (D B C E) (E C D F) (F E))
is used to represent the network of Figure 1 according  to  a  scheme
whereby  there  is a sublist for each vertex consisting of the vertex
itself followed by the vertices to which it is connected.
                              Figure 1

	The  elements  of  a  list  are surrounded by parentheses and
separated by spaces.  A list may have any number of terms and any  of
these  terms  may  themselves  be  lists.   In  this case, the spaces
surrounding a sublist  may  be  omitted,  and  extra  spaces  between
elements of a list are allowed.  Thus the lists

	%5(A B(C  D)    E)


	%5(A B (C D) E)

%1are regarded as the same.

.ss Atoms.

	The expressions %5A, B, X, Y, 3, PLUS, %1and %5ALL%1 occurring in the
above  lists are called atoms.  In general, an atom is expressed by a
sequence of capital letters,  digits,  and  special  characters  with
certain  exclusions.   The exclusions are <space>, <carriage return>,
and the other non-printing  characters,  and  also  the  parentheses,
brackets,  semi-colon,  and  comma.   Numbers are expressed as signed
decimal or octal numbers,  the  exact  convention  depending  on  the
implementation.  Floating  point  numbers  are  written  with decimal
points and, when appropriate, an exponent notation depending  on  the
implementation.   The  reader  should consult the programmer's manual
for the LISP implementation he intends to use.

	Some examples of atoms are


%1and from these we can form lists like

	((345 3.14159 -47) A307B THE-LAST-TRUMP -45.21).
.ss List structures.

	Lists  are  represented in the memory of the computer by list
structures.    A list structure is a collection of memory words  each
of  which  is  divided  into  two  parts, and each part is capable of
containing an address in memory. The two parts are called are  called
the  a-part  and  the  d-part.  There  is  one computer word for each
element of the list, and the a-part of the word contains the  address
of the list or atom representing the element, and the d-part contains
the address of the word representing the next element  of  the  list.
If the list element is itself a list, then, of course, the address of
the first word of its list structure is given in the  a-part  of  the
word  representing  that  element.  A diagram shows this more clearly
than words, and the list structure corresponding to the  list   %5(PLUS
(TIMES  X  Y)  X  3)%1   which may represent the expression  %3xy%2 + %3x%2 + %53  is
shown in figure 2.
                              Figure 2.

	Atoms  are  represented  by  the  addresses of their property
lists which are list structures of a special kind  depending  on  the
implementation.   (In  some  implementations,  the  first  word  of a
property list is in a special are of memory, in others the first word
is  distinguished  by  sign, in still others it has a special a-part.
For basic LISP programming, it is  enough  to  know  that  atoms  are
distinguishable  from  other  list  structures  by a predicate called

	The  last  word  of  a list cannot have the address of a next
word in its d-part since there isn't any next word,  so  it  has  the
address of a special atom called  %5NIL%1.

	A  list  is  referred  to  by giving the address of its first
element.  According to this convention, we see that the a-part  of  a
list  word  is  the  list  element  and  the d-part is a pointer to a
sublist formed by deleting the first element.  Thus the first word of
the  list  structure  of  figure  2  contains  a  pointer to the list
structure representing the atom  %5PLUS%1, while its d-part points to the
list  %5((TIMES X Y) X 3)%1.  The second word contains the list structure
representing  %5(TIMES X Y)%1  in  its  a-part  and  the  list  structure
representing  %5(X 3)%1  in its d-part.  The last word points to the atom
%53%1  in its a-part and has a pointer to the atom  %5NIL%1  in its  d-part.
This is consistent with the convention that  %5NIL%1  represents the null

.ss S-expressions.

	When we examine the way list structures  represent  lists  we
see  a  curious  asymmetry.   Namely,  the  a-part of a list word can
contain an atom or a list, but the d-part can contain only a list  or
the special atom  %5NIL%1.   This restriction is quite unnatural from the
computing point of view,  and  we  shall  allow  arbitrary  atoms  to
inhabit  the  d-parts  of  words, but then we must generalize the way
list structures are expressed as character strings. To  do  this,  we
introduce the notion of S-expression.

	An  S-expression is either an atom or a pair of S-expressions
separated by "#.#" and surrounded by parentheses.   In  BNF,  we  can

<S-expression> ::= <atom> | (<S-expression> . <S-expression>).

Examples of S-expressions are

	(A . B)
	(A . (B . A))
	(PLUS (X . (Y . NIL)))
	(3 . 3.4)

	In the memory of a computer, an S-expression  is  represented
by  the  address of a word whose a-part contains the first element of
the pair and whose d-part contains the second element  of  the  pair.
Thus,  the S-expressions  %5(A.B),  (A.(B.A))%1, and  %5(PLUS.(X.(Y.NIL))) %1
are represented by the list structures of figure 3.
                              Figure 3.

	Note that the list %5(PLUS X Y)%1 and the S-expression
%5 (PLUS . (X . (Y . NIL)))%1  are represented  in  memory  by  the  same  list
structure.  The simplest way to treat this is to regard S-expressions
as primary and lists  as  abbreviations  for  certain  S-expressions,
namely those that never have any atom but  NIL  as the second part of
a pair. In giving  input  to  LISP,  either  the  list  form  or  the
S-expression  form may be used for lists.  On output, LISP will print
a list structure as a  list  as  far  as  it  can,  otherwise  as  an
S-expression.  Thus,  some list structures will be printed in a mixed
notation, e.g. %5((A . B) (C . D) (3))%1.

	In general, the list %2(%3a b . . .  z%2)%1 may be regarded
as an abbreviation of the S-expression %2(%3a%2 . (%3b%2 . (%3c%2 .
(... (%3z . %5NIL%2) ...)))%1.

	1. If we represent sums and products as indicated  above  and
use  %5(MINUS X),  (QUOTIENT X Y)%1, and  %5(POWER X Y)%1  as representations
of  %2-%3x%1,  %3x%2/%3y%1, and  %3x%2↑%3y%1  respectively, then

	a. What do the lists 



	%5(PLUS -2 (MINUS 2) (TIMES X (POWER Y 3.3)))


	b.    How    are    the   expressions   %3xyz%2+%53%2(%3u%2+%3v%2)↑(-%53%2)%1   and
%2(%3xy%2-%3yx%2)/(%3xy%2+%3yx%2)%1 to be represented?

	2. In the above  mentioned  graph  notation,  what  graph  is
represented by the list

	%5((A D E F)(B D E F)(C D E F)(D A B C)(E A B C)(F A B C))?

	%13. Write the list %5((PLUS (TIMES X Y) X 3)%1 as an S-expression.
This is sometimes referred to as "dot-notation".

	4.  Write  the  following  S-expressions  in list notation to
whatever extent is possible:
	a. (A . NIL)
	b. (A . B)
	c. ((A . NIL) . B)
	d. ((A . B) . ((C . D) . NIL).
.ss The basic functions and predicates of LISP.

	Just as numerical computer programs are  based  on  the  four
arithmetic  operations  of  addition subtraction, multiplication, and
division, and the arthmetic predicates of equality and comparison, so
symbolic  computation  has  its basic predicates and functions.  LISP
has three basic functions and two predicates.

	First,  we have two functions %4a%1 and %4d%1.  %4a %3x%1 is
the a-part of the S-expression %5x%1.  Thus,  %4a%5(A . B) %2= %5A%1,
and %4a%5((A . B) . A) %2= %5(A . B)%1. %4d %3x%1 is the d-part of
the S-expression %3x%1. Thus %4d%5(A . B) %2= %5B%1, and
%4d%5((A . B) . A) %2= %5A%1.  %4a %3x%1 and %4d %3x%1 are undefined in
basic LISP when %3x%1 is an atom, but they may have a meaning in some

	Since  lists  are  a  particular  kind  of  S-expression, the
meanings of  %4a%1  and  %4d%1  for lists are also determined  by  the  above
definitions.  Thus, we have

	%4a%5(A B C D) %2=%4 A


	%4d%5(A B C D) %2= %5(B C D),

%1and we see that, in general,  %4a %3x%1  is the first element of  the  list
 %3x%1, and  %4d %3x%1  is the rest of the list, deleting that first element.

	Notice  that  for S-expressions, the definitions of  %4a %3x%1  and
%4d %3x%1  are symmetrical, while for lists the symmetry is lost.  This is
because  of  the  unsymmetrical nature of the convention that defines
lists in terms of S-expressions.

	Notice, further,  our  convention  of  writing   %4a%1   and   %4d%1##
without  brackets  surrounding the argument.  Also, we use lower case
letters for our function names and for variables, reserving the upper
case letters for the S-expressions themselves.

	The  third  function  %3cons%2[%3x%2, %3y%2]%1  forms the S-expression whose
a-part and d-part are  %3x%1  and  %3y%1  respectively.  Thus

	%3cons%2[%5(A.B), A%2] = %5((A.B).A).

	%1We  see  that  for  lists,   %3cons%1   is a prefixing operation.
Namely,  %3cons%2[%3x%2, %3y%2]%1  is the list obtained by putting the  element   %3x%1##
onto the front of the list  %3y%1.  Thus

	%3cons%2[%5A, (B C D E)%2] = %5(A B C D E).

%1If we want  %3cons%2[%3x%2, %3y%2]%1  to  be  a  list,  then   %3y%1   must  be  a  list
(possibly the null list  %5NIL%1), and  %3x%1  must be a list or an atom.  In
the case of S-expressions in general, there is no restriction on  the
arguments  of   %3cons%1.   Usually,  we  shall  write   %3x . y%1   instead of
%3cons%2[%3x%2, %3y%2]%1  since this is briefer.

	The  first  predicate  is   %4at %3x%1.   %4at %3x%1   is  true  if   the
S-expression  %3x%1  is atomic and false otherwise.

	The  second  predicate  is equality of atomic symbols written
%3x %4eq %3y%1. Equality of S-expressions is tested by a  program  based  on
%4eq%1.   Actually   %4eq%1  does a bit more than testing equality of atoms.
Namely,  %3x %4eq %3y%1  is true if and only if the addresses  of  the  first
words  of  the  S-expressions   %3x%1   and  %3y%1  are equal.  Therefore, if
%3x %4eq %3y%1, then  %3x%1  and %3y%1 are certainly  the  same  S-expression  since
they  are  represented by the same structure in memory.  The converse
is false because there is no  guarantee  in  general  that  the  same
S-expression is not represented by two different list structures.  In
the particular case where at least one of the S-expressions is  known
to  be  an atom, this guarantee can be given, because LISP represents
atoms uniquely in memory.

	The above are all the basic functions of LISP; all other LISP
functions  can  be  built  from  them  using  recursive  conditional
expressions as will shortly be explained. However, the use of certain
abbreviations makes LISP programs easier to write and understand.

	%4n %3x%1   is  an  abbreviation for  %3x %4eq %5NIL%1.  It rates a special
notation because  %5NIL%1  plays the same  role  among  lists  that  zero
plays  among  numbers,  and list variables often have to be tested to
see if their value is  %5NIL%1.

	The notation   %3list%2[%3x1, x2, . . . , xn%2]%1   is  used  to  denote  the
composition of %3cons%1's that forms a list from its elements.  Thus

	%3list%2[%3x, y, z%2] = %3cons%2[%3x, cons%2[%3y, cons%2[%3z, %5NIL%2]]]

%1and forms a list of three elements out of the quantities  %3x,  y, %1  and
%3z%1.  We  often  write  %2<%3x y . . .  z%2>%1  instead of  %3list%2[%3x, y, . . . , z%2]%1
when this will not cause  confusion.

	Compositions of  %4a%1  and  %4d%1  are written by concatenating  the
letters   %4a%1  and  %4d%1.  Thus, it is easily seen that  %4ad %3x%1  denotes the
second element of the list  %3x%1, and  %4add %3x%1  denotes the third  element
of that list.

.ss Conditional expressions.

	When the form that represents a function depends on whether a
certain  predicate is true of the arguments, conditional expressions.
are used.  The conditional expression

	%4if %3p %4then %3a %4else %3b

%1is evaluated as follows:  First  %3p%1  is evaluated and determined to be
true or false.  If  %3p%1  is true, then  %3a%1  is evaluated and  its  value
is  the  value  of  the  expression.   If   %3p%1   is false, then  %3b%1  is
evaluated and its value is the value of the expression.  Note that if
%3p%1  is true,  %3b%1  is never evaluated, and if  %3p%1  is false, then  %3a%1  is
never evaluated.  The importance of this will be explained  later.  A
familiar  function that can be written conveniently using conditional
expressions is the absolute value of a real number.  We have

	%2|%3x%2| = %4if %3x%2<%50 %4then %2-%3x %4else %3x.

%1A more general form of conditional expression is

	%4if %3p %4then %3a %4else if %3q %4then %3b . . .  %4else if %3s %4then %3d %4else %3e.

%1There  can  be  any  number  of  terms;  the  value  is determined by
evaluating the propositional terms  %3p,  q%1, etc. until a true term  is
found;  the value is then that of the term following the next %4then%1.
If none of the propositional terms is true, then the value is that of
the term following the %4else%1.

	The function graphed in figure 4 is described by the equation

	%3tri%2[%3x%2] = %4if %3x%2<-%51 %4then %50 %4else if %3x%2<%50 %4then %51%2+%3x
%4else if %3x%2<%51 %4then %51%2-%3x %4else %50.
%1                              Figure 4.
.ss Boolean expressions.

	In  making  up  the  propositional   parts   of   conditional
expressions,   it   is   often   necessary   to   combine  elementary
propositional expressions using the Boolean operators  and,  or,  and
not.   We  use  the  symbols   %2∧%1,  %2∨%1, and  %2¬%1  respectively, for these
operators.  In LISP, the atoms  %5T%1  and  %5NIL%1  are used for  the  truth
values.  The Boolean operators may be described simply by listing the
values of the elementary Boolean expressions for  each  case  of  the
arguments.  Thus we have:

	%5T%2∧%5T %2= %5T
	T%2∧%5F %2= %5F
	F%2∧%5T %2= %5F
	F%2∧%5F %2= %5F

	T%2∨%5T %2= %5T
	T%2∨%5F %2= %5T
	F%2∨%5T %2= %5T
	F%2∨%5F %2= %5F

 	%2¬%5T %2= %5F
	%2¬%5F %2= %5T.

	%1The  Boolean  operators  can  be  described  by   conditional
expressions in the following way:

	%3p%2∧%3q %2= %4if %3p %4then %3q %4else %5F
	%3p%2∨%3q %2= %4if %3p %4then %5T %4else %3q
	%2¬%3p %2= %4if %3p %4then %5F %4else %5T.

%1Note that if  %3p%1  is false  %3p%2∧%3q%1  is false independent of the value  of
%3q%1,  and  likewise  if  %3p%1  is true, then  %3p%2∨%3q%1  is true independent of
%3q%1.  If  %3p%1  has been evaluated and found to be false, then   %3q%1   does
not  have  to  be evaluated at all to find the value of  %3p%2∧%3q%1, and, in
fact, LISP does not evaluate  %3q%1  in this case.  Similarly,  %3q%1  is not
evaluated  in  evaluating   %3p%2∨%3q%1  if  %3p%1  is true. This procedure is in
accordance with the above conditional expression descriptions of  the
Boolean operators.  The importance of this convention which contrasts
with that of ALGOL  60,  will  be  apparent  later  when  we  discuss
recursive definitions of functions and predicates.

.ss Recursive function definitions.

	In such languages as FORTRAN and  Algol,  computer  progrrams
are  expressed  in the main as sequences of assignment statements and
conditional go to's.  In LISP, programs are mainly expressed  in  the
form of recursively defined functions.  We begin with an example.

	The  function   %3alt%2[%3x%2]%1   gives  a  list  whose  elements  are
alternate elements of the list  %3x%1  beginning with the first.  Thus

	%3alt%2[%5(A B C D E)%2] = %5(A C E),

	%3alt%2[%5(((A B) (C D))%2] = %5((A B)),

	%3alt%2[%5(A)%2] = %5(A),
	%3alt%2[%5NIL%2] = %5NIL.

	The function  %3alt%1  is defined by the equation

	alt%2[%3x%2] ← %4if n %3x %2∨ %4n d %3x %4then %3x %4else a %3x . alt%2[%4dd %3x%2].
	%1The  above  definition  is  best  explained  by  using  it to
evaluate some expressions.  We start with  %3alt%2[%5NIL%2]%1. To evaluate this
expression  we  evaluate  the expression to the right of the  %2←%1  sign
remembering that the variable  %3x%1  has the value  %5NIL%1.  A  conditional
expression  is  evaluated by first evaluating the first propositional
term ¬ in this case  %4n %3x %2∨ %4n d %3x%1. This expression is a disjunction and
in  its evaluation we first evaluate the first disjunct, namely  %4n#%3x%1.
Since  %3x %2= %5NIL,  %4n %3x%1  is true, the disjunction is true, and the value
of  the  conditional  expression  is  the value of the term after the
first true propositiional term. The term is   %3x%1,  and  its  value  is
%5NIL%1,  so the value of  %3alt%2[%5NIL%2]%1  is  %5NIL%1  as stated above.   Obeying
the rules about the order of evaluation of terms in  conditional  and
Boolean expressions is important in this case since if we didn't obey
these rules, we might find ourselves trying to  evaluate   %4n d %3x%1   or
%3alt%2[%4dd %3x%2]%1, and since  %3x%1 is  %5NIL%1, neither of these has a value.  An
attempt to evaluate them in LISP would give rise to an error return.

	As a second example, consider   %3alt%2[%5(A  B)%2]%1.   Since  neither
%4n %3x%1 nor %4n d %3x%1 is true in this case, the disjunction %4n %3x %2∨ %4n d %3x
%1is  false  and  the  value  of  the  expression  is  the   value   of
%4a %3x . alt%2[%4dd %3x%2].     %4a %3x%1 has the value  %5A%1, and %4dd %3x%1 has the value
%5NIL%1, so we must now evaluate  %3alt%2[%5NIL%2]%1, and we already know that the
value   of   this   expression  is   %5NIL%1.  Therefore,  the  value  of
%3alt%2[%5(A B)%2]%1  is that of  %5A.NIL%1  which is  %5(A)%1.

	We can describe this  evaluation  in  a  less  wordy  way  by

	%3alt%2[%5(A B)%2] = %4if n%5(A B) %2∨ %4n d%5(A B) %4then %5(A B) %4else
			%4a%5(A B).%3alt%2[%4dd%5(A B)%2]

		   = %4if %5NIL %2∨ %4n d%5(A B) %4then %5(A B) %4else
			%4a%5(A B).%3alt%2[%4dd%5(A B)%2]

		   = %4if %5NIL %4then %5(A B) %4else
			%4a%5(A B).%3alt%2[%4dd%5(A B)%2]

		   = %4a%5(A B).%3alt%2[%4dd%5(A B)%2]

		   = %5A.%3alt%2[%5NIL%2]

		   = %5A%2.[%4if n%5NIL %2∨ %4nd%5NIL %4then %5NIL %4else

 		   = %5A%2.[%4if %5T %2∨ %4nd%5NIL %4then %5NIL %4else

 		   = %5A%2.[%4if %5T %4then %5NIL %4else

		   = %5A%2.[%5NIL%2]

		   = %5(A).
	%1This is still very  long-winded,  and  now  that  the  reader
understands  the  order  of  evaluation  of  conditional  and Boolean
expressions, we can proceed more briefly to evaluate

	%3alt%2[%5(A B C D E)%2] = %5A.%3alt%2[%5(C D E)%2]

			= %5A%2.[%5C.%3alt%2[%5(E)%2]]

			= %5A.%2[%5C.(E)%2]

			= %5(A C E).

	%1Here are three more examples of recursive functions and their
application: We define  %3last%1  by

	%3last%2[%3x%2] ← %4if n d %3x %4then a %3x %4else %3last%2[%4d %3x%2],

%1and we compute

	%3last%2[%5(A B C)%2] = %4if nd%5(A B C) %4then a%5(A B C) %4else %3last%2[%4d%5(A B C)%2]

		      = %3last%2[%5(B C)%2]

		      = %3last%2[%5(C)%2]

		      = %5C.

%1Clearly   %3last%1   computes  the  last element of a list.  %3last%2[%5NIL%2]%1 is
undefined in the LISP language; the result of trying  to  compute  it
may be an error message or may be some random result depending on the

	The function  %3subst%1  is defined by

	%3subst%2[%3x, y, z%2] ← %4if at %3z %4then %2[%4if %3z %4eq %3y %4then %3x %4else %3z%2]
			%4else %3subst%2[%3x, y, %4a %3z%2].%3subst%2[%3x, y, %4d %3z%2].

%1We have

	%3subst%2[%5(A.B), X, ((X.A).X)%2] =

		= %3subst%2[%5(A.B), X, (X.A)%2]%3subst%2[%5(A.B), X, X%2]

		= [%3subst%2[%5(A.B), X, X%2].%3subst%2[%5(A.B), X, A%2]].%5(A.B)

		%2= [[%5(A.B)%2].%5A%2].%5(A.B)%2]

		= %5(((A.B).A).(A.B)).
%3subst%1  computes the result of substituting the S-expression   %3x%1   for
the  atom  %3y%1  in the S-expression  %3z%1.  This is an important operation
in all kinds of symbolic computation.

	Another important operation is the  concatenation  of  lists,
and  it is generally denoted by the infixed expression  %3x%2*%3y%1  since it
is associative.  We have the examples

	%5(A B C)%2*%5(D E F) %2= %5(A B C D E F),


	%5NIL%2*%5(A B) %2= %5(A B) %2= %5(A B)%2*%5NIL,

%1and the formal definition

	%3x%2*%3y %2← %4if n %3x %4then %3y %4else %2[%4a %3x%2].[[%4d %3x%2]*%3y%2].

	%1The  Boolean  operations can also be used in making recursive
definitions  provided  we  observe  the  order   of   evaluation   of
constituents. First, we define a predicate  %3equal%1  by

	%3equal%2[%3x, y%2] ← %3x %4eq %3y %2∨ [¬%4at %3x %2∧ ¬%4at %3y %2∧
			%3equal%2[%4a %3x, %4a %3y%2] ∧ %3equal%2[%4d %3x, %4d %3y%2]].
%3equal%2[%3x, y%2]%1  is true  if  and  only  if   %3x%1   and   %3y%1   are  the  same
S-expression,  and  the  use  of this predicate makes up for the fact
that the basic predicate  %4eq%1  is guaranteed  to  test  equality  only
when  one  of the operands is known to be an atom.  We shall also use
the infixes  %2=%1  and  %2≠%1.

 	Membership of an S-expression  %3x%1  in a list  %3y%1  is tested by

	%3member%2[%3x, y%2] ← ¬%4n %3y %2∧ [[%3x %2= %4a %3y%2] ∨ %3member%2[%3x, %4d %3y%2]].

%1This relation is also denoted by  %3x%2ε%3y.  Here are some computations:

	%3member%2[%5B, (A B)%2] = ¬%4n %5(A B) %2∧ [[%5B %2= %4a %5(A B)%2]
			    ∨ %3member%2[%5B, %4d %5(A B)%2]],

			= %3member%2[%5B, (B)%2]

			= %5T.
	%1Sometimes  a  function  is defined with the help of auxiliary
functions.  Thus, the reverse of a list  %3x%1 , (e.g.   %3reverse%2[%5(A B C
D)%2] = %5(D C B A)%1), is given by

	%3reverse%2[%3x%2] ← %3rev%2[%3x, %5NIL%2]


	%3rev%2[%3x, y%2]   ← %4if n %3x %4then %3y %4else %3rev%2[%4d %3x%2, [%4a %3x%2].%3y%2].

%1A computation is

	%3reverse%2[%5(A B C)%2] = %3rev%2[%5(A B C), NIL%2]

 			 = %3rev%2[%5(B C), (A)%2]

			 = %3rev%2[%5(C), (B A)%2]

			 = %3rev%2[%5NIL, (C B A)%2]

			 = %5(C B A).

	%1A more elaborate example of recursive definition is given by

	%3flatten%2[%3x%2] ← %3flat%2[%3x, %5NIL%2]

	%3flat%2[%3x, y%2] ← %4if at %3x %4then %3x.y
			      %4else %3flat%2[%4a %3x, flat%2[%4d %3x, y%2]].

%1We have

	%3flatten%2[%5((A.B).C)%2] = %3flat%2[%5((A.B).C), NIL%2]

			   = %3flat%2[%5(A.B), %3flat%2[%5C, NIL%2]]

			   = %3flat%2[%5(A.B), (C)%2]

			   = %3flat%2[%5A, %3flat%2[%5B, (C)%2]]

			   = %3flat%2[%5A, (B C)%2]

			   = %5(A B C).
%1The  reader  will see that the value of  %3flatten%2[%3x%2]%1  is a list of the
atoms  of  the  S-expression   %3x%1    from   left   to   write.    Thus
%3flatten%2[%5((A B) A)%2] = %5(A B NIL A NIL)%1.

	Many  functions  can be conveniently written in more than one
way.  For example, the function   %3reverse%1   mentioned  above  can  be
written without an auxiliary function as follows:

	%3reverse%2[%3x%2] ← %4if n %3x %4then %5NIL %4else %3reverse%2[%4d %3x%2]*%5<a x>

%1but it will be explained later that the earlier  definition  involves
less computation.

	The use of conditional  expressions  for  recursive  function
definition  is  not  limited  to  functions  of  S-expressions.   For
example, the factorial function and the Euclidean algorithm  for  the
greatest common divisor are expressed as follows:

	%3n%2! ← %4if %3n%2=%50 %4then %51 %4else %3n%2(%3n%2-%51%2)!


	%3gcd%2(%3m, n%2) ← %4if %3m%2>%3n %4then %3gcd%2(%3n, m%2) %4else if %3m%2=%50 %4then %3n
			%4else %3gcd%2(%3n mod m, m%2)
%1where  %3n mod m%1  denotes the remainder when  %3n%1  is divided by  %3m%1   and
may itself be expressed recursively by

	%3n mod m %2← %4if %3n%2<%3m %4then %3n %4else %2(%3n%2-%3m%2) %3mod m.

%1                              Exercises

	1. Consider the function  %3drop%1  defined by

	%3drop%2[%3x%2] ← %4if n %3x %4then %5NIL %4else %2<%4a %3x%2>.%3drop%2[%4d %3x%2].

%1Compute (by hand)  %3drop%2[%5(A B C)%2]%1.  What does  %3drop%1  do  to  lists  in

	2. What does the function

	%3r2%2[%3x%2] ← %4if n %3x %4then %5NIL %4else %3reverse%2[%4a %3x%2].%3r2%2[%4d %3x%2]

%1do to lists of lists?  How about

	%3r3%2[%3x%2] ← %4if at %3x %4then %3x %4else %3reverse%2[%3r4%2[%3x%2]]

	%3r4%2[%3x%2] ← %4if n %3x %4then %5NIL %4else %3r3%2[%4a %3x%2].%3r4%2[%4d %3x%2]?

	%13. Compare

	%3r3'%2[%3x%2] ← %4if at %3x %4then %3x %4else %3r3'%2[%4d %3x%2]*<%3r3'%2[%4a %3x%2]>

%1with the function  %3r3%1  of the preceding example.

	4. Consider  %3r5%1  defined by

	%3r5%2[%3x%2] ← %4if n %3x %2∨ %4n d %3x %4then %3x
		%4else %2[%4a %3r5%2[%4d %3x%2]]
			. %3r5%2[%4a %3x . r5%2[%4d %3r5%2[%4d %3x%2]]].
%1Compute  %3r5%2[%5(A B C D)%2]%1.  What does  %5r5%1  do in general?   Needless  to
say, this is not a good way of computing this function even though it
involves no auxiliary functions.

.ss Lambda expressions and functions with functions as arguments.

	It is common to use phrases like "the function  2%3x%2+%3y%1".   This
is  not a precise notation because we cannot say  2%3x%2+%3y%2(%53, 4%2)%1  and know
whether the desired  result  is   2%Bπ.%13+4   or   2%Bπ.%14+3   regarding  the
expression  as a function of two variables.  Worse yet, we might have
meant a one-variable function of  %3x%1  wherein  %3y%1   is  regarded  as  a

	The problem  of  giving  names  to  functions  is  solved  by
Church's   λ-notation.    In   the  above  example,  we  would  write
%2λ%3x y%2: %52%3x%2+%3y%1  to denote  the  function  of  two  variables  with  first
argument   %3x%1   and  second  argument   %3y%1  whose value is given by the
expression  2%3x%2+%3y%1.  Thus,

	%2[λ%3x y%2: %52%3x%2+%3y%2][%53, 4%2] = %510%1.

%1Likewise,   %2[λ%3y x%2: %52%3x%2+%3y%2][%53, 4%2] = %511%1.  Like variables of integration
and the bound variables of quantifiers in logic, variables following   λ
are  bound  or dummy and the expression as a whole may be replaced by
any others provided the replacement is done consistently and does not
make  any  variable  bound  by  λ  the same as a free variable in the
expression.  Thus   %2λ%3x y%2: %52%3x%2+%3y%1   represents  the  same   function   as
%2λ%3y x%2: %52%3y%2+%3x%1 or %2λ%3u v%2: %52%3u%2+%3v%1 , but in the function of one argument
%2λ%3x%2: %52%3x%2+%3y%1 , we cannot replace the variable  %3x%1  by %3y%1 , though we could
replace it by  %3u%1.

	λ-notation plays two important  roles  in  LISP.   First,  it
allows us to rewrite an expression containing two or more occurrences
of the same sub-expression in such a way that the  expression  occurs
only once. Thus   %2(%52%3x%2+%51%2)↑%54%2+%53%2(%52%3x%2+%51%2)↑%53%1  can be written
%2[λ%3w%2: %3w%2↑%54%2+%53%3w%2↑%53%2][%52%3x%2+%51%2]%1. This can save considerable
computation, and
corresponds to the practice in ordinary programming of assigning to a
variable the value of a sub-expression that occurs more than once  in
an  expression  and  then  writing  the  expression  in  terms of the

	The second use of λ-expressions is in  using  functions  that
take functions as arguments.  Suppose we want to form a new list from
an old one by applying a function  %3f%1  to each element  of  the  list.
This can be done using the function  %3mapcar%1  defined by

	%3mapcar%2[%3x, f%2] ← %4if n %3x %4then %5NIL %4else %3f%2[%4a %3x%2]
 . %3mapcar%2[%4d %3x, f%2].

%1Suppose the operation we want to perform is squaring, and we want  to
apply it to the list  %5(1 2 3 4 5 6 7)%1.  We have

	%3mapcar%2[%5(1 2 3 4 5 6 7), %2λ%3x%2: %3x%2↑%52%2] = %5(1 4 9 16 25 36 49).

	%1A more generally useful operation than  %3mapcar%1 is %3maplist%1
in  which  the  function is applied to the successive sublists of the
list rather than to the elements.  %3maplist%1  is defined by

	%3maplist%2[%3x, f%2] ← %4if n %3x %4then %5NIL %4else %3f%2[%3x%2]
 . %3maplist%2[%4d %3x, f%2].

	%1As  an  application  of  %3maplist%1 and functional arguments, we
shall define a function  for  differentiating  algebraic  expressions
involving sums and products.  The expressions are built up from atoms
denoting variables and integer constants according to the syntax

	<expression> ::= <variable> | <integer> |
			 (PLUS <explist>) | (TIMES <explist>)

	<explist>    ::= <expression> | <expression><explist>
Here,  %5PLUS%1  followed by a list of arguments denotes the sum of these
arguments and  %5TIMES%1  followed by a list of arguments  denotes  their
product.   The  function   %3diff%2[%3e, v%2]%1  gives the partial derivative of
the expression  %3e%1  with respect to the variable  %3v%1. We have

	%3diff%2[%3e, v%2] ← %4if at %3e %4then %2[%4if %3e %4eq %3v %4then %51 %4else %50%2]
		%4else if a %3e %4eq %5PLUS %4then
			%5PLUS . %3mapcar%2[%4d %3e%2, λ%3x%2: %3diff%2[%3x, v%2]_]
		%4else if a %3e %4eq %5TIMES %3then
			%5PLUS.%3maplist%2[%4d %3e%2, λ%3x%2: %5TIMES
  			      .	%3maplist%2[%4d %3e%2, λ%3y%2: %4if %3x %4eq %3y %4then
					%3diff%2[%4a %3y, v%2] %4else a %3y%2]].
%1The  term  that  describes  the  rule  for  differentiating  products
corresponds to the rule

	%2∂/∂%3v    %3e%6i%2 =       [%4if %3i%2=%3j %4then %2∂%3e%6j%2/∂%3v %4else %3e%6j%2].

and   %3maplist%1   has  to be used rather than  %3mapcar%1  since whether to
differentiate in forming the product is determined by equality of the
indices   %3i%1   and   %3j%1   rather  than equality of the terms  %3e%6i%1  and

	Two more useful functions with functions as arguments are the
predicates  %3andlis%1  and  %3orlis%1  defined by the equations

	%3andlis%2[%3u, p%2] ← %4n %3u %2∨ [%3p%2[%4a %3u%2] ∧ %3andlis%2[%4d %3u, p%2]]


	%3orlis%2[%3u, p%2] ← ¬%4n %3u %2∧ [%3p%2[%4a %3u%2] ∨ %3orlis%2[%4d %3u, p%2]].

%1                              Exercises

	1. Compute  %3diff%2[%5(TIMES X (PLUS Y 1) 3), X%2]%1  using  the  above
definition  of  %3diff%1.  Now do you see why algebraic simplification is

	2. Compute  %3orlis%2[%5((A B) (C D) E), %4at%2]%1.

.ss Label.

	The λ mechanism is  not  adequate  for  providing  names  for
recursive  functions,  because  in this case there has to be a way of
referring to the function name within the  function.   Therefore,  we
use  the notation  %4label%2[%3f, e%2]%1  to denote the expression  %3e%1  but where
occurrences of  %3f%1  within  %3e%1  refer  to  the  whole  expression.  For
example,  suppose we wished to define a function that takes alternate
elements of each element of a list and makes a list of these.   Thus,
we want

	%3glub%2[%5((A B C) (A B C D) (X Y Z))%2] = %5((A C) (A C) (X Z)).

%1We can make the definition

	%3glub%2[%3x%2] ← %3mapcar%2[%3x, %4label%2[%3alt%2, λ%3x%2: %4if n %3x %2∨ %4n d %3x %4then %3x
					%4else a %3x . alt%2[%4dd %3x%2]]].
%1The identifier  %3alt%1  in the above example is bound by the  label  and
is  local  to  that  expression,  and  this is the general rule.  The
label  construction is not often used in LISP since it is more usual
to  give functions global definitions. D. M. R. Park pointed out that
if we allow variables to represent functions and use a  suitable   λ
construction, the use of  label  could be avoided.

.ss Static and dynamic ways of programming.

	In  order  to  write recursive function definitions, one must
think about programming differently than is  customary  when  writing
programs  in  languages like Fortran or Algol or in machine language.
In these languages, one has in mind the state of the  computation  as
represented  by  the  values of certain variables or locations in the
memory of the machine, and then  one  writes  statements  or  machine
instructions in order to make the state change in an appropriate way.

	When writing LISP recursive functions one thinks differently.
Namely, one thinks about the value of the  function,  asks  for  what
values  of the arguments the value of the function is immediate, and,
given  an  arbitrary  values  of  the  arguments,  for  what  simpler
arguments  must  the  function be known in order to give the value of
the function for  the  given  arguments.  Let  us  take  a  numerical
example;  namely,  suppose  we want to compute the function  %3n%2!%1.  For
what argument is the value of the function immediate.   Clearly,  for
%3n %2= %50  or  %3n %2= %51%1, the value is immediately seen to be  1.  Moreover,
we can get the value for an arbitrary  %3n%*  if we know  the  value  for
%3n%2-%51.   Also, we see that knowing the value for  %3n %2= %51  is redundant,
since it can be obtained from the  %3n %2= %50  case by the  same  rule  as
gets  it  for  a  general  %3n%*  from the value for  %3n%2-%51%1.  All this talk
leads to the simple recursive formula:

	%3n%2! ← %4if %3n %2= %50 %4then %51 %4else %3n%2(%3n%2-%51%2)!.

	%1We may regard this as a static way of looking at programming.
We ask what simpler cases the general case of our function depends on
rather  than  how  we  build up the desired state of the computation.
One often is led to believe that  static = bad  and   dynamic = good,
but  in  this  case,  the static way is often better than the dynamic
way.  LISP offers  both,  but  since  it  is  less  usual,  we  shall
concentrate on the static way for now.

	Compare  the  above  recursive  definition with the following
obvious Algol program for computing  %3n%2!:

	%4integer procedure %3factorial%2(%3n%2); %4integer %3s%2;
	%3s %2:= %51%2;
%3loop%2:	%4if %3n %2= %50 %4then go to %3done%2;
	%3s %2:= %3n%2*%3s%2;
	%3n %2:= %3n%2-%51%2;
	%4go to %3loop%2;
%3done%2:	%3factorial %2:= %3s%2;
	%1The  LISP program is shorter and clearer in this particularly
favorable  case.   Actually,  when  we  discuss  the   mechanism   of
recursion, it will turn out that the LISP program will be inefficient
in using the pushdown mechanism unnecessarily and should be  replaced
by  the  following  somewhat  longer  program that corresponds to the
above Algol program rather precisely:

	%3n%2! ← %3fact%2(%3n%2, %3s%2),


	%3fact%2(%3n%2, %3s%2) ← %4if %3n %2= %50 %4then %3s %4else %3fact%2(%3n%2-%51%2, %3n%2*%3s%2).

%1In  fact,  compilers should produce the same object code from the two
.ss Simple list recursion.

	About the simplest form of recursion in LISP occurs when  one
of the arguments is a list, the result is immediate when the argument
is null, and otherwise we need only know the result for the %4d%*-part of
that argument.  Consider, for example,  %3u%2*%3v%1, the concatenation of the
lists  %3u%*  and %3v%*.  The result is immediate for  the  case   %4n %3u%1   and
otherwise depends on the result for  %4d %3u%1.  Thus, we have

	%3u%2*%3v %2← %4if n %3u %4then %3v %4else a %3u %2. [%4d %3u %2* %3v%2].

%1On the other hand, if we had tried to recur on  %3v%1  rather than on  %3u%1
we would not have been successful.  The result would be immediate for
%4n %3v%1, but  %3u%2*%3v%1  cannot be constructed in any direct way from   %3u%2*%4d %3v%1
without  a  function  that  puts  an  element onto the end of a list.
(From a strictly list point of view, such  a  function  would  be  as
elementary  as  %3cons%1  which puts an element onto the front of a list,
but, when we consider the implementation of lists by list structures,
we  see  that  the  function is not so elementary.  This has led some
people to construct systems in which lists are  bi-directional,  but,
in  the  main,  this has turned out to be a bad idea).  Anyway, it is
usually easier to recur on one argument of a function than  to  recur
on the other.

	It  is  often necessary to represent a correspondence between
the elements of a small set of atoms and certain  S-expressions  by  a
list structure.  This is conveniently done by means of an association
list which is a list of pairs, each pair consisting of  an  atom  and
the corresponding S-expression. Thus the association list

	%5((X . (PLUS A B)) (Y . C) (Z . (TIMES U V)),

%1which would print as

	%5((X PLUS A B)) (Y . C) (Z TIMES U V)),

%1pairs  %5X%1  with  %5(PLUS A B),  Y%1  with  %5C%1, etc. We need a  function  to
tell  whether  anything  is  associated  with  the  atom   %3x%1   in the
association list  %3a%1, and, if so, to tell us what. We have

	%3assoc%2[%3x, a%2] ← %4if n %3a %4then %5NIL %4else if %3x %4eq aa %3a %4then a %3a
		%4else %3assoc%2[%3x, %4d %3a%2].
%1Its value is   %5NIL%1   if  nothing  is  associated  with   %3x%1   and  the
association pair otherwise.  E.g.  %3assoc%2[%5X, ((X.W) (Y.V))%2] = %5(X.W)%1.

	It  commonly happens that a function has no simple recursion,
but there is a simple recursion for a function with one more variable
that  reduces  to the desired function when the extra variable is set
to %5NIL%1.  Thus

	%3reverse%2[%3u%2] ← %3rev1%2[%3x, %5NIL%2],


	%3rev1%2[%3u, v%2] ← %4if n %3u %4then %3v %4else %3rev1%2[%4d %3u, %4a %3u . v%2].

%3reverse%1 has a direct recursive definition as discovered by S. Ness,
but no-one would want to use the following in actual computation  nor
does  it generate much understanding, only appreciation of Mr. Ness's

	%3reverse%2[%3u%2] ← %4if n %3u %2∨ %4n d %3u %4then %3u %4else
		a %3reverse%2[%4d %3u%2] . %3reverse%2[%4a %3u. %3reverse%2[%4d %3reverse%2[%4d %3u%2]]].


	1. Using the function  %3member%2[%3x, u%2]%1  defined in Chapter I
which  may also be written  %3x %2ε %3u%1, write function definitions for the
union  %3u %2∪ %3v%1  of lists  %3u%1  and  %3v%1, the intersection  %3u %2∩ %3v%1,  and  the
set  difference   %3u%2-%3v%1.    What  is  wanted  should  be clear from the

	%5(A B C) %2∪%5 (B C D) %2=%5 (A B C D),

	(A B C) %2∩%5 (B C D) %2=%5 (B C),


	%5(A B C) %2-%5 (B C D) %2=%5 (A).

%1Pay  attention  to getting correct the trivial cases in which some of
the arguments are %5NIL%1.  In general, it  is  important  to  understand
clearly the trivial cases of functions.

	2.  Suppose   %3x%1   takes  numbers  as  values and  %3u%1  takes as
values lists of numbers in ascending order, e.g.  %5(2 4 7)%1.   Write  a
function   %3merge%2[%3x, u%2]%1   whose  value  is obtained from that of  %3u%1  by
putting     %3x%1     in     %3u%1     in    its    proper    place.     Thus
%3merge%2[%53, (2 4)%2] = %5(2 3 4)%1, and  %3merge%2[%53, (2 3)%2] = %5(2 3 3)%1.

	3.  Write  functions  giving the union, intersection, and set
difference of ordered lists; the result is wanted as an ordered list.

	Note that computing these functions of unordered lists  takes
a  number  of comparisons proportional to the square of the number of
elements of a typical list, while for ordered lists,  the  number  of
comparisons is proportional to the number of elements.

	4.  Using   %3merge%1, write a function  %3sort%1  that transforms an
unordered list into an ordered list.

	5. Write a function  %3goodsort%1  that  sorts  a  list  using  a
number  of  comparisons  proportional  to   %3n log n%1, where  %3n%1  is the
length of the list to be sorted.

.ss Simple S-expression recursion.

	In another class of problems, the value of  the  function  is
immediate  for  atomic symbols, and for non atoms depends only on the
values for  the a-part and the d-part of the argument.  Thus   %3subst%1
was defined by

	%3subst%2[%3x, y, z%2] ← %4if at %3z %4then %2[%4if %3z %4eq %3y %4then %3x %4else %3z%2]
			%4else %3subst%2[%3x, y, %4a %3z%2] . %3subst%2[%3x , y , %4d %3z%2].
	%1Two other examples are  %3equal%1  which gives  the  equality  of
S-expressions  and   %3flat%1  which spreads an S-expression into a list
of atoms:  They are defined by

	%3x%2=%3y %2← %3x %4eq %3y %2∨ [¬%4at %3x %2∧ ¬%4at %3y %2∧ %4a %3x %2= %4a %3y %2∧ %4d %3x %2= %4d %3y%2],


	%3flat%2[%3x%2] ← %3flata%2[%3x, %5NIL%2]


	%3flata%2[%3x, u%2] ← %4if at %3x %4then %3x.y %4else %3flata%2[%4a %3x, flata%2[%4d %3x, y%2]].


	1. Write a predicate to tell whether a given atom occurs in a
given S-expression, e.g.  %3occur%2[%5B, ((A.B).C)%2] = %5T%1.

	2. Write a predicate to tell how  many  times  a  given  atom
occurs in an S-expression.

	3.  Write  a  function to make a list without duplications of
the atoms occurring in an S-expression.

	4. Write a function to make a list of all  atoms  that  occur
more   than   once   in   a  given  S-expression  paired  with  their

	5. Write a predicate to tell whether an S-expression has more
than one occurrence of a given S-expression as a sub-expression.

.ss Other structural recursions.

	When lists are used to represent algebraic expressions,
functions of these algebraic expressions often have a
recursive form closely related to the inductive definition of the
expressions.  Suppose, for example, that sums and products are represented
respectively by the forms  %5(PLUS X Y)%1  and  %5(TIMES X Y)%1  and that the
values of variables are given on an a-list.  We can write a recursive
formula for the value of an expression as follows:

	%3value%2[%3e, a%2] ← %4if at %3e %4then d %3assoc%2[%3e, a%2]
		%4else if a %3e %4eq %5PLUS %4then %3value%2[%4ad %3e, a%2] + %3value%2[%4add %3e, a%2]
		%4else if a %3e %4eq %5TIMES %4then %3value%2[%4ad %3e, a%2] * %3value%2[%4add %3e, a%2].
%1On the other hand, suppose that sums and products are not restricted
to have just two arguments; then we must use auxiliary functions
to define the value of an expression, as follows:

	%3value%2[%3e, a%2] ← %4if at %3e %4then d %3assoc%2[%3e, a%2]
			%4else if a %3e %4eq %5PLUS %4then %3vplus%2[%4d %3e, a%2]
			%4else if a %3e %4eq %5TIMES %4then %3vtimes%2[%4d %3e, a%2].


	%3vplus%2[%3u, a%2] ← %4if n %3u %4then %50 %4else %3value%2[%4a %3u, a%2] + %3vplus%2[%4d %3u, a%2],


	%3vtimes%2[%3u, a%2] ← %4if n %3u %4then %51 %4else %3value%2[%4a %3u, a%2] * %3vtimes%2[%4d %3u, a%2].
%1In both cases, the recursion form is related to the structure of the
algebraic expressions more closely than to the structure of
S-expressions or lists.
.AT "\J" ⊂FILL⊃ ;
.AT "\." ⊂NOFILL⊃ ;
.turn on "↔" for "←" ;
.<<\\M0NGR25;\M1BDJ25;\M2BDR25X;\M3SUB;\M4NGR30;\M5NGR40;\M6SUP;%1 >>
.ss Tree search.

\J	We begin with a general depth first tree search function.
It can be used to search specific trees of possibilities by defining
three auxiliary functions in a way that depends on the application.
We have\.

	%3search p %2← %4if %3lose p %4then %1LOSE
			 %4else if %3ter p %4then %3p %4else %3searchlis%2[%*successors p%2]%1


\J	%3searchlis u %2← %4 if n %3u %4then %1LOSE %4else %3%2{%*search %4a
 %3u%2}[%*λx%2:%* %4if %3x %2= %1LOSE %4then %3searchlis %4d %3u %4else %3x%2]%*.%1\.

\JIn the applications, we  start with a position %3p%60%1,  and we
are looking for  a win in the successor tree of %3p%60%1.  Certain
positions lose and  there is  no point looking  at their  successors.
This is decided  by the predicate %3lose%1. A position  is a win if
it  doesn't  lose  and  it  satisfies  the  predicate %3ter%1.  The
successors of a position  is given by the  function %3successors%1,
and  the  value  of %3search  p%1  is  the  winning position.    No
non-losing position should have the  name LOSE or the function  won't
work properly.

	Our first example is  finding a path from an  initial node to
a final node  in a graph represented by a list structure as described
in chapter I.   A position is a path  starting from the initial  node
and  continuing to  some intermediate  node and  is represented  by a
list  of its nodes  in reverse order.   The three  functions for this
application are\.

	%3lose p %2← %4a %3p %2ε %4d %3p,

	ter p %2← [%4a %3p %2=%* final%2]%*, %1


	%3successors p %2←%* mapcar%2[%4d %3assoc%2[%4a %3p, graph%2]%*, λx%2:%* x.p%2]%*.%1

\J	Another example is the so-called %3Instant Insanity%1 puzzle.
There are four cubical blocks, and each face of each block is colored with
one of four colors.  The object of the puzzle is to build a tower of all four
blocks such that each vertical face of the tower involves all four colors.
In order to use the above defined function %3search%1 for this purpose,
we must define the representation of positions and give the functions
%3lose, ter, %1and %3successors%1.  A position is represented by a list
of lists ¬ one for each face of the tower.  Each sublist is the list of colors
of the faces of the blocks showing in that face.  We shall assume that the
blocks are described in the following longwinded but convenient way.  (We'll
take up precomputing this description later.)  For each block there is a list
of the 24 orientations of the block where each orientation is described as
a list of the colors around the vertical faces of the block when it is in that
orientation.  Thus the puzzle is described by a list of lists of lists which
we shall call %3puzz%1.\.

	We now have

	%3p%60%1 %2=%* (NIL NIL NIL NIL),

	%3lose p %2←%* orlis%2[%*p, λu%2:%* %4a %3u %2ε %4d %3u%2]%*,

	ter p %2← [%*length %4a %3p %2=%* 4%2]%1,


\J	%3successors p %2←%* mapcar%2[%4a %3nth%2[%*puzz, 1 + length %4a %3p%2]%*
, λx%2:%* mapcar2%2[%*p, x, λyz%2:%* z.y%2]]%*, %1\.


\J	%3mapcar2%2[%*u, v, f%2] ← %3if n %3u %4then %1NIL %4else
f%2[%4a %3u, %4a %3v%2]%* . mapcar2%2[%4d %3u, %4d %3v, f%2]%*.%1\.

\J	Getting the initial position in the desired form is as complicated
a computation as the actual tree search.  It can be
conveniently done by a sequence of assignment
statements starting with a description of the blocks: \.

	%3puzz1 %2← %1((G B B W R G) (G G B G W R) (G W W R B R) (G G R B W W)).

\JHere each block is represented by a list of the colors of the faces starting
with the top face, going around the sides in a clockwise direction and
finishing with the bottom face.

	We need to go from this description of the blocks to a list of the
possible cycles of colors on the vertical faces for the 24 orientations of
the block.  This not easy, because the order in which we have given the colors
is not invariant under rotations of the block.  An easy way out is to start with
a block whose faces are assigned the numbers 1 thru 6 starting with the top,
going clockwise around the sides and finishing with the bottom.  We write down
one cycle of side colors for each choice of the face put on top and get the
list of all 24 cycles by appending the results of generating the cyclic
permutations of the cycles.  All this is accomplished by the assignment\.

\J	%3puzz2 %2←%* cycles%2[%1(2 3 4 5)%2]%*%2*%*%3cycles%2[%*(%1(2 5 4 3)%2]%*%2*%*
%3cycles%2[%*(1 2 6 4)%2]%*\.
	          %2*%*cycles%2[%*(1 4 6 2)%2]%*%2*%*cycles%2[%*(1 3 6 5)%2]%*%2*%*cycles%2[%*(1 5 6 3)%2]%*, %1

where the function %3cycles%1 is defined by

	%3cycles u %2←%* maplist%2[%*u, λx%2:%* x%2*%*upto%2[%*u, x%2]]%1

with the auxiliary function

\J	%3upto%2[%*u, x%2] ← %4if %3x %4eq %3u %4then %1NIL %4else a
 %3u . upto%2[%4d %3u, x%2]%*.%1\.

\JNext we create for each block a list of substitutions expressing the
colors of the six numbered faces.  We have\.

	%3puzz3 %2←%* mapcar%2[%*puzz1, λx%2:%* prup%2[%1(1 2 3 4 5 6), %3x%2]]%*, %1

\Jand we use these substitutions to get for each block the list of 24 orientations
of the block. Thus\.

	%3puzz4 %2←%* mapcar%2[%*puzz3, λs%2:%* sublis%2[%*s, puzz3%2]]%*.

\Jpuzz4%1 has all 24 orientations of the first block while for symmetry reasons
we need only consider three as distinct, say the first, ninth, and seventeen.  So
we finally get\.

\J	%3puzz %2←%* (%4a %3nth%2[%4a %3puzz4, 1%2] %4a %3nth%2[%4a %3puzz4, 9%2]%*
%4a %3nth%2[%4a %3puzz4, 17%2]%*) . %4d %3puzz4.%1\.

\JThe program when compiled runs about 11 seconds on the PDP-10.

	A more sophisticated representation of face cycles and partial towers
makes a factor of ten speedup without changing the basic search algorithm.  A
face cycle is represented by 16 bits in a word four for each face a particular
one of which being turned on tells us the color of the face.  If we %4or%1
these words together for the blocks in a partial tower we get a word which
tells us for each face of the tower what colors have been used.  A
particular face cycle from the next block can be added to the tower if
the %4and%1 of its word with the word representing the tower is zero.
We represent a position by a list of words representing its partial
towers with 0 as the last element and the highest partial tower as the
first element.  The virtue of this representation is that it makes
the description of the algorithm short.
The initial position is (0).  The new %3puzz%1 can be formed from the
old one by the assignment\.

	%3puzza %2←%* mapcar%2[%*puzz, λx%2:%* mapcar%2[%*x, zap%2]]%*, %1


\J	%3zap v %2← %4if n %3v %4then %30 %4else %3poo %4a %3v +
16zap %4d %3v, %1\.


\J	%3poo x %2← %4if %3x%2=%1R %4then %31 %4else if %3x%2=%1W %4then
 %12 %4else if %3x%2=%1G %4then %14 %4else %18.\.

\JNow we need the new functions %3lose, ter, %1and
%3successors%1.  These are\.

	%3lose p %2← %4false%3,

	%3ter p %2← [%*length p %2=%* 5%2]%*, %1


\J	%3successors p %2←%* mapchoose%2[%4a %3nth%2[%*puzza, length p%2]%*,
λx%2:%* %4a %3p %4and %3x %2=%* 0, λx%2:%* %2[%4a %3p %4or %3x%2]%* . p%2]%*.%1\.


	%3mapchoose%2[%*u, pred, fn%2] ← %4if n %3u %4then %1NIL
\J		%4else if
%3pred %4a %3u %4then %3fn%2[%4a %3u%2]%* . mapchoose%2[%4d %3u
, pred, fn%2] %4\.
		else %3mapchoose%2[%4d %3u, pred, fn%2]%*.%1

\J%3lose%1 is trivial, because the %3mapchoose%1 is used to make sure
that only non-losing new positions are generated by %3successors%1.
This version runs in a little less than one second on the PDP-10.  A greater
speedup can be made by the application of some mathematics.  In fact, with
enough mathematics, extensive tree search is unnecessary in this problem.

	%3search%1 is used when we want to search a tree of possibilities
for a solution to a problem.  What if we want to find all solutions
to a problem?  This can be done with a function %3allsol%1 that uses
the same %3lose, ter, %1and %3successors%1 functions as does %3search%1.
The simplest way to write %3allsol%1 is\.

\J	%3allsol p %2← %4if %3lose p %4then %1NIL %4else if %3ter p
 %4then %3(p) %4else %3mapapp%2[%*successors p, allsol%2]%*, %1\.

\J	%3mapapp%2[%*u, fn%2] ← %4if n %3u %4then %1NIL %4else
%3fn%2[%4a %3u%2]%* . mappap%2[%4d %3u, fn%2]%*.%1\.

\JThis form of the function is somewhat inefficient because of all the
%3append%1ing.  A more efficient form uses an auxiliary function as follows: \.

	%3allsol p %2←%* allsola%2[%*p, %1NIL%2]%*

	%3allsola%2[%*p, found%2] ← %4if %3lose p %4then %3found
					%4else if %3ter p %4then %3p . found
					%4else %3allsolb%2[%*successors p, found%2]%*,

\J	%3allsolb%2[%*u, found%2] ← %4if n %3u %4then %3found
%4else %3allsolb%2[%4d %3u, allsola%2[%4a %3u, found%2]]%*.%1\.

\JThe recursive program structure that arises here is common when a list
is to be formed by recurring through a list structure.\.
.ss Game trees.

\J	The positions that can be reached from an initial position in
a  game  form  a  tree, and deciding what move to make often involves
searching this tree.  However, game trees are searched in a different
way  than the trees we have looked at, because the opposing interests
of the players makes it not a search for a joint line  of  play  that
will  lead  to  the  first  player winning, but rather a search for a
strategy that will lead to a win regardless of what the other  player

	The   simplest  situation  is  characterized  by  a  function
%3successors%1 that gives the positions that can be reached in  one
move,  a  predicate  %3ter%1  that  tells  when a position is to be
regarded  as  terminal  for  the  given  analysis,  and  a   function
%3imval%1  that  gives  a  number  approximating  the  value  of the
position to one of the  players.   We  shall  call  this  player  the
maximizing  player  and  his opponent the minimizing player. Usually,
the numerical values arise, because the search cannot be carried  out
to the end of the game, and the analysis stops with reasonably static
positions that  can  be  evaluated  by  some  rule.   Naturally,  the
function  %3imval%1  is  chosen  to  be  easy  to  calculate and to
correlate well with the probability that the  maximizing  player  can
win the position.

	The simplest rule for finding the correct move in a position
uses auxiliary functions
%3valmax%1 and %3valmin%1 that give a value to a position
by using %3imval%1 if the position is terminal and taking the max
or min of the successor positions otherwise.

	For this we want functions for getting the maximum or the
minimum of a function on a list, and they are defined as follows: \.

\J	%3maxlis%2[%*u, f%2] ← %4if n %3u %4then %3-%2∞%* %4else %3
max%2[%*f%2[%4a %3u%2]%*, maxlis%2[%4d %3u, f%2]]%*, %1\.


\J	%3minlis%2[%*u, f%2] ← %4if n %3u %4then %3%2∞%* %4else %3
min%2[%*f%2[%4a %3u%2]%*, minlis%2[%4d %3u, f%2]]%*.%1\.

\JIn these functions, -%2∞%* and %2∞%* represent numbers that are smaller and
larger than any actual values that will occur in evaluating %3f%1.
If these numbers are not available, then it is necessary to prime
the function with the values of %3f%1 applied to the first element
of the list, and the functions are meaningless for null lists.
Iterative versions of the functions are generally better; we give only
the iterative version of %3maxlis%1, namely\.

	%3maxlis%2[%*u, f%2] ←%* maxlisa%2[%*u, -%2∞%*, f%2]%*, %1


\J	%3maxlisa%2[%*u, x, f%2] ← %3if n %3u %4then %3x %4else
%3maxlisa%2[%4d %3u, max%2[%*x, f%2[%4a %3u%2]]%*, f%2]%*.%1\.

We now have

\J	%3valmax p %2← %4if %3ter p %4then %3imval p %4else
%3maxlis%2[%*successors p, valmin%2]%1, \.


\J	%3valmin p %2← %4if %3ter p %4then %3imval p %4else
%3minlis%2[%*successors p, valmax%2]%1.\.

The best move is now chosen by

	%3movemax p %2←%* bestmax%2[%*succesors p, valmin%2]%*, %1


	%3movemin p %2←%* bestmin%2[%*succesors p, valmax%2]%*, %1


	%3bestmax%2[%*u, f%2] ←%* bestmaxa%2[%4d %3u, %4a %3u, f%2[%4a %3u%2]%*, f%2]%*,

	%3bestmaxa%2[%*u, sofar, valsofar, f%2] ← %4if n %3u %4then %3sofar
\J		%4else if %3f%2[%4a %3u%2] ≤ %3bestsofar %4then
%3bestmaxa%2[%4d %3u, sofar, bestsofar, f%2]%*\.
		%4else %3bestmaxa%2[%4d %3u, %4a %3u, f%2[%4a %3u%2]%*, f%2]%*,

	%3bestmin%2[%*u, f%2] ←%* bestmina%2[%4d %3u, %4a %3u, f%2[%4a %3u%2]%*, f%2]%*, %1


	%3bestmina%2[%*u, sofar, valsofar, f%2] ← %4if n %3u %4then %3sofar
\J		%4else if %3f%2[%4a %3u%2] ≥ %3bestsofar %4then
%3bestmina%2[%4d %3u, sofar, bestsofar, f%2]%*\.
		%4else %3bestmina%2[%4d %3u, %4a %3u, f%2[%4a %3u%2]%*, f%2]%*.%1

\J	However, this straight minimax computation of the best move does
much more computation in general than is usually necessary.  The simplest
way to see this is from the move tree of Figure 2.6.\.
↔Figure 2.6
\JWe see from this figure that it is unnecessary to examine the moves marked
x, because their values have no effect on the value of the game or on the
correct move since the presence of the 9 is sufficient information at this
point to show that the move leading to the vertex preceding it should not
be chosen by the minimizing player.

	The general situation is that it is unnecessary to examine further
moves in a position once a move is found that refutes moving to the
position in the first place.  This idea is called the αβ-heuristic and
expressed in the following recursive definitions: \.

	%3maxval p %2←%* maxval1%2[%*p, -%2∞%*, %2∞%*%2]%*,

\J	  maxval1%2[%*p, α, β%2] ← %4if %3ter p %4then %3max%2[%*α, min%2[%*β, imval p%2]]%*
 %4else %3maxval2%2[%*successors p, α, β%2]%*, \.

\J	  maxval2%2[%*u, α, β%2] ← {%*minval1%2[%4a %3u, α, β%2]}[%*λw%2:%* %4if %3w %2=%* β %4then
 %3β %4else %3maxval2%2[%4d %3u, w, β%2]]%*, \.

	%3minval p %2←%* minval1%2[%*p, -%2∞%*, %2∞%*%2]%*,

\J	  minval1%2[%*p, α, β%2] ← %4if %3ter p %4then %3max%2[%*α, min%2[%*β, imval p%2]]%*
 %4else %3minval2%2[%*successors p, α, β%2]%*, \.

\J	  minval2%2[%*u, α, β%2] ← {%*maxval1%2[%4a %3u, α, β%2]}[%*λw%2:%* %4if %3w %2=%* α %4then
 %3α %4else %3minval2%2[%4d %3u, α, w%2]%*.%1\.

\J	The reduction in number of positions examined given by the αβ algorithm
over the simple minimax algorithm depends on the order in which the moves are
examined.  In the worst case, the moves happen to be examined in inverse order
of merit in every position on the tree, i.e. the worst move first.  In that case,
there is no improvement over minimax.  The best case is the one in which the
best move in every position is examined first.  If we look %3n%1 moves
deep on a tree that has %3k%1 successors to each position, then minimax looks
at %3k%7n%1 positions while αβ looks at about only %3k%7n/2%1.  Thus a
program that looks at 10%74%1 moves with αβ might have to look at 10%78%1
with minimax.  For this reason, game playing programs using αβ make a big
effort to include as good as possible an ordering of moves into the %3successors%1
function.  When there is a deep tree search to be done, the way to make the
ordering is with a short look-ahead to a much smaller depth than the main
search.  Still shorter look-aheads are used deeper in the tree, and beyond
a certain depth, non-look-ahead ordering methods are of decreasing complexity.

	A version of αβ incorporating optimistic and pessimistic evaluations
of positions was first proposed by McCarthy about 1958.  Edwards and Hart at
M.I.T. about 1959 proved that the present version of αβ works and calculated the
improvement it gives over minimax.  The first publication, however, was
Brudno (1963).  It is worth noting that αβ was not used in the early chess
playing programs in spite of the fact that it is clearly used in any human
play.  Its non-use, therefore, represents a failure of self-observation.
Very likely, there are a number of other algorithms used in human thought
that we have not noticed an incorporated in our programs.  To the extent
that this is so, artificial intelligence will be %3a posteriori%1 obvious
even though it is %3a priori%1 very difficult.\.