Another way to get repetitive operations

There's yet another way to get repetition out of our 
procedures, and that falls under the header of "applicative 
programming" as opposed to "recursive programming".  To 
demonstrate how applicative programming works, though, we'll 
start with a recursive explanation of applicative 
programming.

When using a programming language whose basic data structure 
is the list, it's not surprising that one of the things we 
want to do most often is perform the same procedure on all 
the elements of a list.  We already know how to do that 
recursively.  Say for example, that we want to take a list of 
numbers as input and return a list of corresponding square 
roots.  That procedure might look like this (do you recognize 
the recursion template?):

(defun lotsa-sqrts (input-list)
  (cond ((null input-list) nil)
        (T (cons (sqrt (first input-list))
                 (lotsa-sqrts (rest input-list))))))

and it would work like this:

   ? (lotsa-sqrts '(1 4 9 16 25))
   (1 2 3 4 5)
   ?

Now say instead of sqrt I want to use "double" to double every element
of my list, as in

   (defun double (x)
      (* 2 x))

   ? (lotsa-doubles '(1 2 3 4))
   (2 4 6 8)
   ?

It's easy to imagine how to write that.  Just write a new function where
every occurrence of "sqrt" is replaced by "double".

_OR_, instead of writing anything new, it turns out we can just say

   (mapcar #'double '(1 2 3 4)) => (2 4 6 8)
   (mapcar #'sqrt '(1 4 9 16)) => (1 2 3 4)

Huh?


Functions as data

I've jumped ahead of myself, introducing two new functions: mapcar and
hash-quote #' in order to show you the result we're aiming at.  Let's
back up the truck (beep beep!) and see what's going on.

In order to make this happen, there are some things you need 
to know first.  Remember way back when we were touting all 
the things that made LISP so nice?  One of those features was 
the lack of any procedure/data distinction.  Here's one place 
where that feature comes in handy.

Since a procedure can be treated as a piece of data, we can 
decompose procedures into component parts.  That means we can 
separate a function body from its name.  (How did that body 
get that name?  The "defun" function did it, remember?)  In 
other words, it's possible (and in many cases desirable, as 
we're about to see) to use a nameless, anonymous function 
definition in our computations.  LISP of course has a 
predefined function for separating function bodies from their 
names, and it is named, ironically, "function".  Here's how 
it works:

Let's say you've defined a new function of your own, which in 
this case takes a number as an argument and returns its 
double.  When you use "defun" to create that function:

   (defun double (x)
      (* 2 x))

you've told LISP to bind the name "double" to everything that 
follows the name "double" in your definition.  That association 
is then stored in the symbol table.  Later, when you call the 
"double" function, LISP looks up "double" in the symbol table and 
retrieves the function body associated with it, then uses 
that function body to figure out what to do.  If we want to 
tell LISP at some point to explicitly go to the symbol table, 
look up the "double" function, retrieve the function body and 
return it without doing anything else with it, then we can 
just say:

   > (function double)

Now, if we're doing this in some form of Common LISP that used
to be available here, we'd see this:

   > (function double)
   (LAMBDA (X) (* 2 X))
   >

Actually, we might see more junk in there, but it would be 
implementation-dependent detail.  What you see just above is 
the function body in its "pure" form.

What you're looking at is LISP's basic anonymous function 
form, called the "lambda function".  The "(x)" part is 
the argument list, and the rest is just the function body.
Thus, a lambda function is just a function body that's not
bound to a function name.  

That "function" function gets used a lot, it turns out, so 
there's an abbreviation.  Instead of typing 

   ? (function double)

we could type 

   ? #'double

and get the same result.  That abbreviation is pronounced 
"hash-quote".


What can you do with a lambda function?

Back to the original problem: how do we create a generic 
function like "lotsa-sqrts" that isn't restricted to just 
computing square roots?  How do we get it to use any function 
we pass it as an argument?  How do we turn "lotsa-sqrts" into 
"lotsa-anything"?

Let's borrow the "lotsa-sqrts" and make a few necessary 
changes and see where that gets us:

(defun lotsa-anything (func-body input-list)              ; two args now
  (cond ((null input-list) nil)                           ; nothing new
        (T (cons (*magic* func-body (first input-list))   ; eh?
                 (lotsa-anything func-body (rest input-list))))))

We know we needed to pass a function body as an argument, so 
we added that argument.  Everything else is pretty much the 
same, except we don't know how to make the function body 
passed as "func-body" do anything to the argument passed as 
"input-list".  All we have there is the function body, and 
since LISP lets us separate function bodies from their names, 
there must be some way of using a nameless function body, 
right?  I hope you said yes, because it's true.  And that's 
what we need to put in place of *magic* up above in "lotsa-
anything".  (No, *magic* is not literally a predefined LISP 
function.  It'd be way cool if it were.)

LISP actually provides two basic functions for applying 
anonymous function bodies to arguments.  The first is called 
(you guessed it) "apply".  The "apply" function takes two 
arguments, a function body and a list whose elements are the 
arguments to be passed to the function body.  The function 
body is then applied to the that list of arguments (i.e., 
variable bindings are made, the function is then executed, 
the result is returned...just like in "normal" function 
evaluation).  The "apply" function is the function to choose 
when you don't know how many arguments to expect (i.e., the 
anonymous function can take on an arbitrary number of 
arguments).  For example, we can say:

   ? (apply #'+ '(2 4 6 8))
   20

and all is ok. Apply expects an arbitrarily long list of 
arguments, and "+" can accept any number of arguments.  But 
if we say:

   ? (apply #'+ 2 4 6 8)

we get an error:

   > Error: Can't construct argument list from 8.
   > While executing: APPLY
   > Type Command-. to abort.
   See the Restarts... menu item for further choices.
   1 > 

On the other hand, we can do this:

   ? (apply #'+ 2 4 '(6 8))
   20
   ?

The way that "apply" is usually used is with two arguments: a function
body and a list of arguments for that function body.  But, as a
"convenience" (as one book puts it), "apply" can take any number
of arguments so long as the last one is a list.  So while
(apply #'+ 2 4 6 8) won't work, (apply #'+ 2 4 (6 8)) will work.
Personally, I never use "apply" in this way, and I almost always 
forget that I can.  

What if you do know in advance how many arguments your function
expects, like in the case of the "sqrt" function, which always 
takes only one argument?  In this case,  we can use "funcall" 
instead of "apply".  The "funcall" function takes a function 
body as its first argument, and the remaining arguments are 
exactly those arguments needed by the function body passed as 
the first argument.  Thus, we can say:

   ? (funcall #'sqrt 25)
   5
   ?

but we can't say:

   ? (funcall #'sqrt 25 36)
   > Error: Too many arguments.
   > While executing: SQRT
   > Type Command-. to abort.
   See the Restarts... menu item for further choices.
   1 > 

because we'd be trying to pass too many arguments to "sqrt", 
and we can't say:

   ? (funcall #'sqrt '(25 36))
   > Error: value (25 36) is not of the expected type NUMBER.
   > While executing: ZEROP
   > Type Command-. to abort.
   See the Restarts... menu item for further choices.
   1 > 

because "sqrt" expects a number, not a list.  That was easy, 
wasn't it?

So now, which of those two functions, "apply" and "funcall", 
would be the right one to put in place of *magic* in our 
"lotsa-anything" function?  We'd replace *magic* with 
"funcall":

   (defun lotsa-anything (func-body input-list)  
     (cond ((null input-list) nil)               
           (T (cons (funcall func-body (first input-list)) 
                    (lotsa-anything 
                       func-body (rest input-list))))))
   
The net result is a function which maps another function onto 
the elements of a list, performs that operation on each of 
those elements, and returns a list of the results.

Because "lotsa-anything" sort of scoots along, mapping the 
passed function body onto succeeding "first"s or "car"s of 
the ever-shrinking "input-list", this function resembles a 
function called "mapcar".  The "mapcar" function is already 
predefined in LISP, and works sort of like what we've defined 
here:  it applies the given function to successive "first"s or
"car"s of the list, collects the individual results into a list, 
and returns that list.  Despite the similarities, "mapcar" isn't
the same as "lotsa-anything"---"mapcar" is much more powerful.
So while building the "lotsa-anything" function gives us an idea 
as to what the "mapcar" and its associated mapping functions do, 
you should take the time to look up "mapcar" and the others in the 
Steele book and/or the Graham book and become familiar with 
what's really going on there.

Here's how I can substitute the elegant, pre-defined "mapcar" function
for my crude "lotsa-anything" slop and get the same result:

   ? (mapcar #'sqrt '(1 4 9 16 25))
   (1 2 3 4 5)
   ?

One thing that "mapcar" can do that "lotsa-anything" can't is
take functions that expect more than one argument.  If, for
example, I wanted to "cons" a bunch of elements of one list
into their respective elements of another list, I'd just do
this:

   ? (mapcar #'cons '(a b c) '(1 2 3))
   ((A . 1) (B . 2) (C . 3))
   ? 

(Dotted pairs...yuk!  Anyway, we move on...)

There's a corresponding function called "maplist" which maps the
given function onto successive "rest"s or "cdr"s of the list,
collects the results into a list, and returns that list.  As I
mentioned in class, "maplist" is of limited usefulness, but here's
a semi-pointless example that we generated as a result of an in-class
discussion a couple of quarters ago...

Let's say I wanted to compute the factorials (of course!) of a
sequence of numbers from N to 1 which I conveniently have
already stored in a list like this: (5 4 3 2 1).

I could write two not-so-obvious functions like this:

   (defun list-factorial (num-list)
     (maplist #'list-multiply num-list))
   
   (defun list-multiply (num-list)
     (apply #'* num-list))

and then do this:

   ? (list-factorial '(5 4 3 2 1))
   (120 24 6 2 1)
   ? 

Ooohhh!!  Neat!  OK, it's not a real practical example, but it
works.

It's these predefined mapping functions like "mapcar" that 
provide us with a second means of getting repetitive 
operations without the traditional looping structure.  The 
mapping functions are very efficient in applying a function 
in sequence to different groupings of an argument list.  
Again, this style of programming is called "applicative 
programming" to distinguish it from "recursion" or 
"iteration".

Note:

You may get the impression from the discussion above that you 
can only use apply and funcall with a named function whose body
is then extracted via #' (i.e., the function function).  Not 
true at all.  If the sqr function is defined as follows:

   ? (defun sqr (x) (* x x))
   SQR

then the following are equivalent:

   ? (apply #'sqr '(2))
   4
   ? (funcall #'sqr 2)
   4
   ? (apply #'(lambda (x) (* x x)) '(2))
   4
   ? (funcall #'(lambda (x) (* x x)) 2)
   4
   ? (apply (function (lambda (x) (* x x))) '(2))
   4
   ? (funcall (function (lambda (x) (* x x))) 2)
   4

So note that I could construct a function which builds a list
that just happens to be a lambda function, plunk that inside
a "function" function, and put that inside either "apply" or
"funcall", and thereby evaluate a lambda function that was
constructed in real time by another function.  Piece o' cake.


Now we turn and wave goodbye to that grunt-level implementation
stuff and move on to questions about knowledge and how we
represent it.  


Lecture notes by Kurt Eiselt, 1998.
Minor changes / additions by Brian McNamara, 1998.
Last updated on Tue Jul 14 05:29:16 EDT 1998 by Brian McNamara