[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.lisp

PG's On Lisp: do-tuples/o errata error?

Malice

4/10/2016 12:05:00 AM

So I was reading throught PG's On Lisp, and when dealing with do-tuples/o, I wrote it down and tested it:

(defmacro do-tuples/o (params source &body body)
(when params
(with-gensyms (src)
`(prog ((,src ,source))
(mapc (lambda ,params ,@body)
,@(map0-n (lambda (n) `(nthcdr ,n ,src))
(1- (length params))))))))

The version is slightly changed, but no change in logic was made.

Now the other time I was reading errata to On Lisp, and I found this:

p. 156. In do-tuples/o the expression (1- (length parms)) should be (- (length source) (length parms)). Reported by Roland. (at netquant.com.br)

So I changed the code:

(defmacro do-tuples/o (params source &body body)
(when params
(with-gensyms (src)
`(prog ((,src ,source))
(mapc (lambda ,params ,@body)
,@(map0-n (lambda (n) `(nthcdr ,n ,src))
(- (length source) (length params))))))))

Now let's run both macros in the following example:

(do-tuples/o (a b) '(a b c d)
(princ (list a b)))

To my surprise, the first example works as intended, while the second one results in an error. Is the errata wrong, and the original correct?
2 Answers

Pascal J. Bourguignon

4/10/2016 10:52:00 AM

0

Malice <gwmaniak@gmail.com> writes:

> So I was reading throught PG's On Lisp, and when dealing with
> do-tuples/o, I wrote it down and tested it:
>
> (defmacro do-tuples/o (params source &body body)
> (when params
> (with-gensyms (src)
> `(prog ((,src ,source))
> (mapc (lambda ,params ,@body)
> ,@(map0-n (lambda (n) `(nthcdr ,n ,src))
> (1- (length params))))))))
>
> The version is slightly changed, but no change in logic was made.
>
> Now the other time I was reading errata to On Lisp, and I found this:
>
> p. 156. In do-tuples/o the expression (1- (length parms)) should be (-
> (length source) (length parms)). Reported by Roland. (at
> netquant.com.br)
>
> So I changed the code:
>
> (defmacro do-tuples/o (params source &body body)
> (when params
> (with-gensyms (src)
> `(prog ((,src ,source))
> (mapc (lambda ,params ,@body)
> ,@(map0-n (lambda (n) `(nthcdr ,n ,src))
> (- (length source) (length params))))))))
>
> Now let's run both macros in the following example:
>
> (do-tuples/o (a b) '(a b c d)
> (princ (list a b)))
>
> To my surprise, the first example works as intended, while the second
> one results in an error. Is the errata wrong, and the original
> correct?

When you wan to debug a macro, the first thing to do is to use
macroexpand (or macroexpand-1 if it's a macro expanding to calls to
itself).


Your macro:

cl-user> (pprint (macroexpand
'(do-tuples/o-1 (a b) '(a b c d)
(princ (list a b)))))

