The Revised Maclisp ManualThe PitmanualPage A-6
Published by HyperMeta Inc.
 
Prev | Index | Next
[Blue Marble]
Climate Change
Why not a carbon tax?


SETF

The SETF Family


SETFSpecial Form(SETF form1 val1 form2 val2 ...)

This form allows one to assign a value to the cell which would be read by form. In the simplest case, a form is a symbol so the value, val, is placed in the symbol's value cell. In other words, (SETF sym val) is the same as (SETQ sym val). It is more general than SETQ, however, since form may be a non-symbol. In that case, the cell which would be accessed by form is changed to contain value. e.g., (SETF (CXR n exp) val) is the same as (PROGN (RPLACX n exp val) val).

SETF goes to a lot of trouble to return the last value even if the setting function, in this case RPLACX, does not return that value. Other Lisp dialects (e.g., Lisp Machine Lisp) may not guarantee the return value of SETF; Common Lisp is expected to change this, however, by explicitly defining the return value (compatibly with the Maclisp definition). However, some programmers still feel that the return value of an operation done for side-effect should not be relied upon. For these reasons, it may be desirable to adopt a coding style which does not make use of SETF's return value.

SETF initially knows how to invert the following types of operations: *LDB, *LOAD-BYTE, ARG, ARGS, ARRAYCALL, CXR, FIXNUM-IDENTITY, FLONUM-IDENTITY, GET, LDB, LOAD-BYTE, NTH, NTHCDR, PLIST, PROGN, SFA-GET, SYMEVAL, and C...R. To see what sorts of things SETF expands into, it may be convenient to just write a loop that displays some expansions. e.g.,

(DO ((FORM))
    (NIL)
  (IF (NULL (SETQ FORM (PROGN (PRINT 'INPUT/:) (READ))))
      (RETURN 'DONE))
  (PRINC " => ")
  (PRIN1 (MACROEXPAND FORM)))
INPUT: (SETF X VAL)  => (SETQ X VAL)
INPUT: (SETF (CAR X) VAL) => (PROGN (RPLACA X VAL) VAL)
INPUT: (SETF (CDR X) VAL) => (PROGN (RPLACD X VAL) VAL)
INPUT: (SETF (NTH 5 X) VAL) => (PROGN (RPLACA (NTHCDR 5 X) VAL) VAL)
INPUT: (SETF (GET X Y) VAL) => (PROGN (PUTPROP X VAL Y))
INPUT: NIL
DONE

To extend the set of things SETF knows about, the user can add an appropriate setf-x property to other operators of his choice by the use of DEFSETF.

If SETF does not find a SETF-X property on the operator of form, it will try to macroexpand form. If it can be expanded into something SETF knows about, the SETF expansion will still succeed. If the macroexpansion fails to produce a recognizable result, SETF will err.

SETF also tries to support proper left to right evaluation of its arguments (according to the textually apparent order of the forms in the user-specified form). For example, since STORE evaluates its arguments backwards,

(SETF (ARRAYCALL T FOO 3) BAR)

can expand to something like

(STORE (ARRAYCALL T FOO 3) BAR)

but

(SETF (ARRAYCALL T (FOO) (BAR)) (BAZ))

must expand to

((LAMBDA (G0001 G0002 G0003)
   (STORE (ARRAYCALL T G0001 G0002) G0003))
 (FOO) (BAR) (BAZ))

to make sure that the FOO, BAR, and BAZ function calls, which may have side-effects, occur in the proper order.

If SETF does not recognize a form, it will hope that the car of the form is a symbol which has a SETF-X property and will ask that function for help (see DEFSETF).

(setq a '(a b c))
=> (A B C)

(setf (cadr a) 'd)
=> D

a
=> (A D C)

(defmacro square-root (x) `(get ,x 'square-root))
=> SQUARE-ROOT

(setf (square-root 'nine) 'three)
=> THREE

(square-root 'nine)
=> THREE

Multics users must (%include setf) to get SETF.


DEFSETFSpecial Form(DEFSETF fn (form val) retval invform)

This is the appropriate way to provide information to SETF about how to do inversions on forms that it would not otherwise know about. It creates a SETF-X property on the function, fn, which is a function constructed from information given by the rest of its arguments. The second argument is destructured over and should have the same shape as the cdr of a simple (2 argument) SETF form. The third argument, retval, is T if the return value from the inversion of form is the same as val. The last argument, invform, is code which must return the appropriately inversion of form in order to store val. For example, the DEFSETF code for CXR would look like this:

(DEFSETF CXR ((CXR INDEX HUNK) VALUE)
  NIL ;RPLACX returns the whole hunk, not just value stored
  `(RPLACX ,INDEX ,HUNK ,VALUE))

Note that DEFSETF will take care of worrying about whether there are side-effects in the given form or val and will wrap a LAMBDA around the form automatically in such a case.

Note: This definition is not compatible with the proposed Common Lisp definition of DEFSETF.

(DEFSETF GET-INFO ((GET-INFO TAG) VALUE) T
  `(PUT-INFO ,TAG ,VALUE))
=> GET-INFO

(MACROEXPAND '(SETF (GET-INFO 'FOO) 3))
=> (PUT-INFO (QUOTE FOO) 3)

(MACROEXPAND '(SETF (GET-INFO (A)) (B)))
=> (PUT-INFO (A) (B))

(DEFSETF FOO ((FOO IDX) VALUE) NIL
  `(SET-FOO ,IDX ,VALUE))
=> FOO

(MACROEXPAND '(SETF (FOO 3) 5))
=> (PROGN (SET-FOO 3 5) 5)

(MACROEXPAND '(SETF (FOO (A)) (B)))
=> ((LAMBDA (G0001 G0002) (SET-FOO G0001 G0002) G0002)
    (A) (B))

Multics users must (%include setf) to get DEFSETF.

Stack Handlers Using SETF


PUSHSpecial Form(PUSH value form)

This form is essentially like (SETF form (CONS value form)). See POP and SETF.

Multics users must (%include other_other) to get PUSH.


POPSpecial Form(POP form)

(POP sym) is like (PROG1 (CAR sym) (SETQ sym (CDR sym))). Called on other forms, it uses SETF to attempt to access and pop whatever type of access is being attempted. For example, the expression (POP (GET 'FOO 'BAR)) can be used instead of (PUTPROP 'FOO (CDR (GET 'FOO 'BAR)) 'BAR).

Multics users must (%include other_other) to get POP.

(defvar *reg1* nil "Register 1")
=> *REG1*

(push 'a *reg1*)
=> (A)

(push 'b *reg1*)
=> (B A)

(pop *reg1*)
=> B

;; Use in a program
(defun list-fringe (tree)
  (let ((*fringe* nil))
    (declare (special *fringe*))
    (list-fringe-aux tree)
    (nreverse *fringe*)))
=> LIST-FRINGE

(defun list-fringe-aux (tree)
  (declare (special *fringe*))
  (cond ((atom tree) (push tree *fringe*))
        (t (list-fringe-aux (car tree))
           (list-fringe-aux (cdr tree)))))
=> LIST-FRINGE-AUX

(list-fringe '((a . b) (c (d . e) . f) . g))
=> (A B C D E F G)

[Blue Marble]
Climate Change
What was wrong with the electric car?

The Revised Maclisp Manual (Sunday Morning Edition)
Published Sunday, December 16, 2007 06:17am EST, and updated Sunday, July 6, 2008.
Prev | Index | Next