From: Frank Buss
Subject: avoiding redundancy in Generalized Reference
Date: 
Message-ID: <ck6vct$d3k$1@newsreader2.netcologne.de>
I have a function like this:

(defun maze-aref (maze x y) (elt (elt maze (1+ (* y 2))) (1+ (* x 2))))

now I can call it for retrieving a value:

(maze-aref maze 4 2)

but setf gives an error:

(setf (maze-aref maze 4 2) #\Space)

so I define the inversion:

(defun (setf maze-aref) (new-stone maze x y)
  (setf (elt (elt maze (1+ (* y 2))) (1+ (* x 2)))
        new-stone)
  new-stone)

now setf works. But how can I avoid the redundancy? Is there a macro or 
something which builts the inversion automaticly for simple cases like 
this?

-- 
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de

From: Thomas F. Burdick
Subject: Re: avoiding redundancy in Generalized Reference
Date: 
Message-ID: <xcvwty06fki.fsf@conquest.OCF.Berkeley.EDU>
Frank Buss <··@frank-buss.de> writes:

> I have a function like this:
> 
> (defun maze-aref (maze x y) (elt (elt maze (1+ (* y 2))) (1+ (* x 2))))
> 
> now I can call it for retrieving a value:
> 
> (maze-aref maze 4 2)
> 
> but setf gives an error:
> 
> (setf (maze-aref maze 4 2) #\Space)
> 
> so I define the inversion:
> 
> (defun (setf maze-aref) (new-stone maze x y)
>   (setf (elt (elt maze (1+ (* y 2))) (1+ (* x 2)))
>         new-stone)
>   new-stone)
> 
> now setf works. But how can I avoid the redundancy? Is there a macro or 
> something which builts the inversion automaticly for simple cases like 
> this?

Not in the standard language, but here's one from my personal
collection of utilities:

  (declaim (inline parse-body))
  (defun parse-body (&rest args)
    #+cmu (apply #'sys:parse-body args)
    #+sbcl (apply #'sb-int:parse-body args)
    #-(or cmu sbcl) (error "No parse-body on this system."))
  
  (defmacro defun/setf (name llist &body body)
    "Define NAME and (SETF NAME) based on BODY."
    (multiple-value-bind (body decls doc) (parse-body body)
      (assert (= (length body) 1))
      (let ((new (gensym "NEW")))
        `(progn
           (defun ,name ,llist
             ,@decls ,@(when doc (list doc))
             ,@body)
           (defun (setf ,name) (,new ,@llist)
             ,@decls ,@(when doc (list doc))
             (setf ,@body ,new))))))
From: Peter Seibel
Subject: Re: avoiding redundancy in Generalized Reference
Date: 
Message-ID: <m3y8igrj28.fsf@javamonkey.com>
Frank Buss <··@frank-buss.de> writes:

> I have a function like this:
>
> (defun maze-aref (maze x y) (elt (elt maze (1+ (* y 2))) (1+ (* x 2))))
>
> now I can call it for retrieving a value:
>
> (maze-aref maze 4 2)
>
> but setf gives an error:
>
> (setf (maze-aref maze 4 2) #\Space)
>
> so I define the inversion:
>
> (defun (setf maze-aref) (new-stone maze x y)
>   (setf (elt (elt maze (1+ (* y 2))) (1+ (* x 2)))
>         new-stone)
>   new-stone)
>
> now setf works. But how can I avoid the redundancy? Is there a macro or 
> something which builts the inversion automaticly for simple cases like 
> this?

Well, for simple cases like this you could define your own:

  (defmacro defun-setfable (name (&rest lambda-list) &body body)
    (with-gensyms (new-value)
      `(progn
         (defun ,name (,@lambda-list) ,@body)
         (defun (setf ,name) (,new-value ,@lambda-list)
           (setf ,@body ,new-value)))))

Then instead of:

  (defun maze-aref (maze x y)
    (elt (elt maze (1+ (* y 2))) (1+ (* x 2))))

write:

  (defun-setfable maze-aref (maze x y)
    (elt (elt maze (1+ (* y 2))) (1+ (* x 2))))

Or you can use a macro instead of a function as Pascal pointed out as
long as you don't need to FUNCALL, APPLY, MAPCAR, etc. maze-aref.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Steven M. Haflich
Subject: Re: avoiding redundancy in Generalized Reference
Date: 
Message-ID: <qdE9d.26682$QJ3.920@newssvr21.news.prodigy.com>
Peter Seibel wrote:

>   (defmacro defun-setfable (name (&rest lambda-list) &body body)
>     (with-gensyms (new-value)
>       `(progn
>          (defun ,name (,@lambda-list) ,@body)
>          (defun (setf ,name) (,new-value ,@lambda-list)
>            (setf ,@body ,new-value)))))
                    ^^^^^^

This macrology is syntactically broken.  There seems to be an
assumption that the BODY might be more than a single form.
But clearly that won't work if multiple forms are spliced into
the setf macro call.

I'll also point out that regular setf machinery is required to
handle multiple values, even though many implementations don't
get it right.  It's tricky to extend defun-setfable to functions
that return multiple values.
From: Pascal Bourguignon
Subject: Re: avoiding redundancy in Generalized Reference
Date: 
Message-ID: <87llegyk2s.fsf@thalassa.informatimago.com>
Frank Buss <··@frank-buss.de> writes:

> I have a function like this:
> 
> (defun maze-aref (maze x y) (elt (elt maze (1+ (* y 2))) (1+ (* x 2))))
> 
> now I can call it for retrieving a value:
> 
> (maze-aref maze 4 2)
> 
> but setf gives an error:
> 
> (setf (maze-aref maze 4 2) #\Space)
> 
> so I define the inversion:
> 
> (defun (setf maze-aref) (new-stone maze x y)
>   (setf (elt (elt maze (1+ (* y 2))) (1+ (* x 2)))
>         new-stone)
>   new-stone)
> 
> now setf works. But how can I avoid the redundancy? Is there a macro or 
> something which builts the inversion automaticly for simple cases like 
> this?

Of course:

(defun make-maze (&key (width 10) (height 10)) (make-array (list widht height)))
(defmacro maze-aref (maze x y) `(aref ,maze ,x ,y))
(setf (maze-aref maze 4 2) #\space)

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

Voting Democrat or Republican is like choosing a cabin in the Titanic.