(block nil
(let ((#1=#:src6776 '(a b c d)))
(tagbody (mapc (lambda (a b) (princ (list a b)))
(nthcdr 0 #1#)
(nthcdr 1 #1#)))))
; No value


Your macro with Roland's patch:

cl-user> (pprint (macroexpand
'(do-tuples/o-2 (a b) '(a b c d)
(princ (list a b)))))

(block nil
(let ((#1=#:src6777 '(a b c d)))
(tagbody (mapc (lambda (a b) (princ (list a b)))
(nthcdr 0 #1#)))))
; No value
cl-user>

You can see immediately what is wrong with the second macro: it doesn't
pass the right number of arguments.

Now, why is that?

What is the length of SOURCE?

You don't have to guess. Macros are functions like any other function,
you can debug with the usual tools. eg. print-debugging:


cl-user> (defmacro do-tuples/o-2 (params source &body body)
(format t "source = ~S~% length = ~S~%" source (length source))
(when params
(with-gensyms (src)
`(prog ((,src ,source))
(mapc (lambda ,params ,@body)
,@(map0-n (lambda (n) `(nthcdr ,n ,src))
(- (length source) (length params))))))))
do-tuples/o-2
cl-user> (pprint (macroexpand
'(do-tuples/o-2 (a b) '(a b c d)
(princ (list a b)))))
source = '(a b c d)
length = 2

(block nil
(let ((#1=#:src6788 '(a b c d)))
(tagbody (mapc (lambda (a b) (princ (list a b))) (nthcdr 0 #1#)))))
; No value
cl-user>

Obviously, SOURCE is bound to (quote (a b c d)), so it's length is 2.
It is also irrelevant compared to the length of PARAMS, that is, the
number of parameters. Also, SOURCE could be a non-list atom!

In:

(let ((list (list 1 2 3 4)))
(do-tuples/o-2 (a b) list (print (list a b ))))

SOURCE will be bound to LIST. A symbol, not a list.

The patch is erroneous.


Your macro is perfectly correct, there's no need to patch it.

--
__Pascal Bourguignon__ http://www.informat...
â??The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.� -- Carl Bass CEO Autodesk

Malice

4/10/2016 12:54:00 PM

0

On Sunday, 10 April 2016 12:51:38 UTC+2, informatimago wrote:
> Malice <gwmaniak@gmail.com> writes:
>
> > So I was reading throught PG's On Lisp, and when dealing with
> > do-tuples/o, I wrote it down and tested it:
> >
> > (defmacro do-tuples/o (params source &body body)
> > (when params
> > (with-gensyms (src)
> > `(prog ((,src ,source))
> > (mapc (lambda ,params ,@body)
> > ,@(map0-n (lambda (n) `(nthcdr ,n ,src))
> > (1- (length params))))))))
> >
> > The version is slightly changed, but no change in logic was made.
> >
> > Now the other time I was reading errata to On Lisp, and I found this:
> >
> > p. 156. In do-tuples/o the expression (1- (length parms)) should be (-
> > (length source) (length parms)). Reported by Roland. (at
> > netquant.com.br)
> >
> > So I changed the code:
> >
> > (defmacro do-tuples/o (params source &body body)
> > (when params
> > (with-gensyms (src)
> > `(prog ((,src ,source))
> > (mapc (lambda ,params ,@body)
> > ,@(map0-n (lambda (n) `(nthcdr ,n ,src))
> > (- (length source) (length params))))))))
> >
> > Now let's run both macros in the following example:
> >
> > (do-tuples/o (a b) '(a b c d)
> > (princ (list a b)))
> >
> > To my surprise, the first example works as intended, while the second
> > one results in an error. Is the errata wrong, and the original
> > correct?
>
> When you wan to debug a macro, the first thing to do is to use
> macroexpand (or macroexpand-1 if it's a macro expanding to calls to
> itself).
>
>
> Your macro:
>
> cl-user> (pprint (macroexpand
> '(do-tuples/o-1 (a b) '(a b c d)
> (princ (list a b)))))
>
> (block nil
> (let ((#1=#:src6776 '(a b c d)))
> (tagbody (mapc (lambda (a b) (princ (list a b)))
> (nthcdr 0 #1#)
> (nthcdr 1 #1#)))))
> ; No value
>
>
> Your macro with Roland's patch:
>
> cl-user> (pprint (macroexpand
> '(do-tuples/o-2 (a b) '(a b c d)
> (princ (list a b)))))
>
> (block nil
> (let ((#1=#:src6777 '(a b c d)))
> (tagbody (mapc (lambda (a b) (princ (list a b)))
> (nthcdr 0 #1#)))))
> ; No value
> cl-user>
>
> You can see immediately what is wrong with the second macro: it doesn't
> pass the right number of arguments.
>
> Now, why is that?
>
> What is the length of SOURCE?
>
> You don't have to guess. Macros are functions like any other function,
> you can debug with the usual tools. eg. print-debugging:
>
>
> cl-user> (defmacro do-tuples/o-2 (params source &body body)
> (format t "source = ~S~% length = ~S~%" source (length source))
> (when params
> (with-gensyms (src)
> `(prog ((,src ,source))
> (mapc (lambda ,params ,@body)
> ,@(map0-n (lambda (n) `(nthcdr ,n ,src))
> (- (length source) (length params))))))))
> do-tuples/o-2
> cl-user> (pprint (macroexpand
> '(do-tuples/o-2 (a b) '(a b c d)
> (princ (list a b)))))
> source = '(a b c d)
> length = 2
>
> (block nil
> (let ((#1=#:src6788 '(a b c d)))
> (tagbody (mapc (lambda (a b) (princ (list a b))) (nthcdr 0 #1#)))))
> ; No value
> cl-user>
>
> Obviously, SOURCE is bound to (quote (a b c d)), so it's length is 2.
> It is also irrelevant compared to the length of PARAMS, that is, the
> number of parameters. Also, SOURCE could be a non-list atom!
>
> In:
>
> (let ((list (list 1 2 3 4)))
> (do-tuples/o-2 (a b) list (print (list a b ))))
>
> SOURCE will be bound to LIST. A symbol, not a list.
>
> The patch is erroneous.
>
>
> Your macro is perfectly correct, there's no need to patch it.
>
> --
> __Pascal Bourguignon__ http://www.informat...
> "The factory of the future will have only two employees, a man and a
> dog. The man will be there to feed the dog. The dog will be there to
> keep the man from touching the equipment." -- Carl Bass CEO Autodesk

Thanks. I've noticed that this "patch" is "reported", which means that someone sent it, but PG didn't have time to check it. I wrote a short email with hope that he'll have time to read it about this. Thank you for explanation.