[Top][All Lists]
[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