From: Tamas
Subject: macroexpand question - where does myquote go
Date: 
Message-ID: <f82c3747-c3f6-4064-93f4-24475cbb7ed7@m45g2000hsb.googlegroups.com>
Consider the macro

(defmacro foo (n &optional (type 'double-float))
  `(make-array ,n :element-type ,type))

(foo 5) expands to (MAKE-ARRAY 5 :ELEMENT-TYPE DOUBLE-FLOAT)

but

(macroexpand '(foo 5 'double-float)) expands to (MAKE-ARRAY 5 :ELEMENT-
TYPE 'DOUBLE-FLOAT)

I am trying to figure out why the quote disappears from the default
for the type argument, 'double-float.  I think that there is something
fundamental I still don't get about macros, and I wonder if someone
would please explain it.

I already found that ''double-float as the default gives what I want
('double-float in the expansion), but I still don't know why that is,
or if it is the right way to do it.

Sorry if the question is stupid.

Thanks,

Tamas

From: Pascal Costanza
Subject: Re: macroexpand question - where does myquote go
Date: 
Message-ID: <6cn72kF3hrlvrU1@mid.individual.net>
Tamas wrote:
> Consider the macro
> 
> (defmacro foo (n &optional (type 'double-float))
>   `(make-array ,n :element-type ,type))
> 
> (foo 5) expands to (MAKE-ARRAY 5 :ELEMENT-TYPE DOUBLE-FLOAT)
> 
> but
> 
> (macroexpand '(foo 5 'double-float)) expands to (MAKE-ARRAY 5 :ELEMENT-
> TYPE 'DOUBLE-FLOAT)
> 
> I am trying to figure out why the quote disappears from the default
> for the type argument, 'double-float.  I think that there is something
> fundamental I still don't get about macros, and I wonder if someone
> would please explain it.
> 
> I already found that ''double-float as the default gives what I want
> ('double-float in the expansion), but I still don't know why that is,
> or if it is the right way to do it.
> 
> Sorry if the question is stupid.

No, it isn't. It's actually a little design bit in Lisp that is hard to 
grasp.

When you evaluate (quote a), you get the symbol a as a result.

So: (eval (quote a)) => a

When you evaluate the result of evaluating (quote a), the interpreter 
will consider this as an attempt to access a variable.

So: (eval (eval (quote a))) => some value, or an error if the variable 
doesn't exist

So quote prevents something from being evaluated, but quote is not 
"sticky". [1]

If you watch closely, you will notice that in your call to macroexpand, 
you actually already put two quotes to prevent an attempt to access to a 
variable double-float: the one for the complete form, and the one 
immediately in front of double-float.

In (foo 5), according to your definition, you have only one quote.

Note that (foo 5 'single-float) works fine with your macro definition, 
because the macroexpansion function will see the result of '(foo 5 
'single-float) to expand, so there are two quotes there!

However, it's probably more idiomatic to introduce the necessary quotes 
yourself in the macro definition:

(defmacro foo (n &optional (type 'double-float))
   `(make-array ,n :element-type ',type))

If you wanted to actually have the arguments to foo evaluated, it would 
be better to define this as a function:

(defun foo (n &optional (type 'double-float))
   (make-array n :element-type type))

...because in your version you don't take any advantage of the fact that 
you're defining a macro. In such cases, it's almost always better to use 
functions.

I hope this helps.


Pascal

[1] This is actually one of the "improvements" of 3-Lisp, that quote is 
"sticky" in that Lisp dialect. In 3-Lisp, (eval 'a) => 'a and (eval 
(eval 'a)) => 'a

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Tamas
Subject: Re: macroexpand question - where does myquote go
Date: 
Message-ID: <dc6dcc3d-c347-4748-b734-79fa5a3b550f@y38g2000hsy.googlegroups.com>
On Jun 28, 6:27 pm, Pascal Costanza <····@p-cos.net> wrote:

> So quote prevents something from being evaluated, but quote is not
> "sticky". [1]

Thanks Pascal.  I think I understand now.

> However, it's probably more idiomatic to introduce the necessary quotes
> yourself in the macro definition:
>
> (defmacro foo (n &optional (type 'double-float))
>    `(make-array ,n :element-type ',type))

I won't do that, since this macro might be called with arguments that
need to be evaluated, eg :type (if something 'double-float 'single-
float).  So in the actual code, I ended up using two quotes.

The example was a simplified version from an actual macro which
'vectorizes' expressions (see example in the docstring).  I feel that
I am out of my element writing complicated macros like this, so I
welcome constructive criticism.

(defmacro vectorize ((&rest vectors) expression
		     &key (result-element-type ''double-float)
		     (into nil))
  "Expand into a loop so that `expression' is evaluated in all
corresponding elements of the `vectors', where the name of the vector
will be replaced by the actual values the appropriate expression.
Results from the elementwise evaluation of expression will be returned
as a vector.

If `into' is non-nil, it has to contain the name of one of the
vectors, where the element will be placed.  All other parts of the
expression will have their original meaning (see example below).

Return the resulting vector (which is one of the original, if `into'
was specified).

Example:

 (let ((a #(1d0 2d0 3d0))
       (b #(4d0 5d0 6d0))
       (c 0.25d0))
   (vectorize (a b)
 	      (+ a b c 0.25)))  ; => #(5.5d0 7.5d0 9.5d0)

Notes:

1. Obviously, `vectors' can only contain symbols (otherwise the macro
would not know which vector you are referring to).  If you want to use
a vector you just constructed, use let as above.

2. If you want to put the result in an array that has a different
element type, you need to use coerce explicitly in `expression'."
  (assert (every #'symbolp vectors))
  (assert (plusp (length vectors)))
  (with-unique-names (result n i)
    ;; we setup another name for each vector, otherwise the symbol
    ;; macros would be recursive
    (let ((shadowed-vector-names (mapcar (lambda (x) (gensym (symbol-
name x)))
					 vectors)))
      `(progn
	 ,result-element-type
	 ;; check first vector
	 (assert (vectorp ,(car vectors)))
	 ;; assign vectors to shadow names
	 (let (,@(mapcar #'list shadowed-vector-names vectors))
	   (let* ((,n (length ,(car vectors))))
	     ;; check that all vectors are the same length
	     (assert (every (lambda (v)
			      (and (= (length v) ,n) (vectorp v)))
			    (list ,@(cdr vectors))))
	     ;; setup result if necessary, if not, results end up in
	     ;; the vector specified by `into'
	     (let ((,result ,(if into
				 (progn
				   (assert (and (symbolp into)
						(member into vectors)))
				   into)
				 `(make-array ,n :element-type
					      ,result-element-type))))
	       ;; symbol macros index in shadow names
	       (symbol-macrolet (,@(mapcar
				    (lambda (name shadowed-name)
				      (list name (list 'aref shadowed-name i)))
				    vectors
				    shadowed-vector-names))
		 ;; the loop calculates the expression
		 (dotimes (,i ,n)
		   (setf (aref ,result ,i) ,expression)))
	       ,result)))))))

Thanks,

Tamas
From: Steven M. Haflich
Subject: Re: macroexpand question - where does myquote go
Date: 
Message-ID: <qoX9k.10218$xZ.10051@nlpi070.nbdc.sbc.com>
Pascal Costanza wrote:

> ...because in your version you don't take any advantage of the fact that 
> you're defining a macro. In such cases, it's almost always better to use 
> functions.

I don't want to disagree with Pascal, since his response is generally 
correct, but I want to add that there is a slight, possible value to the 
macro.

The macro definition allows the compiler to see the make-array call, and 
the implementation may be able to optimize that call in certain ways 
where the optimization would be less likely if it had to peek inside the 
function definition (even assuming the function had already been 
defined).  This is even more likely to be significant if the allocation 
were declared or inferrable to be dynamic-extent and the implementation 
were capable of doing stack allocation of that array type.
From: Pascal Costanza
Subject: Re: macroexpand question - where does myquote go
Date: 
Message-ID: <6cr6ulF3g3p31U2@mid.individual.net>
Steven M. Haflich wrote:
> Pascal Costanza wrote:
> 
>> ...because in your version you don't take any advantage of the fact 
>> that you're defining a macro. In such cases, it's almost always better 
>> to use functions.
> 
> I don't want to disagree with Pascal, since his response is generally 
> correct, but I want to add that there is a slight, possible value to the 
> macro.
> 
> The macro definition allows the compiler to see the make-array call, and 
> the implementation may be able to optimize that call in certain ways 
> where the optimization would be less likely if it had to peek inside the 
> function definition (even assuming the function had already been 
> defined).  This is even more likely to be significant if the allocation 
> were declared or inferrable to be dynamic-extent and the implementation 
> were capable of doing stack allocation of that array type.


OK, but I would still suggest to stick to a function definition, and 
additionally provide a compiler macro to allow such an optimization.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Pascal J. Bourguignon
Subject: Re: macroexpand question - where does myquote go
Date: 
Message-ID: <87skuvqx9y.fsf@hubble.informatimago.com>
"Steven M. Haflich" <···@alum.mit.edu> writes:

> Pascal Costanza wrote:
>
>> ...because in your version you don't take any advantage of the fact
>> that you're defining a macro. In such cases, it's almost always
>> better to use functions.
>
> I don't want to disagree with Pascal, since his response is generally
> correct, but I want to add that there is a slight, possible value to
> the macro.
>
> The macro definition allows the compiler to see the make-array call,
> and the implementation may be able to optimize that call in certain
> ways where the optimization would be less likely if it had to peek
> inside the function definition (even assuming the function had already
> been defined).  This is even more likely to be significant if the
> allocation were declared or inferrable to be dynamic-extent and the
> implementation were capable of doing stack allocation of that array
> type.

(declare (inline foo))
(defun foo ...)

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

Nobody can fix the economy.  Nobody can be trusted with their finger
on the button.  Nobody's perfect.  VOTE FOR NOBODY.
From: Kaz Kylheku
Subject: Re: macroexpand question - where does myquote go
Date: 
Message-ID: <9a5f75b5-0385-4a43-b6fb-4c71a35fd50a@s21g2000prm.googlegroups.com>
On Jun 28, 9:14 am, Tamas <······@gmail.com> wrote:
> Consider the macro
>
> (defmacro foo (n &optional (type 'double-float))
>   `(make-array ,n :element-type ,type))

The expression which gives the default value of an optional parameter
is evaluated, even if it is in a macro lambda list.

I.e. if you were to write (type (+ 2 2)), then the default value
produced if the argument is not given shall be 4, not the list (+ 2
2).

> (foo 5) expands to (MAKE-ARRAY 5 :ELEMENT-TYPE DOUBLE-FLOAT)
>
> but
>
> (macroexpand '(foo 5 'double-float)) expands to (MAKE-ARRAY 5 :ELEMENT-
> TYPE 'DOUBLE-FLOAT)

Because FOO is a macro, its parameters take on the source code of the
argument expressions, rather than their values. So the TYPE parameter
here has the value (QUOTE DOUBLE-FLOAT). That is exactly the argument
expression itself.

If you want (QUOTE DOUBLE-FLOAT) to be the default value of the
parameter, you have to specify that as &OPTIONAL (TYPE '(QUOTE DOUBLE-
FLOAT)) which of course is the same thing as what you discovered:
(TYPE ''DOUBLE-FLOAT).

> I am trying to figure out why the quote disappears from the default
> for the type argument, 'double-float.

Quote disappears under evaluation in the same way that other functions
and operators disappear. The result of (+ 4) is 4, and so the + has
``disappeared''.