Last time we finished up talking about how practically everything in LISP
is a list, and we introduced FIRST, REST, and CONS as list operations,
and did some examples with this

   A  ->  ( X Y Z 4 )

Box-and-pointer notation

Now you're comfortable, I hope, with the notion that (X Y Z 4) is a list, but 
unlike Pascal and other languages, LISP doesn't require you to worry about 
the pointer details.  But sometimes, LISP folks like to see the pointers to 
help understand what's going on.  So here's a more tangible (i.e., less 
abstract) picture of what our sample list looks like:

A  
|
|
|    _______       _______       _______       _______
+-->|   |   |     |   |   |     |   |   |     |   |  /|     
    | | | --+---->| | | --+---->| | | --+---->| | | / |     
    |_|_|___|     |_|_|___|     |_|_|___|     |_|_|/__|     
      |             |             |             |
      X             Y             Z             4

In this lovely figure, each element of the list is represented as a pair of 
words in memory.  The first or left word contains a pointer to the symbol 
that "is" the first element, and the second or right word contains a pointer 
to the next element.  It's now easy to see that, given a pointer to this list, 
the function "first" (e.g., (first A)) looks at the pair of words at the end 
of that pointer, follows the pointer stored in the left word, and returns 
what's at the end of that pointer.  In this case, it's the symbol X.  
The "rest" function (e.g., (rest A)) looks at the pair of words pointed at by 
A, follows the pointer stored in the right word, and returns what's at the 
end of that pointer, which in this case is the list (Y Z 4).  Note again that 
these operations didn't change the structure of the list, they merely followed 
pointers and returned what they pointed to.

Each of these two-word pairs are called "cons cells", because it's what you 
get when you "cons" two things together.  (This is where the dynamic memory 
allocation mechanism comes into play.)

Earlier, I said that the second argument to the "cons" function should be a 
list, but I lied for the sake of simplicity.  You can in fact have something 
that's not a list as the second argument to a "cons" function, but the result 
is something slightly weird, called a "dotted pair".  For example:

   ? (cons 'A 'B)
   (A . B)

The box-and-pointer notation for this dotted pair looks like this:

     _______      
    |   |   |     
    | | | --+---->B
    |_|_|___|     
      |           
      A           

You used to see dotted pairs used a lot in LISP programming, but they're not 
used as frequently any more (except in some circumstances, which we might get 
to in this course).  I personally interpret these as meaning that I "cons'ed" 
two things together that I didn't mean to.  And that happens more often
than I like to admit.


The wonderful world of nil

What's the technical difference between the list and the dotted pair?  It's 
how they are terminated.  A "well-formed" list always ends with something 
called "nil", which we represented in the box-and-pointer diagram last time 
with a big slash through the right word of the last element.  A dotted pair, 
on the other hand, ends with something other than "nil".  

So what's a nil?  A nil is a very special thing in LISP.  First, it has the 
unusual property of being both an atom and a list at the same time.  What 
kind of list?  It's the empty list, represented by "()".  Consequently, "nil" 
and "()" are the same thing.  It's also the symbol meaning Boolean "false" in 
LISP (Boolean "true" is the predefined "T" or anything non-nil).  And, as we 
noted just above, it's always the end of a "well-formed" list, which allows 
LISP to maintain the following sorts of consistencies:  

The first element of the empty list is, naturally, nothing, which is nil, 
which is the empty list:

   ? (first nil)
   NIL

The rest of the empty list, which is just the empty list with the first 
element (i.e., nothing) removed, is also the empty list:

   ? (rest nil)
   NIL

But if we try to put (first nil) and (rest nil) back together using "cons", 
we should get the original thing we started with, which was nil, no?  No:

   ? (cons (first nil) (rest nil))
   (NIL)

It's a result of the unique nature of nil in LISP.  Think of it as one of 
LISP's endearing idiosyncracies.  


The conditional

A programming language really isn't worth much if there's no 
way to change the flow of program control.  Being able to 
take different branches depending on the results of some test 
is what makes computer programs useful.  Without conditionals,
computing in general would be really boring.  The basic mechanism 
for doing this is called the "conditional", and in LISP the 
fundamental conditional is called "cond".  Here's the syntax:

(cond (*test1* *action1*)
      (*test2* *action2*)
          :
          :
      (*testN* *actionN*))

If the expression *test1* evaluates to non-nil, then the 
"cond" function returns what the expression *action1* 
evaluates to.  (Since *test1* is an expression, we'd expect 
to see a function call there, or maybe a symbol bound to some 
value...that sort of thing.)  If *test1* evaluates to nil, 
the "cond" skips to *test2*, which is evaluated as above, 
and so on.  Each test-action pair is called a "cond clause".

