From: Mirko
Subject: macro & macrolet combo
Date: 
Message-ID: <ed705651-413c-4fb4-afb5-5acab245bb07@h5g2000yqh.googlegroups.com>
Hello,

I am trying to combine two macros into one with the latter one using a
macrolet.  However, I have trouble with an unbound variable.  Here are
the specifics

I would like to combine these two macros:

(defmacro with-xy-file ((stream file) &body body)
  "read an `*.xy' file and its header"
  `(let (title xlabel ylabel)
     (with-open-file (,stream ,file
			      :direction :input)
       (setf title (read ,stream))
       (let ((form (read ,stream)))
	 (setf xlabel (second form)
	       ylabel (third form)))
       ,@body)))

(defmacro read-xy-data-block ((x y))
"place contents of next data block into x&y"
  `(let ((form (read stream))
	 label)
     (setf label (cadr form))
     (loop for (this-x this-y) on (rest form) by #'cddr
	  do (push this-x ,x)
	  do (push this-y ,y))
     (values ,x ,y)))

into a single one, since read-xy-data-block does not make much sense
outside of an with-xy-file.

Example usage is:
(with-xy-file1 (stream "320-1--573-1--673-1.xy")
  (let (x y)
    (read-xy-data-block1 (stream x y))
    (do-stuff x y)))

My current form is as follows (I essentially placed the defmacro into
a macrolet)

