From: Peter Scott
Subject: Iterating over general sequences
Date: 
Message-ID: <1115919670.607026.232040@f14g2000cwb.googlegroups.com>
How would I iterate over any sequence, regardless of whether it's a
list or a vector? MAPC (et al) only work on lists, LOOP has seperate
syntaxes for vectors and lists, DOLIST only works on lists, and I don't
like the idea of coercing to one type.

I know that some functions, like REDUCE, work on general sequences. I
suppose I could use generic functions or TYPECASE to dispatch to
seperate type-specific functions, but that isn't very appealing. Am I
missing something here?

-Peter

From: O-MY-GLIFE
Subject: Re: Iterating over general sequences
Date: 
Message-ID: <1115921172.202765.17710@z14g2000cwz.googlegroups.com>
Peter Scott wrote:
> How would I iterate over any sequence, regardless of whether it's a
> list or a vector? MAPC (et al) only work on lists, LOOP has seperate
> syntaxes for vectors and lists, DOLIST only works on lists, and I
don't
> like the idea of coercing to one type.
>
> I know that some functions, like REDUCE, work on general sequences. I
> suppose I could use generic functions or TYPECASE to dispatch to
> seperate type-specific functions, but that isn't very appealing. Am I
> missing something here?
>

[··@helios ~]$ clisp -q
;; Loading file /home/rv/.clisprc ...
;; Loaded file /home/rv/.clisprc
[1]> (defvar >>a (list 1 2))
>>A
[2]> (defvar >>b #(4 8))
>>B
[3]> (map 'list #'+ >>a >>b)
(5 10)
[4]> (map 'vector #'+ >>a >>b)
#(5 10)

Is that what you want?

> -Peter
From: Thomas A. Russ
Subject: Re: Iterating over general sequences
Date: 
Message-ID: <ymi3bsswb20.fsf@sevak.isi.edu>
"Peter Scott" <·········@gmail.com> writes:

> 
> How would I iterate over any sequence, regardless of whether it's a
> list or a vector? MAPC (et al) only work on lists,

Actually, MAP works on any sequence.

The sequences dictionary can be found here, and it gives you all of the
functions that operate on any sequence:

http://www.lispworks.com/documentation/HyperSpec/Body/c_sequen.htm

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Marco Antoniotti
Subject: Re: Iterating over general sequences
Date: 
Message-ID: <cPNge.39$mi7.62521@typhoon.nyu.edu>
Hi

you want the MAP function.

	(map 'list #'+ #(1 2 3) '(1 2 3))
	==> (2 4 6)

Or you want the CL-ENUMERATION library from common-lisp.net (shameless 
plug).

Cheers
--
Marco





Peter Scott wrote:
> How would I iterate over any sequence, regardless of whether it's a
> list or a vector? MAPC (et al) only work on lists, LOOP has seperate
> syntaxes for vectors and lists, DOLIST only works on lists, and I don't
> like the idea of coercing to one type.
> 
> I know that some functions, like REDUCE, work on general sequences. I
> suppose I could use generic functions or TYPECASE to dispatch to
> seperate type-specific functions, but that isn't very appealing. Am I
> missing something here?
> 
> -Peter
> 
From: Peter Scott
Subject: Re: Iterating over general sequences
Date: 
Message-ID: <1115931272.695405.253830@g44g2000cwa.googlegroups.com>
Thanks everyone, MAP solved my immediate problem. CL-ENUMERATION looks
like a good way to do this sort of thing in the future, but my
immediate use for this was in writing an optimized version of a
function in the cl-utilities library at common-lisp.net (I can do
shameless plugs too), and I didn't want to introduce extra dependencies
with unknown licenses that would probably slow down my "optimized"
function. It's already slower than the original for most (but not all)
cases.

-Peter
From: Marco Antoniotti
Subject: Re: Iterating over general sequences
Date: 
Message-ID: <jp5he.42$mi7.63595@typhoon.nyu.edu>
Peter Scott wrote:
> Thanks everyone, MAP solved my immediate problem. CL-ENUMERATION looks
> like a good way to do this sort of thing in the future, but my
> immediate use for this was in writing an optimized version of a
> function in the cl-utilities library at common-lisp.net (I can do
> shameless plugs too), and I didn't want to introduce extra dependencies
> with unknown licenses

If you are referring to CL-ENUMERATION license, there is no uncertainty. 
  It is a DFSG compliant BSD style license.

Cheers
--
Marco
From: Joerg Hoehle
Subject: Re: Iterating over general sequences
Date: 
Message-ID: <uk6m36t3i.fsf@users.sourceforge.net>
"Peter Scott" <·········@gmail.com> writes:
> Thanks everyone, MAP solved my immediate problem. CL-ENUMERATION looks
> like a good way to do this sort of thing in the future, but my
> immediate use for this was in writing an optimized version of a
> function in the cl-utilities library at common-lisp.net (I can do
> shameless plugs too), and I didn't want to introduce extra dependencies
> with unknown licenses that would probably slow down my "optimized"
> function. It's already slower than the original for most (but not all)
> cases.

Maybe you should look into COMPILER-MACRO so that you can inline the
function for typical cases where :test is #'eql and :key is #'identity,
instead of using (funcall test x (funcall key y)) inside a DEFUN.

Not sure this really helps you.

Regards,
	Jorg Hohle
Telekom/T-Systems Technology Center
From: Alexander Schmolck
Subject: Re: Iterating over general sequences
Date: 
Message-ID: <yfsll6kcoi3.fsf@black4.ex.ac.uk>
"Peter Scott" <·········@gmail.com> writes:

> How would I iterate over any sequence, regardless of whether it's a
> list or a vector? 

You could use (map nil ... seq) or write something like this (not tested):

  (defun snarf-declaration (body)
    (if (eq (caar body) 'declare)
      (values (list (car body)) (cdr body))
      (values () body)))

  ;; Note: not 100% like dolist
  (defmacro doseq ((var seq &optional (result nil)) &body body)
    "Like DOLIST but for all sequences and with destructuring."
    (multiple-value-bind (declaration body) (snarf-declaration body)
      (with-gensyms (dummy)
        `(block nil
          (map nil (lambda (,dummy)
                     ,@declaration
                     (tagbody
                        (destructuring-bind ,var ,dummy
                          ,@body)))
           ,seq)
          ,result))))

'as
From: Thomas F. Burdick
Subject: Re: Iterating over general sequences
Date: 
Message-ID: <xcvoebg6yp2.fsf@conquest.OCF.Berkeley.EDU>
Alexander Schmolck <··········@gmx.net> writes:

>   ;; Note: not 100% like dolist
>   (defmacro doseq ((var seq &optional (result nil)) &body body)
>     "Like DOLIST but for all sequences and with destructuring."
>     (multiple-value-bind (declaration body) (snarf-declaration body)
>       (with-gensyms (dummy)
>         `(block nil
>           (map nil (lambda (,dummy)
>                      ,@declaration
>                      (tagbody
>                         (destructuring-bind ,var ,dummy
>                           ,@body)))
>            ,seq)
>           ,result))))

A few things:

  - that's a bad place for the declarations (what if I'm declaring VAR
    to be special?)

  - the tagbody should be within the destructuring-bind

  - VAR should be bound to NIL when evaluating RESULT (at least if you
    want to be like DOLIST)

  (defmacro doseq ((var seq &optional result) &body body)
    (multiple-value-bind (decl body) (snarf-declaration body)
      (with-gensyms (=var =seq)
  	`(block nil
  	   (let ((,=seq ,seq) ,var)
  	     ,@decl
  	     (map nil (lambda (,=dummy)
  			(setf ,var ,=dummy)
  			(tagbody ,@body))
                  ,=seq)
  	     (setf ,var nil)
  	     ,result)))))

Alternately, this is a bit further from DOLIST, but simpler (and more
intuitive in some ways):

  (defmacro doseq ((var seq &optional result) &body body)
    `(block nil
       (map nil (lambda (,var) ,@body) ,seq)
       (let ((,var nil)) ,result)))

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | Free Mumia Abu-Jamal! |
     ,--'    _,'   | Abolish the racist    |
    /       /      | death penalty!        |
   (   -.  |       `-----------------------'
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Alexander Schmolck
Subject: Re: Iterating over general sequences
Date: 
Message-ID: <yfspsvw9fme.fsf@black4.ex.ac.uk>
···@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> Alexander Schmolck <··········@gmx.net> writes:
>
>>   ;; Note: not 100% like dolist
>>   (defmacro doseq ((var seq &optional (result nil)) &body body)
>>     "Like DOLIST but for all sequences and with destructuring."
>>     (multiple-value-bind (declaration body) (snarf-declaration body)
>>       (with-gensyms (dummy)
>>         `(block nil
>>           (map nil (lambda (,dummy)
>>                      ,@declaration
>>                      (tagbody
>>                         (destructuring-bind ,var ,dummy
>>                           ,@body)))
>>            ,seq)
>>           ,result))))
>
> A few things:
>
>   - that's a bad place for the declarations (what if I'm declaring VAR
>     to be special?)
>   - the tagbody should be within the destructuring-bind

Indeed, thanks -- both the ,@declarartion and the tagbody are obviously
misplaced, but why wouldn't pushing them both into the body of
destructuring-bind be satisfactory? And out of curiosity -- have you got an
example when declaring an iteration variable special would be handy?

>   - VAR should be bound to NIL when evaluating RESULT (at least if you
>     want to be like DOLIST)

I know, but I couldn't figure out why that would be useful.

'as
From: Rob Warnock
Subject: Re: Iterating over general sequences
Date: 
Message-ID: <fN6dnaq02M7qrxnfRVn-ow@speakeasy.net>
Alexander Schmolck  <··········@gmx.net> wrote:
+---------------
| ···@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
| >   - that's a bad place for the declarations (what if I'm declaring VAR
| >     to be special?)
...
| And out of curiosity -- have you got an example when declaring an
| iteration variable special would be handy?
+---------------

