From: Thaddeus L Olczyk
Subject: Looping over array.
Date: 
Message-ID: <3c87b0b5.309836171@nntp.interaccess.com>
I'm getting tierd of doing

(loop for i from 0 to (- (length array))
         do
           (let ((x (aref i array))) 
                  ; For one thing I keep forgetting which goes first
                  ; i or array.
            ...

is there some wqay of doing something like:

(loop for x element-of array
         do ....

From: Wade Humeniuk
Subject: Re: Looping over array.
Date: 
Message-ID: <a68bou$4e2$1@news3.cadvision.com>
"Thaddeus L Olczyk" <······@interaccess.com> wrote in message
·······················@nntp.interaccess.com...
> I'm getting tierd of doing
>
> (loop for i from 0 to (- (length array))
>          do
>            (let ((x (aref i array)))
>                   ; For one thing I keep forgetting which goes first
>                   ; i or array.
>             ...
>
> is there some wqay of doing something like:
>
> (loop for x element-of array
>          do ....

(loop for x across array do ......

Array is of type vector.

Wade
From: Glenn Burnside
Subject: Re: Looping over array.
Date: 
Message-ID: <u8fhtrks7tbd9f@corp.supernews.com>
Forgive me for jumping in here in all my newbie glory, but if you want to do
something for each element in an array, can you not use mapcar?  I thought
that it worked for sequences in general - not just lists but also vectors
and arrays.

GB
"Wade Humeniuk" <········@cadvision.com> wrote in message
·················@news3.cadvision.com...
>
> "Thaddeus L Olczyk" <······@interaccess.com> wrote in message
> ·······················@nntp.interaccess.com...
> > I'm getting tierd of doing
> >
> > (loop for i from 0 to (- (length array))
> >          do
> >            (let ((x (aref i array)))
> >                   ; For one thing I keep forgetting which goes first
> >                   ; i or array.
> >             ...
> >
> > is there some wqay of doing something like:
> >
> > (loop for x element-of array
> >          do ....
>
> (loop for x across array do ......
>
> Array is of type vector.
>
> Wade
>
>
From: Wade Humeniuk
Subject: Re: Looping over array.
Date: 
Message-ID: <a68jdg$78c$1@news3.cadvision.com>
"Glenn Burnside" <··············@ni.com> wrote in message
···················@corp.supernews.com...
> Forgive me for jumping in here in all my newbie glory, but if you want to
do
> something for each element in an array, can you not use mapcar?  I thought
> that it worked for sequences in general - not just lists but also vectors
> and arrays.


This is true.  But usually I only use map when I am transforming a sequence
into a sequence of equal size.  I still use iteration for things like

CL-USER 5 > (loop for c across "Hello World!"
                  when (char= #\l c) count 1)
3

instead of map.

CL-USER 6 > (let ((number-of-ls 0))
              (map nil (lambda (c) (when (char= c #\l)
                                     (incf number-of-ls)))
                   "Hello World!")
              number-of-ls)
3

CL-USER 7 >

Wade
From: Joe Marshall
Subject: Re: Looping over array.
Date: 
Message-ID: <tDRh8.105$44.81845@typhoon.ne.ipsvc.net>
"Wade Humeniuk" <········@cadvision.com> wrote in message
·················@news3.cadvision.com...
>
> This is true.  But usually I only use map when I am transforming a
sequence
> into a sequence of equal size.  I still use iteration for things like
>
> CL-USER 5 > (loop for c across "Hello World!"
>                   when (char= #\l c) count 1)
> 3
>
> instead of map.
>
> CL-USER 6 > (let ((number-of-ls 0))
>               (map nil (lambda (c) (when (char= c #\l)
>                                      (incf number-of-ls)))
>                    "Hello World!")
>               number-of-ls)
> 3
>

(count #\l "Hello World!" :test #'char=)
From: Rainer Joswig
Subject: Re: Looping over array.
Date: 
Message-ID: <joswig-75890E.09584509032002@news-east.giganews.com>
In article <············@news3.cadvision.com>,
 "Wade Humeniuk" <········@cadvision.com> wrote:

> "Glenn Burnside" <··············@ni.com> wrote in message
> ···················@corp.supernews.com...
> > Forgive me for jumping in here in all my newbie glory, but if you want to
> do
> > something for each element in an array, can you not use mapcar?  I thought
> > that it worked for sequences in general - not just lists but also vectors
> > and arrays.
> 
> 
> This is true.  But usually I only use map when I am transforming a sequence
> into a sequence of equal size.  I still use iteration for things like
> 
> CL-USER 5 > (loop for c across "Hello World!"
>                   when (char= #\l c) count 1)
> 3

? (loop for c across "Hello World!"
        count (char= #\l c))
3
From: Erik Naggum
Subject: Re: Looping over array.
Date: 
Message-ID: <3224682531234024@naggum.net>
* Rainer Joswig <······@lisp-machine.de>
| ? (loop for c across "Hello World!"
|         count (char= #\l c))
| 3

(count #\l "Hello World!")
=> 3

///
-- 
  In a fight against something, the fight has value, victory has none.
  In a fight for something, the fight is a loss, victory merely relief.
From: Coby Beck
Subject: Re: Looping over array.
Date: 
Message-ID: <mJvi8.59919$eb.2361491@news3.calgary.shaw.ca>
"Erik Naggum" <····@naggum.net> wrote in message
·····················@naggum.net...
> * Rainer Joswig <······@lisp-machine.de>
> | ? (loop for c across "Hello World!"
> |         count (char= #\l c))
> | 3
>
> (count #\l "Hello World!")
> => 3
>

3
=> 3
--
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")
From: Barry Margolin
Subject: Re: Looping over array.
Date: 
Message-ID: <hMPh8.17$0%4.163@paloalto-snr2.gtei.net>
In article <··············@corp.supernews.com>,
Glenn Burnside <··············@ni.com> wrote:
>Forgive me for jumping in here in all my newbie glory, but if you want to do
>something for each element in an array, can you not use mapcar?  I thought
>that it worked for sequences in general - not just lists but also vectors
>and arrays.

No.  The only mapping functions that work on sequences are MAP and
MAP-INTO.

Also, since you say "vectors and arrays", I assume you're using "arrays" to
refer to multi-dimensional arrays.  They aren't sequences, only vectors and
lists are.

-- 
Barry Margolin, ······@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Nils Goesche
Subject: Re: Looping over array.
Date: 
Message-ID: <a68hv3$ck15l$1@ID-125440.news.dfncis.de>
In article <··············@corp.supernews.com>, Glenn Burnside wrote:
> "Wade Humeniuk" <········@cadvision.com> wrote in message
> ·················@news3.cadvision.com...
>>
>> "Thaddeus L Olczyk" <······@interaccess.com> wrote in message
>> ·······················@nntp.interaccess.com...
>> > I'm getting tierd of doing
>> >
>> > (loop for i from 0 to (- (length array))
>> >          do
>> >            (let ((x (aref i array)))
>> >                   ; For one thing I keep forgetting which goes first
>> >                   ; i or array.
>> >             ...
>> >
>> > is there some wqay of doing something like:
>> >
>> > (loop for x element-of array
>> >          do ....
>>
>> (loop for x across array do ......
>>
>> Array is of type vector.

> Forgive me for jumping in here in all my newbie glory, but if you want to do
> something for each element in an array, can you not use mapcar?  I thought
> that it worked for sequences in general - not just lists but also vectors
> and arrays.

No, mapcar works only for lists.  There is map:

(map 'vector #'1+ #(1 2 3))

=> #(2 3 4)

But it might not be what the OP wants (of course, it might as
well be).

Regards,
-- 
Nils Goesche
  "The sooner all the animals are dead, the sooner we'll find
   their money."                              -- Ed Bluestone
PGP key ID 0x42B32FC9
From: Christopher Browne
Subject: Re: Looping over array.
Date: 
Message-ID: <m36648ds1b.fsf@chvatal.cbbrowne.com>
In an attempt to throw the authorities off his trail, ······@interaccess.com (Thaddeus L Olczyk) transmitted:
> I'm getting tierd of doing
>
> (loop for i from 0 to (- (length array))
>          do
>            (let ((x (aref i array))) 
>                   ; For one thing I keep forgetting which goes first
>                   ; i or array.
>             ...
>
> is there some wqay of doing something like:
>
> (loop for x element-of array
>          do ....

Were you perhaps thinking of:

> (loop with array = #(1 4 9 16 "Foo" "Bar" 'frobozz |Bogomatic|)
      for i across array
      for j from 0 by 1
      do
      (format t "Element ~D is ~A~%" j i))
Element 0 is 1
Element 1 is 4
Element 2 is 9
Element 3 is 16
Element 4 is Foo
Element 5 is Bar
Element 6 is 'FROBOZZ
Element 7 is Bogomatic
NIL
-- 
(reverse (concatenate 'string ····················@" "454aa"))
http://www.ntlug.org/~cbbrowne/lisp.html
Points are awarded for getting the last word in.  Drawing the
conversation out so long that the original message disappears due to
being indented off the right hand edge of the screen is one way to do
this.  Another is to imply that anyone replying further is a hopeless
cretin and is wasting everyone's valuable time.
-- from the Symbolics Guidelines for Sending Mail
From: Marco Antoniotti
Subject: Re: Looping over array.
Date: 
Message-ID: <y6csn7c3xyw.fsf@octagon.mrl.nyu.edu>
······@interaccess.com (Thaddeus L Olczyk) writes:

> I'm getting tierd of doing
> 
> (loop for i from 0 to (- (length array))
>          do
>            (let ((x (aref i array))) 
>                   ; For one thing I keep forgetting which goes first
>                   ; i or array.
>             ...
> 
> is there some wqay of doing something like:
>
> (loop for x element-of array
>          do ....

(loop for x across array ....)

Note that you must ensure that `array' is actually a `vector'.

Also note that the LOOP macro allows you to do things in a nicer ways,
when it comes to bound checking.  Even if you wrote the above using
the integer variable, the result could look like

(loop for i from 0 below (length array)
      do (let ((x (aref array i))) .....))

Cheers

-- 
Marco Antoniotti ========================================================
NYU Courant Bioinformatics Group        tel. +1 - 212 - 998 3488
719 Broadway 12th Floor                 fax  +1 - 212 - 995 4122
New York, NY 10003, USA                 http://bioinformatics.cat.nyu.edu
                    "Hello New York! We'll do what we can!"
                           Bill Murray in `Ghostbusters'.
From: Thomas F. Burdick
Subject: Re: Looping over array.
Date: 
Message-ID: <xcvlmd4dpdm.fsf@conquest.OCF.Berkeley.EDU>
Marco Antoniotti <·······@cs.nyu.edu> writes:

> (loop for x across array ....)
> 
> Note that you must ensure that `array' is actually a `vector'.
> 
> Also note that the LOOP macro allows you to do things in a nicer ways,
> when it comes to bound checking.  Even if you wrote the above using
> the integer variable, the result could look like
> 
> (loop for i from 0 below (length array)
>       do (let ((x (aref array i))) .....))

Actually, it's even easier, you can do

  (loop for i below (length array)
        do ...)

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Christopher Browne
Subject: Re: Looping over array.
Date: 
Message-ID: <m3k7soc5ir.fsf@chvatal.cbbrowne.com>
In an attempt to throw the authorities off his trail, Marco Antoniotti <·······@cs.nyu.edu> transmitted:
> Also note that the LOOP macro allows you to do things in a nicer ways,
> when it comes to bound checking.  Even if you wrote the above using
> the integer variable, the result could look like
>
> (loop for i from 0 below (length array)
>       do (let ((x (aref array i))) .....))

Wouldn't it be nicer to do:

(loop with len = (length array) ;;; evaluate length just once...
   for i from 0 below len
   for x = (aref array i)
   do ....)

It seems really silly to open up a DO clause just to do an assignment
when LOOP is perfectly able to hide that behind:
   for x = (aref array i)
-- 
(concatenate 'string "cbbrowne" ·@ntlug.org")
http://www.ntlug.org/~cbbrowne/unix.html
"Programming  graphics  in X  is  like  finding  sqrt(pi) using  Roman
numerals."  -- Henry Spencer
From: Thomas F. Burdick
Subject: Re: Looping over array.
Date: 
Message-ID: <xcvit87hq8k.fsf@apocalypse.OCF.Berkeley.EDU>
Christopher Browne <········@acm.org> writes:

> Wouldn't it be nicer to do:
> 
> (loop with len = (length array) ;;; evaluate length just once...
>    for i from 0 below len
>    for x = (aref array i)
>    do ....)

I don't think anything in the standard requires or disallows
evaluating the below argument only once.  I'd imagine most LOOPs only
evaluate it once, it seems the obvious implementation.  I know CMUCL
does:

  * (defun foo () (print 'foo) 3)
  FOO
  * (loop for i below (foo) collecting i)
  FOO
  (0 1 2)

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Coby Beck
Subject: Re: Looping over array.
Date: 
Message-ID: <_JXh8.95449$kb.5708638@news1.calgary.shaw.ca>
"Christopher Browne" <········@acm.org> wrote in message
···················@chvatal.cbbrowne.com...
> In an attempt to throw the authorities off his trail, Marco Antoniotti
<·······@cs.nyu.edu> transmitted:
> > (loop for i from 0 below (length array)
> >       do (let ((x (aref array i))) .....))
>
> Wouldn't it be nicer to do:
>
> (loop with len = (length array) ;;; evaluate length just once...
>    for i from 0 below len
>    for x = (aref array i)
>    do ....)
>

While I couldn't (quickly) find anything in the HyperSpec to say it must not
do so, if I discovered an implementation that re-evaluated (length array)
every iteration I would think the developers were being malicious!  Not just
for efficiency reasons, but also so that other forms in that position with
side effects will cause them only once.

--
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")
From: Nils Goesche
Subject: Re: Looping over array.
Date: 
Message-ID: <a6afbh$culdu$1@ID-125440.news.dfncis.de>
In article <······················@news1.calgary.shaw.ca>, Coby Beck wrote:
> 
> "Christopher Browne" <········@acm.org> wrote in message
> ···················@chvatal.cbbrowne.com...
>> In an attempt to throw the authorities off his trail, Marco Antoniotti
><·······@cs.nyu.edu> transmitted:
>> > (loop for i from 0 below (length array)
>> >       do (let ((x (aref array i))) .....))
>>
>> Wouldn't it be nicer to do:
>>
>> (loop with len = (length array) ;;; evaluate length just once...
>>    for i from 0 below len
>>    for x = (aref array i)
>>    do ....)
>>
> 
> While I couldn't (quickly) find anything in the HyperSpec to say it must not
> do so, if I discovered an implementation that re-evaluated (length array)
> every iteration I would think the developers were being malicious!  Not just
> for efficiency reasons, but also so that other forms in that position with
> side effects will cause them only once.

It's in 6.1.2.1.1 The for-as-arithmetic subclause:

# In the for-as-arithmetic subclause, the for or as construct iterates
# from the value supplied by form1 to the value supplied by form2
# in increments or decrements denoted by form3. Each expression is
# evaluated only once and must evaluate to a number.

Regards,
-- 
Nils Goesche
  "The sooner all the animals are dead, the sooner we'll find
   their money."                              -- Ed Bluestone
PGP key ID 0x42B32FC9
From: Steve Long
Subject: Re: Looping over array.
Date: 
Message-ID: <3C886B5D.E89D92BB@hotmail.com>
A vector is a sort of degenerate array. If your array can be thought of
as a vector, then

(defmacro dovector ((char vector &optional result) form)
  `(let ((,char nil))
      (dotimes (n (length ,vector) ,result)
         (let ((,char (elt ,vector n)))
            ,form))))

behaves like DOLIST, but works on lists and vectors. That or you can use
the LOOP macro on the array, treating it like a vector.


slong

Thaddeus L Olczyk wrote:

> I'm getting tierd of doing
>
> (loop for i from 0 to (- (length array))
>          do
>            (let ((x (aref i array)))
>                   ; For one thing I keep forgetting which goes first
>                   ; i or array.
>             ...
>
> is there some wqay of doing something like:
>
> (loop for x element-of array
>          do ....
From: Barry Fishman
Subject: A sequence macro (Was: Looping over array.)
Date: 
Message-ID: <m38z8zezob.fsf_-_@barry_fishman.att.net>
Steve Long <·······@hotmail.com> writes:
> A vector is a sort of degenerate array. If your array can be thought of
> as a vector, then
>
> (defmacro dovector ((char vector &optional result) form)
>   `(let ((,char nil))
>       (dotimes (n (length ,vector) ,result)
>          (let ((,char (elt ,vector n)))
>             ,form))))
>
> behaves like DOLIST, but works on lists and vectors. That or you can use
> the LOOP macro on the array, treating it like a vector.

I realize this was give more as an approach rather than complete code.
As someone not yet comfortable with writing macroes, and working
detached from any other lisp programmers, I ask the following, hoping
not to seem too nieve.

As Marco Antoniotti pointed out the "loop" code for vectors is quite
clean:

   (loop for x across array do
       ...)

The lack of a "doseq" macro in the language seems to indicate that it
was felt that it was not needed in the language.


Would a more "sufficiently" written general sequence macro be:(?)

(defmacro do-each ((var proseq &optional result) &rest body)
  (if (consp proseq)
      `(dolist (,var ,proseq ,result) ,@body)
    (let ((g (gensym)))
      `(dotimes (,g (length ,proseq) (let ((,var nil))
				       (declare (ignorable ,var))
				       ,result))
	 (let ((,var (aref ,proseq ,g)))
	   ,@body)))))

Am I still missing something?  (Of course it still isn't sufficent
without a documentation string.)

Barry
From: Tim Moore
Subject: Re: A sequence macro (Was: Looping over array.)
Date: 
Message-ID: <a6itpo$t7l$0@216.39.145.192>
On Mon, 11 Mar 2002 18:18:15 GMT, Barry Fishman <·············@att.net> wrote:

>As Marco Antoniotti pointed out the "loop" code for vectors is quite
>clean:
>
>   (loop for x across array do
>       ...)
>
>The lack of a "doseq" macro in the language seems to indicate that it
>was felt that it was not needed in the language.
>
>
>Would a more "sufficiently" written general sequence macro be:(?)
>
>(defmacro do-each ((var proseq &optional result) &rest body)
>  (if (consp proseq)
>      `(dolist (,var ,proseq ,result) ,@body)
>    (let ((g (gensym)))
>      `(dotimes (,g (length ,proseq) (let ((,var nil))
>				       (declare (ignorable ,var))
>				       ,result))
>	 (let ((,var (aref ,proseq ,g)))
>	   ,@body)))))

No.  You don't know the type of proseq at macroexpansion time, at
least not portably.
>
>Am I still missing something?  (Of course it still isn't sufficent
>without a documentation string.)

If you really want to go this route you could do something like:

(defmacro do-each ((var proseq &optional result) &rest body)
  `(progn
     (map nil
       #'(lambda (,var)
           ,@body)
       ,proseq)
     ,result))

Tim
From: Kent M Pitman
Subject: Re: A sequence macro (Was: Looping over array.)
Date: 
Message-ID: <sfwbsdux5sc.fsf@shell01.TheWorld.com>
······@sea-tmoore-l.dotcast.com (Tim Moore) writes:

> If you really want to go this route you could do something like:
> 
> (defmacro do-each ((var proseq &optional result) &rest body)
>   `(progn
>      (map nil
>        #'(lambda (,var)
>            ,@body)
>        ,proseq)
>      ,result))

Wish I'd thought of this before writing my prior post. But it doesn't
completely solve the problem.

Most people expect RETURN and GO to work in DOxxx macros.

 (let ((fn (gensym "DO-EACH-BODY")))
  `(block nil
     (map nil #'(lambda (,var) (tagbody ,@body)) ,proseq)
     ,result)) ;<--- except... [see below]

I mentioned before I don't like the RESULT-FORM and this gives me a new
reason not to like it.  DOTIMES and DOLIST, for better or worse, seem to
put the result in the scope of the variable, I'm not sure to what end.
Doing this correctly probably requires:

 (let ((fn (gensym "DO-EACH-BODY"))
       (temp (gensym "TEMP")))
  `(block nil
     (let (,var)
       (map nil #'(lambda (,temp) (tagbody (setq ,var ,temp) ,@body)) ,proseq)
       ,result)))

Note also that there is a subtle (or not so subtle?) difference between 
the first and second implementations above as to what happens when you
do:

 (let ((l '()))
   (do-each (x "foo") (push (lambda () x) l))
   (mapcar #'funcall (nreverse l)))

At least there should be if I did this right.  You don't really expect me
to be testing this stuff do you?
From: Thomas F. Burdick
Subject: Re: A sequence macro (Was: Looping over array.)
Date: 
Message-ID: <xcvadtex0la.fsf@apocalypse.OCF.Berkeley.EDU>
Kent M Pitman <······@world.std.com> writes:

> I mentioned before I don't like the RESULT-FORM and this gives me a new
> reason not to like it.  DOTIMES and DOLIST, for better or worse, seem to
> put the result in the scope of the variable, I'm not sure to what end.

Me neither, especially since the spec also says (for dolist):

  At the time result-form is processed, var is bound to nil.

> Doing this correctly probably requires:
> 
>  (let ((fn (gensym "DO-EACH-BODY"))
>        (temp (gensym "TEMP")))
>   `(block nil
>      (let (,var)
>        (map nil #'(lambda (,temp) (tagbody (setq ,var ,temp) ,@body)) ,proseq)
>        ,result)))

So that's not quite right.  A correct solution could be:

  `(block nil
     (let (,var)
       (map nil #'(lambda (,var) ,@body) ,proseq)
       ,result))

Well, it's not the same variable that's bound to nil, but the user
can't tell.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Kent M Pitman
Subject: Re: A sequence macro (Was: Looping over array.)
Date: 
Message-ID: <sfweliqx6ct.fsf@shell01.TheWorld.com>
Barry Fishman <·············@att.net> writes:

> The lack of a "doseq" macro in the language seems to indicate that it
> was felt that it was not needed in the language.

Maybe.  But it's hard to tell.  Probably it's more indicative of the
fact that what gets standardized is what's "in use".  And usage
patterns are not always what you'd expect.  They can be influenced by
a large number of accidental factors.

> Would a more "sufficiently" written general sequence macro be:(?)
> 
> (defmacro do-each ((var proseq &optional result) &rest body)

(Aside: Boy, I hate that "&optional result" thing.  What a terrible place 
        to put it. I'd just leave it out... ;)

>   (if (consp proseq)

This would mean that (do-each (foo (gethash 'foo *the-vectors*)) ...)
would take this branch.

>       `(dolist (,var ,proseq ,result) ,@body)

And would mean that (do-each (foo *the-list*) ...) would take this branch.

That is, you are doing your CONSP test at compile time [on the lisp code,
not on the expression that will result from later execution of the lisp
code.  You're testing whether the _program_ is a cons, not whether the
_data_ is a cons.

>     (let ((g (gensym)))
>       `(dotimes (,g (length ,proseq) (let ((,var nil))
> 				       (declare (ignorable ,var))
> 				       ,result))
> 	 (let ((,var (aref ,proseq ,g)))
> 	   ,@body)))))
> 
> Am I still missing something?

Yes.  You would really want is to expand into a runtime test, which is a 
lot of code.  I don't have time to test it, but the general shape of 
what you want will look like the following:

 (defmacro do-each ((var seq) &body tagbody)
   (let ((seqvar (gensym "SEQ")) (indexvar (gensym "IDX")))
     `(etypecase ,seqvar
        (cons (dolist (,var ,seqvar) ,@tagbody))
        (vector (dotimes (,indexvar (length ,seqvar))
                  (let ((,var (aref ,seqvar ,indexvar)))
                    (tagbody ,@tagbody)))))))


> (Of course it still isn't sufficent without a documentation string.)

Last I checked, doc strings aren't required.  In delivered
applications, doc strings just help an end-user violate his contract
promising not to reverse engineer the product.  Sometimes doc strings
have a purpose, but it's a stretch to call code incomplete without
them.
From: Barry Fishman
Subject: Re: A sequence macro (Was: Looping over array.)
Date: 
Message-ID: <m34rjlxmdc.fsf@barry_fishman.att.net>
Thanks for all the help analysing the generalized doloop code I
presented.  I should have realized the problem with my array type
check.  I hadn't considered using map, which seems much simpler than
trying to handle sequences by type, but it was worthwhile hearing the
details of the type checking approach discussed.

I get the impression that macroes, by giving such a fine grain control
over the code generated, requires a lot of the specifics to always be
expressed as part of it.  But many macros do simple things and seem to
be simple to write.

I feel driven (although reluctant) to rexpress the macro in the way
people have shown me.

The simpler map approach, first expressed by Tim Moore and refined by
Kent Pitman and Thomas Burdick seems to be:

(defmacro do-each-1 ((var proseq &optional result) &body body)
  `(block nil
       (map nil #'(lambda (,var) (tagbody ,@body)) ,proseq)
       (let ((,var)) (declare (ignorable ,var)) ,result)))

I moved the 'let ((,var)' and added the declare to satisfy the
CMU-CL compiler.

Ken Pitman's repairs to my original attempt become:

(defmacro do-each-2 ((var proseq &optional result) &body tagbody)
  (let ((indexvar (gensym "IDX")))
    `(etypecase ,proseq
       (cons
        (dolist (,var ,proseq ,result)
          ,@tagbody))
       (vector
        (dotimes (,indexvar (length ,proseq) (let ((,var nil))
                                               (declare (ignorable ,var))
                                               ,result))
          (let ((,var (aref ,proseq ,indexvar)))
                (tagbody ,@tagbody)))))))

Sorry Ken, but I put back in the '&optional result' to keep
consistancy with the dolist macro.  Would you be a bit happyer with
doing something like:

(defmacro do-each-kp ((var proseq &optional (result nil)) &body body)
  `(block nil
       (map nil #'(lambda (,var) (tagbody ,@body)) ,proseq)
       ,@(if result
             `((let ((,var)) (declare (ignorable ,var)) ,result)))))

as is generally done in the CMU-CL sources?

I was more formal about testing the above code, and it seems to work
OK.  Last time i just interactively typed in what I thought were the
basic cases, but entered sequences directly into the form, so I missed
the main problem.

I tried to compare respective performance of the two alternatives
along just doing a:

(loop for val across proseq ...)

and found it hard see any consistant performance benefit in any
of the approaches, once the code was compiled.

Kent M Pitman <······@world.std.com> writes:
>
> Barry Fishman <·············@att.net> writes:
>> (Of course it still isn't sufficent without a documentation string.)
>
> Last I checked, doc strings aren't required.  In delivered
> applications, doc strings just help an end-user violate his contract
> promising not to reverse engineer the product.  Sometimes doc strings
> have a purpose, but it's a stretch to call code incomplete without
> them.

My background is quite different.  My end user was usually within my
own company or the DOD, and they expected source.  Within a company,
if the software isn't easy to read and use, people tend to go off and
write their own, which is a large waste of resources.  While wasting
too much of my life slogging through and fixing other peoples fragile
code, I noticed that if someone could not describe a function they
wrote in a short amount of text, that function would be visited again
and again to fix bugs.

Thanks again for the help.

Barry Fishman
From: Kent M Pitman
Subject: Re: A sequence macro (Was: Looping over array.)
Date: 
Message-ID: <sfwwuwgdesc.fsf@shell01.TheWorld.com>
Barry Fishman <·············@att.net> writes:

> Ken Pitman's repairs to my original attempt become:
[Kent.  Ken is a shortening of the unrelated name Kenneth.]
> 
> (defmacro do-each-2 ((var proseq &optional result) &body tagbody)
>   (let ((indexvar (gensym "IDX")))
>     `(etypecase ,proseq
>        (cons
>         (dolist (,var ,proseq ,result)
>           ,@tagbody))
>        (vector
>         (dotimes (,indexvar (length ,proseq) (let ((,var nil))
>                                                (declare (ignorable ,var))
>                                                ,result))
>           (let ((,var (aref ,proseq ,indexvar)))
>                 (tagbody ,@tagbody)))))))
> 
> Sorry Ken, but I put back in the '&optional result' to keep
> consistancy with the dolist macro.  Would you be a bit happyer with
> doing something like:
> 
> (defmacro do-each-kp ((var proseq &optional (result nil)) &body body)
>   `(block nil
>        (map nil #'(lambda (,var) (tagbody ,@body)) ,proseq)
>        ,@(if result
>              `((let ((,var)) (declare (ignorable ,var)) ,result)))))

No.  My real objection to this has nothing to do with the implementation.
I think that syntactically, this is just a bad place for a return value.
It is too easy to overlook.  The result form is rarely used, and people are
used to DOLIST/DOTIMES returning NIL.  Making it return T is a major change
to its semantics and should not be lost in a binding list. I'd always
rather people write

 (defun foo ()
   (dotimes (x list)
     ...)
   t)

than

 (defun foo ()
   (dotimes (x list t)
     ...))

I feel pretty much the same about this as I do about &aux variables.  It
may be handy to write

 (defun foo (&aux (x 3))
   ...)

but I'd rather people write

 (defun foo ()
   (let ((x 3))
     ...))

And again, this has nothing to do with implementation (though the 
implementation of &aux is really gross).

> Kent M Pitman <······@world.std.com> writes:
> >
> > Barry Fishman <·············@att.net> writes:
> >> (Of course it still isn't sufficent without a documentation string.)
> >
> > Last I checked, doc strings aren't required.  In delivered
> > applications, doc strings just help an end-user violate his contract
> > promising not to reverse engineer the product.  Sometimes doc strings
> > have a purpose, but it's a stretch to call code incomplete without
> > them.
> 
> My background is quite different.  My end user was usually within my
> own company or the DOD, and they expected source.  Within a company,
> if the software isn't easy to read and use, people tend to go off and
> write their own, which is a large waste of resources.

I use ;-comments sometimes.  Just mostly not string comments unless
there is a specific reason.  The main reason being that using string
comments gives the false suggestion that the comments will "survive".
Implementations are allowed to discard comments, so their usefulness
is questionable.  The main use of comments is in the source, and
there's no reason to waste address space making them be manifest as
strings unless there's a mission-critical need.

> While wasting too much of my life slogging through and fixing other
> peoples fragile code, I noticed that if someone could not describe a
> function they wrote in a short amount of text, that function would
> be visited again and again to fix bugs.

All of this is orthogonal to the intent of my remark, which was not 
intended at all to touch on the question of whether to comment code, only
whether to use doc strings.  I wouldn't have made a remark at all if you'd
said something which seemed to accept

 ;;; The function FOO does ...

 (defun foo ...)

or

 (defun foo ()
   ;; This function does ...
   )

> Thanks again for the help.

No problem.