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
······@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]
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.)
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.
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.
······@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."