From: ······@gmail.com
Subject: rotatef inner workings (newbie)
Date: 
Message-ID: <1186343881.147814.52950@e16g2000pri.googlegroups.com>
For simple variables:
(setf a 0)
a => 0
(setf b 1)
b => 1
(rotatef a b)
a => 1
b => 0

How would I write a macro that emulates this?  As a function such as
(defun my-rotatef (x y)
              (let ((tmp x))
                  (setf x y y tmp) nil))

Obviously doesn't affect anything outside it's code.
(setf a 0 b 1)
(my-rotatef a b)
a => 0
b => 1

From: Don Geddis
Subject: Re: rotatef inner workings (newbie)
Date: 
Message-ID: <871weh39jn.fsf@geddis.org>
······@gmail.com wrote on Sun, 05 Aug 2007:
> For simple variables:
> (setf a 0)
> a => 0
> (setf b 1)
> b => 1
> (rotatef a b)
> a => 1
> b => 0

OK.

> How would I write a macro that emulates this?  As a function such as
> (defun my-rotatef (x y)
>               (let ((tmp x))
>                   (setf x y y tmp) nil))
> Obviously doesn't affect anything outside it's code.
> (setf a 0 b 1)
> (my-rotatef a b)
> a => 0
> b => 1

DEFUN defines a function, not a macro.  DEFMACRO will define a macro.

Do you not know how to write any macros at all?  A quick Google search for
        Common Lisp macro
gives a first hit as
        http://www.apl.jhu.edu/~hall/Lisp-Notes/Macros.html