(defmacro with-xy-file1 ((stream file) &body body)
  "read an `*.xy' file and its header and execute `body'.

  Provide helper function `(read-xy-data-block (stream x y))' to read
  additional set of data "
  `(macrolet ((read-xy-data-block1 ((stream x y))  ;;; !!!!!!!! how to
get read of the stream parameter?
		`(let ((form (read ,stream))
		       label)
		   (setf label (cadr form))
		   (loop for (this-x this-y) on (rest form) by #'cddr
		      do (push this-x ,x)
		      do (push this-y ,y))
		   (values ,x ,y))))
     (let (title xlabel ylabel)
       (with-open-file (,stream ,file
				:direction :input)
	 (setf title (read ,stream))
	 (let ((form (read ,stream)))
	   (setf xlabel (second form)
		 ylabel (third form)))
	 ,@body))))

But for this to work, I had to explictly pass the stream to the read-
xy-data-block1 macro.
I really don't need the stream to be passed.  Ideally, I would like to
have something like

(defmacro with-xy-file1 ((stream file) &body body)  ;;;!!! stream is
the topic of discussion below
  "read an `*.xy' file and its header and execute `body'.

  Provide helper function `(read-xy-data-block (stream x y))' to read
  additional set of data "
  `(macrolet ((read-xy-data-block1 ((x y))  ;;; !!!!!!!! no stream
here
		`(let ((form (read ,stream)) ;;; this stream should refer to the one
from the argument list
		       label)
		   (setf label (cadr form))
		   (loop for (this-x this-y) on (rest form) by #'cddr
		      do (push this-x ,x)
		      do (push this-y ,y))
		   (values ,x ,y))))
     (let (title xlabel ylabel)
       (with-open-file (,stream ,file
				:direction :input)
	 (setf title (read ,stream))
	 (let ((form (read ,stream)))
	   (setf xlabel (second form)
		 ylabel (third form)))
	 ,@body))))

I tried several combinations of commas in the macrolet stream, but
none worked.  I went to the hyperspec, and my eyes glazed over.
(Interestingly, graham's on-lisp does not mention macrolet at all)

What is the dark magic to make it work?  Or is it even legit to use a
macrolet in a macro?  And if it cannot be done, how do I do it in
Ruby?

Thank you,

Mirko

From: TomSW
Subject: Re: macro & macrolet combo
Date: 
Message-ID: <cf2c23ac-1d0b-4d55-a6f8-92bc5e788429@v42g2000yqj.googlegroups.com>
On Feb 11, 11:17 pm, Mirko <·············@gmail.com> wrote:
> Hello,
>
> I am trying to combine two macros into one with the latter one using a
> macrolet.  However, I have trouble with an unbound variable.  Here are
> the specifics

The normal way to combine macros is to use one macro inside another.

You're making your life difficult by creating macros that bind symbols
that aren't paremetised. Eg, with-xy-file sets title, xlabel and
ylabel without giving the user of the macro the chance to use other
symbols; read-xy-data-block assumes that stream is bound. This is a
bad idea, and is the reason you're having problems combining macros.

(defmacro macro1 ((foo bar baz) &body body)
...)

(defmacro macro2 ((foo ugh) &body body)
...)

(defmacro macro12 ((ugh bar baz) &body body)
  (let ((foo (gensym)))
   `(macro1 (,foo ,bar ,baz)
      (macro2 (,foo ,ugh)
        ,@body))))
From: Thomas A. Russ
Subject: Re: macro & macrolet combo
Date: 
Message-ID: <ymiwsbwflek.fsf@blackcat.isi.edu>
Mirko <·············@gmail.com> writes:

> I am trying to combine two macros into one with the latter one using a
> macrolet.  However, I have trouble with an unbound variable.  Here are
> the specifics

Well, you shouldn't really be doing it this way.  But I don't have time
to go into all of the reasons.  I hope someone else does.

You are entering the somewhat arcane realm of nested backquotes, which
is where the specific issue that you are struggling with lies.  Try the
modification below and see if that does what you want.  Don't forget to
remove the stream argument from READ-XY-DATA-BLOCK1 and its invocation.


> My current form is as follows (I essentially placed the defmacro into
> a macrolet)
> 
> (defmacro with-xy-file1 ((stream file) &body body)
>   "read an `*.xy' file and its header and execute `body'.
> 
>   Provide helper function `(read-xy-data-block (stream x y))' to read
>   additional set of data "
>   ;;; !!!!!!!! how to get read of the stream parameter?
>   `(macrolet ((read-xy-data-block1 ((stream x y))
> 		`(let ((form (read ,stream))

                                   ,',stream


> 		       label)
> 		   (setf label (cadr form))
> 		   (loop for (this-x this-y) on (rest form) by #'cddr
> 		      do (push this-x ,x)
> 		      do (push this-y ,y))
> 		   (values ,x ,y))))
>      (let (title xlabel ylabel)
>        (with-open-file (,stream ,file
> 				:direction :input)
> 	 (setf title (read ,stream))
> 	 (let ((form (read ,stream)))
> 	   (setf xlabel (second form)
> 		 ylabel (third form)))
> 	 ,@body))))
> 
> But for this to work, I had to explictly pass the stream to the read-
> xy-data-block1 macro.
> I really don't need the stream to be passed.  Ideally, I would like to
> have something like

> I tried several combinations of commas in the macrolet stream, but
> none worked.  I went to the hyperspec, and my eyes glazed over.
> (Interestingly, graham's on-lisp does not mention macrolet at all)

Well, there are additional combinations of commas and importantly quotes
that you would have needed to try.  Actually, the ,', form is quite
common for nested backquotes.

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Mirko
Subject: Re: macro & macrolet combo
Date: 
Message-ID: <7274ffb2-aaaf-423a-b72a-51c37fd4113e@e18g2000yqo.googlegroups.com>
On Feb 11, 9:18 pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
> Mirko <·············@gmail.com> writes:
> > I am trying to combine two macros into one with the latter one using a
> > macrolet.  However, I have trouble with an unbound variable.  Here are
> > the specifics
>
> Well, you shouldn't really be doing it this way.  But I don't have time
> to go into all of the reasons.  I hope someone else does.
>
> You are entering the somewhat arcane realm of nested backquotes, which
> is where the specific issue that you are struggling with lies.  Try the
> modification below and see if that does what you want.  Don't forget to
> remove the stream argument from READ-XY-DATA-BLOCK1 and its invocation.
>
> > My current form is as follows (I essentially placed the defmacro into
> > a macrolet)
>
> > (defmacro with-xy-file1 ((stream file) &body body)
> >   "read an `*.xy' file and its header and execute `body'.
>
> >   Provide helper function `(read-xy-data-block (stream x y))' to read
> >   additional set of data "
> >   ;;; !!!!!!!! how to get read of the stream parameter?
> >   `(macrolet ((read-xy-data-block1 ((stream x y))
> >            `(let ((form (read ,stream))
>
>                                    ,',stream
>
>
>
> >                   label)
> >               (setf label (cadr form))
> >               (loop for (this-x this-y) on (rest form) by #'cddr
> >                  do (push this-x ,x)
> >                  do (push this-y ,y))
> >               (values ,x ,y))))
> >      (let (title xlabel ylabel)
> >        (with-open-file (,stream ,file
> >                            :direction :input)
> >     (setf title (read ,stream))
> >     (let ((form (read ,stream)))
> >       (setf xlabel (second form)
> >             ylabel (third form)))
> >     ,@body))))
>
> > But for this to work, I had to explictly pass the stream to the read-
> > xy-data-block1 macro.
> > I really don't need the stream to be passed.  Ideally, I would like to
> > have something like
> > I tried several combinations of commas in the macrolet stream, but
> > none worked.  I went to the hyperspec, and my eyes glazed over.
> > (Interestingly, graham's on-lisp does not mention macrolet at all)
>
> Well, there are additional combinations of commas and importantly quotes
> that you would have needed to try.  Actually, the ,', form is quite
> common for nested backquotes.
>
> --
> Thomas A. Russ,  USC/Information Sciences Institute

Yes, that worked.  Many thanks. (And sure enough, I found the
combination in Ch. 7 of `on macros')

Here is the actual code:

(defmacro with-xy-file ((stream file) &body body)
  "read an `*.xy' file and its header and execute `body'"
  `(macrolet ((read-xy-data-block ((x y))
		 "Read next data block into x&y"
		`(let ((form (read ,',stream))
		       label)
		   (setf label (cadr form))
		   (loop for (this-x this-y) on (rest form) by #'cddr
		      do (push this-x ,x)
		      do (push this-y ,y))
		   (values ,x ,y))))
     (let (title xlabel ylabel)
       (with-open-file (,stream ,file
				:direction :input)
	 (setf title (read ,stream))
	 (let ((form (read ,stream)))
	   (setf xlabel (second form)
		 ylabel (third form)))
	 ,@body))))
From: William James
Subject: Re: macro & macrolet combo
Date: 
Message-ID: <gn0ia80gu7@enews2.newsguy.com>
Thomas A. Russ wrote:

> Mirko <·············@gmail.com> writes:
> 
> > I am trying to combine two macros into one with the latter one
> > using a macrolet.  However, I have trouble with an unbound
> > variable.  Here are the specifics
> 
> Well, you shouldn't really be doing it this way.  But I don't have
> time to go into all of the reasons.  I hope someone else does.
> 
> You are entering the somewhat arcane realm of nested backquotes, which
> is where the specific issue that you are struggling with lies.  Try
> the modification below and see if that does what you want.  Don't
> forget to remove the stream argument from READ-XY-DATA-BLOCK1 and its
> invocation.
> 
> 
> > My current form is as follows (I essentially placed the defmacro
> > into a macrolet)
> > 
> > (defmacro with-xy-file1 ((stream file) &body body)
> >   "read an `*.xy' file and its header and execute `body'.
> > 
> >   Provide helper function `(read-xy-data-block (stream x y))' to
> > read   additional set of data "
> >   ;;; !!!!!!!! how to get read of the stream parameter?
> >   `(macrolet ((read-xy-data-block1 ((stream x y))
> > 		`(let ((form (read ,stream))
> 
>                                    ,',stream
> 
> 
> > 		       label)
> > 		   (setf label (cadr form))
> > 		   (loop for (this-x this-y) on (rest form) by #'cddr
> > 		      do (push this-x ,x)
> > 		      do (push this-y ,y))
> > 		   (values ,x ,y))))
> >      (let (title xlabel ylabel)
> >        (with-open-file (,stream ,file
> > 				:direction :input)
> > 	 (setf title (read ,stream))
> > 	 (let ((form (read ,stream)))
> > 	   (setf xlabel (second form)
> > 		 ylabel (third form)))
> > 	 ,@body))))
> > 
> > But for this to work, I had to explictly pass the stream to the
> > read- xy-data-block1 macro.
> > I really don't need the stream to be passed.  Ideally, I would like
> > to have something like
> 
> > I tried several combinations of commas in the macrolet stream, but
> > none worked.  I went to the hyperspec, and my eyes glazed over.
> > (Interestingly, graham's on-lisp does not mention macrolet at all)
> 
> Well, there are additional combinations of commas and importantly
> quotes that you would have needed to try.  Actually, the ,', form is
> quite common for nested backquotes.

I cannot help but marvel at the insolent ease with which Commune Lisp
transmogrifies a mole hill into a mountain.
From: Mirko
Subject: Re: macro & macrolet combo
Date: 
Message-ID: <dc334f76-d0bb-4eb8-948f-de51a3b4e2a7@j38g2000yqa.googlegroups.com>
On Feb 12, 2:15 am, "William James" <·········@yahoo.com> wrote:
> Thomas A. Russ wrote:
> > Mirko <·············@gmail.com> writes:
>
> > > I am trying to combine two macros into one with the latter one
> > > using a macrolet.  However, I have trouble with an unbound
> > > variable.  Here are the specifics
>
> > Well, you shouldn't really be doing it this way.  But I don't have
> > time to go into all of the reasons.  I hope someone else does.
>
> > You are entering the somewhat arcane realm of nested backquotes, which
> > is where the specific issue that you are struggling with lies.  Try
> > the modification below and see if that does what you want.  Don't
> > forget to remove the stream argument from READ-XY-DATA-BLOCK1 and its
> > invocation.
>
> > > My current form is as follows (I essentially placed the defmacro
> > > into a macrolet)
>
> > > (defmacro with-xy-file1 ((stream file) &body body)
> > >   "read an `*.xy' file and its header and execute `body'.
>
> > >   Provide helper function `(read-xy-data-block (stream x y))' to
> > > read   additional set of data "
> > >   ;;; !!!!!!!! how to get read of the stream parameter?
> > >   `(macrolet ((read-xy-data-block1 ((stream x y))
> > >               `(let ((form (read ,stream))
>
> >                                    ,',stream
>
> > >                      label)
> > >                  (setf label (cadr form))
> > >                  (loop for (this-x this-y) on (rest form) by #'cddr
> > >                     do (push this-x ,x)
> > >                     do (push this-y ,y))
> > >                  (values ,x ,y))))
> > >      (let (title xlabel ylabel)
> > >        (with-open-file (,stream ,file
> > >                               :direction :input)
> > >        (setf title (read ,stream))
> > >        (let ((form (read ,stream)))
> > >          (setf xlabel (second form)
> > >                ylabel (third form)))
> > >        ,@body))))
>
> > > But for this to work, I had to explictly pass the stream to the
> > > read- xy-data-block1 macro.
> > > I really don't need the stream to be passed.  Ideally, I would like
> > > to have something like
>
> > > I tried several combinations of commas in the macrolet stream, but
> > > none worked.  I went to the hyperspec, and my eyes glazed over.
> > > (Interestingly, graham's on-lisp does not mention macrolet at all)
>
> > Well, there are additional combinations of commas and importantly
> > quotes that you would have needed to try.  Actually, the ,', form is
> > quite common for nested backquotes.
>
> I cannot help but marvel at the insolent ease with which Commune Lisp
> transmogrifies a mole hill into a mountain.

Sorry dude -- you have not seen the light.