The Department of Computer Science & Engineering
cse@buffalo

CSE202: Programming in Lisp

Course
Grades
Email

Welcome

Policies
    Grades
    Inc
    Intgrty

Preface
Part I
  Chap 1
  Chap 2
  Chap 3
  XEmacs
  Chap 4
  Chap 5
  Chap 6
  Chap 7
  Chap 8
  Chap 9
Part II
  Chap 10
  Chap 11
  Chap 12
  Chap 13
  Chap 14
  Chap 15
  Chap 16
  Chap 17
  Chap 18
  Chap 19
  Chap 20
  Chap 21
  Chap 22
  Chap 23
Part III
  Chap 24
  Chap 25
  Chap 26
  Chap 27
  Chap 28
  Chap 29
  Chap 30
  Chap 31
  Chap 32
CHAPTER 23: MACROS
Corrections
  1. Page 171, line 7: Change its to it has

  2. Page 171, line -9: Change (macroexpand '(pluslist-f (+ 3 4) 5)) to (macroexpand '(pluslist-m (+ 3 4) 5)).

Notes
  1. Read Chapter 23 in conjunction with these notes. Be warned: students in the past have found this chapter difficult.

  2. A way to think about programming with macros is to think of it as programming with patterns. Consider the if defined on page 169 of the text. It will be called with a form looking like
    (if condition then then-clause else else-clause)
    
    and what we really want this form to act like is
    (lisp:if condition then-clause else-clause)
    
    So, the body of the macro will be the form we want, quoted with the backquote, and with every lambda variable in the form preceded with a comma:
    `(lisp:if ,condition ,then-clause ,else-clause)
    

  3. Let's consider the function equal defined in the notes to Chapter 20, and see how to define it as a macro. This is the best technique for making use of a two-argument function to define a version of it that takes an arbitrary number of arguments. We will start the same way, but this time make equal a macro.
    (defmacro equal (object1 object2 &rest more-objects)
      "Returns True if all the objects are lisp:equal;
       False, otherwise."
      _____
      )
    
    Now, if more-objects is NIL, (equal object1 object2) can just be turned into (lisp:equal object1 object2):
    (defmacro equal (object1 object2 &rest more-objects)
      "Returns True if all the objects are lisp:equal;
       False, otherwise."
      (if (null more-objects)
          `(lisp:equal ,object1 ,object2)
        _____)
      )
    
    If there are more-objects, we could first test whether object1 is lisp:equal to object2, and then test whether object2 and all the other objects are equal. That is, we want to turn
    (equal object1 object2 object3 ...)
    
    into
    (and (lisp:equal object1 object2)
         (equal object2 object3 ...))
    
    A first attempt at a form which, put into the body of the macro, would evaluate to this form is
    `(and (lisp:equal ,object1 ,object2)
          (equal ,object2 ,more-objects))
    
    but this would expand into
    (and (lisp:equal object1 object2)
         (equal object2 (object3 ...)))
    
    because more-objects is a list of the other objects. This is exactly what the ,@ option inside a backquote is for---to splice a list into an enclosing list. So our final version of the equal macro is
    (defmacro equal (object1 object2 &rest more-objects)
      "Returns True if all the objects are lisp:equal;
       False, otherwise."
      (if (null more-objects)
          `(lisp:equal ,object1 ,object2)
        `(and (lisp:equal ,object1 ,object2)
              (equal ,object2 ,@more-objects))))
    
    Try defining ch23::equal this way (shadowing lisp:equal, and test it.

  4. Create a file named ch23.cl, and in it define the function ch23::union (shadowing common-lisp:union), as described in the notes to Chapter 20. However, use the techniques of Chapter 23 instead of the techniques of Chapter 20 or of Chapter 22. Submit this file.

Next

Copyright © 1999, 2000 by Stuart C. Shapiro. All rights reserved.

Stuart C. Shapiro <shapiro@cse.buffalo.edu>