with the example
        (defmacro square (x) '(* ,x ,x))
        (macroexpand-1 '(square 9)) ==> (* 9 9)

Perhaps that's enough to get you started.

        -- Don
_______________________________________________________________________________
Don Geddis                  http://don.geddis.org/               ···@geddis.org
I guess I don't mind beavers being as busy as they are, but sometimes it seems
like they're just flaunting it.  -- Deep Thoughts, by Jack Handey [1999]
From: ······@gmail.com
Subject: Re: rotatef inner workings (newbie)
Date: 
Message-ID: <1186364672.094252.206250@e16g2000pri.googlegroups.com>
On Aug 5, 3:23 pm, Don Geddis <····@geddis.org> wrote:
> ······@gmail.com wrote on Sun, 05 Aug 2007:
>
> > For simple variables:
> > (setf a 0)
> > a => 0
> > (setf b 1)
> > b => 1
> > (rotatef a b)
> > a => 1
> > b => 0
>
> OK.
>
> > How would I write a macro that emulates this?  As a function such as
> > (defun my-rotatef (x y)
> >               (let ((tmp x))
> >                   (setf x y y tmp) nil))
> > Obviously doesn't affect anything outside it's code.
> > (setf a 0 b 1)
> > (my-rotatef a b)
> > a => 0
> > b => 1
>
> DEFUN defines a function, not a macro.  DEFMACRO will define a macro.
>
> Do you not know how to write any macros at all?  A quick Google search for
>         Common Lisp macro
> gives a first hit as
>        http://www.apl.jhu.edu/~hall/Lisp-Notes/Macros.html
> with the example
>         (defmacro square (x) '(* ,x ,x))
>         (macroexpand-1 '(square 9)) ==> (* 9 9)
>
> Perhaps that's enough to get you started.
>
>         -- Don
> _______________________________________________________________________________
> Don Geddis                  http://don.geddis.org/              ····@geddis.org
> I guess I don't mind beavers being as busy as they are, but sometimes it seems
> like they're just flaunting it.  -- Deep Thoughts, by Jack Handey [1999]

That square macro needs a back quote (`) as opposed to single-quote
(') right?
From: Kent M Pitman
Subject: Re: rotatef inner workings (newbie)
Date: 
Message-ID: <utzrde8g0.fsf@nhplace.com>
······@gmail.com writes:

> On Aug 5, 3:23 pm, Don Geddis <····@geddis.org> wrote:
> > ...
> >         (defmacro square (x) '(* ,x ,x))
> >         (macroexpand-1 '(square 9)) ==> (* 9 9)
> ...
> That square macro needs a back quote (`) as opposed to single-quote
> (') right?

Yes.

(I'm guessing he had some "smart quotes" tool was working against him.)
From: Don Geddis
Subject: Re: rotatef inner workings (newbie)
Date: 
Message-ID: <87643t1ege.fsf@geddis.org>
Kent M Pitman <······@nhplace.com> wrote on 05 Aug 2007 21:5:
> ······@gmail.com writes:
>> On Aug 5, 3:23 pm, Don Geddis <····@geddis.org> wrote:
>> >         (defmacro square (x) '(* ,x ,x))
>> >         (macroexpand-1 '(square 9)) ==> (* 9 9)

>> That square macro needs a back quote (`) as opposed to single-quote
>> (') right?
>
> Yes.
> (I'm guessing he had some "smart quotes" tool was working against him.)

Thanks, Kent.  Yup, I did copy & paste from the web page I referenced.  I
just went back and checked it, and the original web page appears to have
single-quotes as well.  Probably for a reason like Kent suggested.

But yes, this needs to be a backquote.  Sorry for my original confusing post.

        -- Don
_______________________________________________________________________________
Don Geddis                  http://don.geddis.org/               ···@geddis.org
It takes money to make money because you have to copy the design exactly.
From: Pascal Bourguignon
Subject: Re: rotatef inner workings (newbie)
Date: 
Message-ID: <87vebsopxb.fsf@informatimago.com>
Don Geddis <···@geddis.org> writes:

> ······@gmail.com wrote on Sun, 05 Aug 2007:
>> For simple variables:
>> (setf a 0)
>> a => 0
>> (setf b 1)
>> b => 1
>> (rotatef a b)
>> a => 1
>> b => 0
>
> OK.
>
>> How would I write a macro that emulates this?  As a function such as
>> (defun my-rotatef (x y)
>>               (let ((tmp x))
>>                   (setf x y y tmp) nil))
>> Obviously doesn't affect anything outside it's code.
>> (setf a 0 b 1)
>> (my-rotatef a b)
>> a => 0
>> b => 1
>
> DEFUN defines a function, not a macro.  DEFMACRO will define a macro.
>
> Do you not know how to write any macros at all?  A quick Google search for
>         Common Lisp macro
> gives a first hit as
>         http://www.apl.jhu.edu/~hall/Lisp-Notes/Macros.html
> with the example
>         (defmacro square (x) '(* ,x ,x))
>         (macroexpand-1 '(square 9)) ==> (* 9 9)
>
> Perhaps that's enough to get you started.

Of course, This defmacro is wrong:

(let ((i 0)) (square (aref #(1 2 3) (incf i))))
--> 6 ; !!!

SQUARE is best defined as a function, (and possibly a compiler-macro
function).


When you really need a macro, the question is what you do with the
"places".    Depending on the kind of operation (read, write,
read/write) and the number of them, you can implement an unsurprizing
macro by:

- just binding the places read to temporary lexical variables.
     (let ((temps (loop repeat (length places) collect (gensym))))
       `(let ,(mapcar (function list) temps places)
           ,(expand-stuff-with temps #|instead of places|#)))

- write directly to the place (if you only do that to it), but you
  might still want to use the setf-expansion to avoid out of order
  evaluation.

- use the setf expansions of the places to first bind the read values
  to temps, and finally write these temps to the places.  In the case
  of ROTATEF it's what you need to do.  Here is for example, clisp's
  ROTATEF:

(defmacro rotatef (&rest args &environment env)
  (when (null args) (return-from rotatef NIL))
  (when (null (cdr args)) (return-from rotatef `(PROGN ,(car args) NIL)))
  (do* ((arglist args (cdr arglist))
        (res (list 'LET* nil nil))
        last-setterform
        (tail (cdr res))
        (bindlist '())
        (all-stores '())
        last-stores
        first-stores)
       ((null arglist)
        (setf (second res) (nreverse bindlist)
              (second (third res)) last-stores
              (cdr tail) (nconc (nreverse all-stores) (devalue-form last-setterform))
              (cdr (last res)) (list nil))
        res)
    (multiple-value-bind (temps subforms stores setterform getterform)
        (get-setf-expansion (first arglist) env)
      (setq bindlist (nreconc (mapcar #'list temps subforms) bindlist))
      (setf (cadr tail) (list 'MULTIPLE-VALUE-BIND last-stores getterform nil))
      (setq tail (cddadr tail))
      (if (null first-stores)
          (setq first-stores stores)
          (setq all-stores (revappend (devalue-form last-setterform) all-stores)))
      (setq last-stores stores last-setterform setterform))))


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

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.
From: Pascal Bourguignon
Subject: Re: rotatef inner workings (newbie)
Date: 
Message-ID: <87y7gpk6k8.fsf@voyager.informatimago.com>
······@gmail.com writes:

> For simple variables:
> (setf a 0)
> a => 0
> (setf b 1)
> b => 1
> (rotatef a b)
> a => 1
> b => 0
>
> How would I write a macro that emulates this?  As a function such as
> (defun my-rotatef (x y)
>               (let ((tmp x))
>                   (setf x y y tmp) nil))
>
> Obviously doesn't affect anything outside it's code.
> (setf a 0 b 1)
> (my-rotatef a b)
> a => 0
> b => 1


You can see how a macro expands in a given use case with macroexpand.

(macroexpand-1 '(rotatef a b))
(macroexpand-1 '(rotatef a b c d))
...

but in this case, it's more complex.  The best way is to read the
source! 


The point is that rotatef takes places, and you want to avoid double
evaluation of the arguments used in computing the places, since they
may have side effects:

(let ((i j))
  (rotatef (aref a (incf i))  (aref a (incf i))))

should rotate (aref (+ j 1)) and (aref (+ j 2)), and leave i = (+ j 2).


For this, you can use GET-SETF-EXPANSION to get the setf expansions of
the places.



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

"Klingon function calls do not have "parameters" -- they have
"arguments" and they ALWAYS WIN THEM."