gcl-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Gcl-devel] (SETF (VALUES ...) ...) and related issues


From: Peter Wood
Subject: Re: [Gcl-devel] (SETF (VALUES ...) ...) and related issues
Date: Sun, 20 Oct 2002 07:08:56 +0200
User-agent: Mutt/1.4i

On Sat, Oct 19, 2002 at 05:11:29PM -0500, Paul F. Dietz wrote:
> We now can do (setf (values x y) ...), but macroexpansion show's it's not
> quite right:
> 
> >(macroexpand '(setf (values x y) (f)))
> 
> (LET ((#:G1967 (MULTIPLE-VALUE-LIST (F))))
>   (VALUES (SETQ X (NTH 0 #:G1967)) (SETQ Y (NTH 1 #:G1967))))
> T
> 
> > (macroexpand '(setf (values (car x) (car y)) (f)))
> 
> (LET ((#:G1968 (MULTIPLE-VALUE-LIST (F))))
>   (VALUES (SETQ (CAR X) (NTH 0 #:G1968))
>           (SETQ (CAR Y) (NTH 1 #:G1968))))
> T
> 
> >
> 
> 
> The problem with this implementation is that he call to (F) may
> modify the values of X and Y.  However, SETF is required to
> evaluate the subterms needed to determine places in order, from
> left to right.  This same kind of problem is occuring in some
> other places (MULTIPLE-VALUE-SETQ with symbol macros, for example).
> 
> The proper solution is to use DEFINE-SET-EXPANDER and GET-SETF-EXPANSION
> to produce a setf expansion that preserves the evaluation order.  If
> we had those then added a setf expansion for VALUES would be
> straightforward.  However, gcl doesn't support these yet.
> 
> I've added implementing these two to the Lisp Support task list.
> 
>       Paul

Hi

Happily, I believe GCL does have these (or something _very_ similar)
under slightly different names.

>From the docs:

----------------------------------------------------------------
Macro: DEFINE-SETF-METHOD
    Package:LISP

    Syntax:

(define-setf-method access-fun defmacro-lambda-list {decl | doc}*
          {form}*)

Defines how to SETF a generalized-variable reference of the form
(ACCESS-FUN ...). When a form (setf (ACCESS-FUN arg1 ... argn) value)
is being evaluated, the FORMs are first evaluated as a PROGN with the
parameters in DEFMACRO-LAMBDA-LIST bound to ARG1 ... ARGn. Assuming
that the last FORM returns five values (temp-var-1 ... temp-var-k)
(value-from-1 ... value-form-k) (store-var) storing-form access-form
in order, the whole SETF is then expanded into (let* ((temp-var-1
value-from-1) ... (temp-k value-form-k) (store-var VALUE))
storing-from) Incidentally, the five values are called the five gangs
of a SETF method. The doc-string DOC, if supplied, is saved as a SETF
doc and can be retrieved by (documentation 'NAME 'setf).

Function: GET-SETF-METHOD (form)
    Package:LISP

Returns the five values (or five 'gangs') constituting the SETF method
for FORM. See the doc of DEFINE-SETF-METHOD for the meanings of the
gangs. It is an error if the third value (i.e., the list of store
variables) is not a one-element list. See the doc of
GET-SETF-METHOD-MULTIPLE-VALUE for comparison.

---------------------------------------------------------------

Here is the CLHS example for 'define-setf-expander slightly adapted to
GCL's naming ... it works fine.

(defun lastguy (x) (car (last x))) ;;=>  LASTGUY
(define-setf-method lastguy (x &environment env)
  "Set the last element in a list to the given value."
  (multiple-value-bind (dummies vals newval setter getter)
      (get-setf-method x env)
    (let ((store (gensym)))
      (values dummies
              vals
              `(,store)
              `(progn (rplaca (last ,getter) ,store) ,store)
              `(lastguy ,getter))))) ;;=>  LASTGUY
(setq a (list 'a 'b 'c 'd)
      b (list 'x)
      c (list 1 2 3 (list 4 5 6))) ;;=>  (1 2 3 (4 5 6))
(setf (lastguy a) 3) ;;=>  3
(setf (lastguy b) 7) ;;=>  7
(setf (lastguy (lastguy c)) 'lastguy-symbol) ;;=>  LASTGUY-SYMBOL

#|
a =>  (A B C 3)
b =>  (7)
c =>  (1 2 3 (4 5 LASTGUY-SYMBOL))
|#

Regards,
Peter




reply via email to

[Prev in Thread] Current Thread [Next in Thread]