Google for "Jensen's Device"...

[Yes, I know specials aren't "call-by-name" at all,
but you can do some of the same things with them.]

Or try this one:

    (loop for *print-base* from 2 to 36 do (print 1234567))


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Thomas F. Burdick
Subject: Re: Iterating over general sequences
Date: 
Message-ID: <xcvis1n7eql.fsf@conquest.OCF.Berkeley.EDU>
Alexander Schmolck <··········@gmx.net> writes:

> ···@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> 
> > Alexander Schmolck <··········@gmx.net> writes:
> >
> >>   ;; Note: not 100% like dolist
> >>   (defmacro doseq ((var seq &optional (result nil)) &body body)
> >>     "Like DOLIST but for all sequences and with destructuring."
> >>     (multiple-value-bind (declaration body) (snarf-declaration body)
> >>       (with-gensyms (dummy)
> >>         `(block nil
> >>           (map nil (lambda (,dummy)
> >>                      ,@declaration
> >>                      (tagbody
> >>                         (destructuring-bind ,var ,dummy
> >>                           ,@body)))
> >>            ,seq)
> >>           ,result))))
> >
> > A few things:
> >
> >   - that's a bad place for the declarations (what if I'm declaring VAR
> >     to be special?)
> >   - the tagbody should be within the destructuring-bind
> 
> Indeed, thanks -- both the ,@declarartion and the tagbody are obviously
> misplaced, but why wouldn't pushing them both into the body of
> destructuring-bind be satisfactory?

Because they won't apply to the scope of the result form.

> And out of curiosity -- have you got an
> example when declaring an iteration variable special would be handy?

Rob Warnock posted one in a followup.  It's unusual that you'd want to
have a situation like that where it's not globally special, but I'd
find it very confusing if I wrote the special declaration and it
didn't apply.

> >   - VAR should be bound to NIL when evaluating RESULT (at least if you
> >     want to be like DOLIST)
> 
> I know, but I couldn't figure out why that would be useful.

Got me.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | Free Mumia Abu-Jamal! |
     ,--'    _,'   | Abolish the racist    |
    /       /      | death penalty!        |
   (   -.  |       `-----------------------'
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Alexander Schmolck
Subject: Re: Iterating over general sequences
Date: 
Message-ID: <yfshdh7klbo.fsf@black4.ex.ac.uk>
···@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> Alexander Schmolck <··········@gmx.net> writes:
>
>> ···@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
>> 
>> > Alexander Schmolck <··········@gmx.net> writes:
>> >
>> >>   ;; Note: not 100% like dolist
>> >>   (defmacro doseq ((var seq &optional (result nil)) &body body)
>> >>     "Like DOLIST but for all sequences and with destructuring."
>> >>     (multiple-value-bind (declaration body) (snarf-declaration body)
>> >>       (with-gensyms (dummy)
>> >>         `(block nil
>> >>           (map nil (lambda (,dummy)
>> >>                      ,@declaration
>> >>                      (tagbody
>> >>                         (destructuring-bind ,var ,dummy
>> >>                           ,@body)))
>> >>            ,seq)
>> >>           ,result))))
>> >
>> > A few things:
>> >
>> >   - that's a bad place for the declarations (what if I'm declaring VAR
>> >     to be special?)
>> >   - the tagbody should be within the destructuring-bind
>> 
>> Indeed, thanks -- both the ,@declarartion and the tagbody are obviously
>> misplaced, but why wouldn't pushing them both into the body of
>> destructuring-bind be satisfactory?
>
> Because they won't apply to the scope of the result form.

Yes, but I can't see how such a declaration could apply to anything other than
the iteration variable -- which isn't in scope in my version, and the presence
of which in dolist is actually -- as far as I can see -- a hindrance to useful
declarations (maybe I'm misunderstanding something but doesn't the fact that
dolist sets the iteration variable VAR to nil in the result mean that I can't 
make meaningful type declarations concerning VAR because the type will always
have to include the value nil?).

'as
From: David Steuber
Subject: Re: Iterating over general sequences
Date: 
Message-ID: <874qd7bl20.fsf@david-steuber.com>
···@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

>   (defmacro doseq ((var seq &optional result) &body body)
>     `(block nil
>        (map nil (lambda (,var) ,@body) ,seq)
>        (let ((,var nil)) ,result)))

I don't understand your usage of LET here.  Specifically why do you
bother to bind nil to ,var?  Why do you even need the LET at all?

eg (untested)

(defmacro doseq ((var seq &optional result) &body body)
  `(block nil
     (map nil (lambda (,var) ,@body) ,seq)
     ,result))

-- 
An ideal world is left as an excercise to the reader.
   --- Paul Graham, On Lisp 8.1
No excuses.  No apologies.  Just do it.
   --- Erik Naggum
From: Thomas F. Burdick
Subject: Re: Iterating over general sequences
Date: 
Message-ID: <xcvfywr7853.fsf@conquest.OCF.Berkeley.EDU>
David Steuber <·····@david-steuber.com> writes:

> ···@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> 
> >   (defmacro doseq ((var seq &optional result) &body body)
> >     `(block nil
> >        (map nil (lambda (,var) ,@body) ,seq)
> >        (let ((,var nil)) ,result)))
> 
> I don't understand your usage of LET here.  Specifically why do you
> bother to bind nil to ,var?  Why do you even need the LET at all?

DOLIST and DOTIMES evaluate the result form with VAR bound to NIL.  So
in the case of this DOSEQ macro, it's to be a little more like DOLIST.
I don't think that NIL is an especially useful value for this, but
there it is.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | Free Mumia Abu-Jamal! |
     ,--'    _,'   | Abolish the racist    |
    /       /      | death penalty!        |
   (   -.  |       `-----------------------'
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: ·········@cern.ch
Subject: Re: Iterating over general sequences
Date: 
Message-ID: <yzo64xn2szw.fsf@cern.ch>
Thomas> DOLIST and DOTIMES evaluate the result form with VAR bound to
Thomas> NIL.

As a minor off-topic nit-pick, this is not true for DOTIMES:

CL-USER> (dotimes (i 10 i))
10

Ole
From: Alexander Schmolck
Subject: Re: Iterating over general sequences
Date: 
Message-ID: <yfs7ji4cn8y.fsf@black4.ex.ac.uk>
Alexander Schmolck <··········@gmx.net> writes:

>(not tested):
>   (defun snarf-declaration (body)
>     (if (eq (caar body) 'declare)
>       (values (list (car body)) (cdr body))
>       (values () body)))


OK, that was definitely broken; 2nd try (and I'm sure the macro itself is also
not quite ideal but I hope it gives the idea):

  (defun snarf-declarations (body)
    (loop for (x . rest) on body
          when (or (atom x) (not (eq (car x) 'declare)))
          do (return (values declarations (cons x rest)))
          else collect x into declarations
          finally (return (values declarations ()))))

'as