If all the tests are evaluated in sequence, and all tests 
evaluate to nil, then the "cond" returns nil.  While you can 
count on this to happen, it may not be immediately obvious to 
other folks who read the "cond" expression exactly what the 
original programmer intended to occur in this case.  Good 
programming style in general demands that you make your 
intentions explicit in your code.  Here, that means you 
should always end your "cond" with a cond clause which makes 
it obvious what you expect to happen when all the previous 
tests evaluate to nil.  You do it like this:

(cond (*test1* *action1*)
      (*test2* *action2*)
          :
          :
      (*testN* *actionN*)
      (T *what you want to happen if all else fails*))

Also, you can have more than one action in each cond clause.  
If the test is non-nil, the associated actions will be 
evaluated left-to-right, and the last expression evaluated 
will be the one returned by the "cond" function.  (Note, 
though, that since we're not letting you create any side-
effects by assigning values to variables yet, this feature 
won't be all that useful to you just now.)  What kinds of 
tests already exist for you to use?  Here's a quick lesson:


Predicates

Common LISP provides a set of functions which are designed to 
execute useful tests and Boolean or true/false values 
depending on the outcome of the test.  These are called 
predicates, and we use them all the time as the tests in our 
"cond" functions.  Here are some commonly-used predicates:

  (null *expr*)             returns non-nil if *expr* is the empty
                            list, nil if *expr* is not empty

  (equal *expr1* *expr2*)   returns non-nil if *expr1* and *expr2*
                            evaluate to equivalent data structures
                             (i.e.,they look the same), nil otherwise

With these two predicates in hand and knowledge of the almighty
conditional, you have the potential to write functions that do 
substantially more than multiply three numbers together.  For example....

Using "cond" -- an example

Let's say we want to define a function which tells us if a 
given item is an element of a given list.  This turns out to 
be a very useful function, and it already exists in Common 
LISP.  It's called "member".  But even though it already 
exists, we want the practice, so we're going to construct our 
own version.  And to make sure we don't inadvertently replace 
LISP's version with our own possibly buggy version, we'll 
give ours a distinctive name.  Following a tradition handed
down through generations of programming courses, we'll use
the convention of creating these distinctive names by taking
the name of the LISP function we're trying to mimic and adding
the prefix "my-" to it.  Thus we generate the name "my-member"
for our own version of "member".

What will the design look like?  We can sketch it out with a 
combination of the LISP syntax we already know, and some 
English where we're not sure about the LISP yet.  Here's the 
first cut:

  (defun my-member (the-item the-list)
         if done then return "no"
    else if the-item = first element of the-list
         then return "yes"
    else what?  see if the-item = next thing on the-list?
         how? )

OK, so how are we going to turn all that "if-then-else" stuff into a "cond"?

  (defun my-member (the-item the-list)
    (cond (done then return "no")
          (the-item = first element of the-list
           then return "yes")
          (what?  see if the-item = next thing on 
           the-list? how? ) ) )

Hmmm.  That looks a little more like LISP, but it sure won't 
run on my machine yet.  What looks like something that's going 
to be real easy to turn into LISP?  How about that test to 
see if the-item is the same as the first element of the-list?  
That should be easy.  Just remember the "cond" syntax:

  (defun my-member (the-item the-list)
    (cond (done then return "no")
          ((equal the-item (first the-list))
           then return "yes")
          (what?  see if the-item = next thing on 
           the-list? how? ) ) )

And how do we return "yes" in that case?

  (defun my-member (the-item the-list)
    (cond (done then return "no")
          ((equal the-item (first the-list)) T)
          (what?  see if the-item = next thing on 
           the-list? how? ) ) )

Nothing to it.  How are we going to test if we're done?  
Well, if we just sort of walk along the-list, testing the 
individual elements to see if they match the-item, what 
would be the termination point?  When we run out of the-
list, or, in other words, when the-list is nil.  So now we 
can translate more English into LISP:

  (defun my-member (the-item the-list)
    (cond ((null the-list) nil)
          ((equal the-item (first the-list)) T)
          (what?  see if the-item = next thing on 
           the-list? how? ) ) )

Wow.  Now I have more LISP than English.  But there's still 
one missing chunk.  How do I get this thing to repeat for 
every element of the-list (or at least until I match the-
item)?  If we were piddling around with Pascal or C, we'd want 
to create some sort of loop structure, and maybe create a 
variable or two, and throw in an assignment operation here 
and there...make it really complicated, and in the process 
make ourselves feel good about how much mastery we have over 
our computer.  Grrrrr.

Well, that's not gonna happen here.  Not today at least.  
We're going to use a very elegant and computationally pure 
form of iteration which LISP supports very nicely.  It's 
called recursion...you may have heard of it before.

  (defun my-member (the-item the-list)
    (cond ((null the-list) nil)
          ((equal the-item (first the-list)) T)
          (T (my-member the-item (rest the-list)))))

It's done.  It doesn't work exactly like the official version of
"member" that's already defined in LISP; we'll talk about that in
a moment.  But the function above does what we set out to do, and
you have to admit it was pretty darn easy to make it work.  In fact
it's so easy that many of you were telling me how to write this code
in class, and along the way you introduced the concept of recursion
in LISP without me having to prompt you (much).  We'll talk about
recursion a lot in the next couple of lectures, and you'll use it
a lot in the code you write.  But if you ever get weirded out by
recursion, stop and think about this example, and remember that 
it's such a simple concept that you introduced it in class before
I did.  Really.


We mentioned then that this function doesn't work quite like
LISP's "member" function.  One way in which this function differs
from the "real one" is that this "my-member" function just
returns T or nil, but "member" tries to provide a little
bit more information.  So when you call

   ? (member 'c '(a b c d e))

in your LISP system, you'll see

   (C D E) 

returned, not T.  Why?  Because (C D E) is still a non-nil 
value like T, but your program might find the (C D E) sublist
more useful than plain old T.  It's not much harder to return
the sublist...just change T to the-list:

  (defun my-member (the-item the-list)
    (cond ((null the-list) nil)
          ((equal the-item (first the-list)) the-list)
          (T (my-member the-item (rest the-list)))))

The other major way in which "my-member" differs from "member"
is that "my-member" doesn't use the correct equality predicate.
That is, there's more than one way to test for equality in this
language, and "equal" isn't the right one for purposes of mimicing
the behavior of LISP's "member" function....

Equality predicates

There are several equality predicates worth knowing about.  
In "A Programmer's Guide to Common LISP", Deborah G. Tatar 
explains it pretty well (pp. 48-50):

"...there are four important general tests for equality.  
These tests take any two LISP objects as arguments, and check 
to see if they are equal.  Naturally, two objects must be of 
the same type to be equal.

You might wonder why four tests are necessary.  Why doesn't 
one test serve the purpose?  The reason is that there are 
degrees of equality.  Most of the time you want to know 
whether two objects look the same, but sometimes you have to 
know whether they are actually the same object in memory.  
That accounts for two of the tests.  Then, as it turns out, 
minor modifications on each of the major tests make two more 
surprisingly useful functions.

EQUALP and EQUAL are the more general equality predicates.  A 
good rule of thumb is that two objects are EQUALP or EQUAL if 
they look the same when they are printed on the screen.

:
:

The difference between EQUAL and EQUALP is that EQUALP is 
less pure in its definition of equality.  Simply because it 
turns out to be useful, EQUALP ignores differences in case in 
characters and type in numbers.  For example,

   (equal 3 3.0)
   NIL
   
but

   (equalp 3 3.0)
   T

[ and also

   ? (equal 3/4 0.75)
   NIL
   ? (equalp 3/4 0.75)
   T 
]

Also,

   (equal "YES" "yes")
   NIL
   
   (equalp "YES" "yes")
   T

The last example demonstrates one of the instances in which 
EQUALP is useful; if you had solicited user input, you 
probably wouldn't care whether it was typed in lower-, or 
uppercase letters, or both.

The other two equality predicates, EQ and EQL, tell you 
whether you are looking at two objects in memory or at one.  
Why do we need operators like these?  Consider the following 
calls and returned values:

(equal (cons 'a 'b) (cons 'a 'b))
T

(equalp (cons 'a 'b) (cons 'a 'b))
T

These might look like good answers, and for many purposes 
they are; however, consider that CONS is a function that 
performs an operation.  Each time you call CONS, a new cons 
cell is constructed.  The contents of two cons cells may be 
the same or look the same but they are separate objects, just 
as twins who have DNA with the same sequence of nucleotides 
are still separate persons.  EQ and EQL test whether two 
objects not only look alike, but whether they are the same, 
that is, located in the same place in memory.  In other 
words,

(eq (cons 'a 'b) (cons 'a 'b))
NIL

(eql (cons 'a 'b) (cons 'a 'b))
NIL

This kind of test is important when you have the ability to 
change objects.  Then you often need to know whether both 
items will change, or only one.

:
:

One characteristic difference between EQ and EQL has to do 
with the way LISP handles numbers.  EQ returns true only if 
two numbers are in exactly the same location in memory.  
Small numbers (called FIXNUMS) have a direct representation 
in memory, and are always EQ.  However, LISP must create a 
representation for very large numbers (BIGNUMS) and for 
floating-point numbers each time they are used.  Therefore, 
they may not be EQ.  It turns out that much of the time you 
won't care about exact identity in that case.  Furthermore, 
the number of fixnums is implementation-dependent.  EQL is 
provided as a portable version of EQ.  For example, in a 
given implementation of LISP:

   (eq 1234567890 1234567890)

may return T or NIL, but:

   (eql 1234567890 1234567890)

always returns T.

The difference between EQ and EQL is rather subtle; in fact, 
the only reason for introducing EQL at this early stage is 
that it is the default test that LISP functions use to test 
for equality."


Lecture notes by Kurt Eiselt, 1998.
Minor changes / additions by Brian McNamara, 1998.
Last updated on Fri Jul 3 13:25:53 EDT 1998 by Brian McNamara