sequence iteration

  • Follow


Yet another "newbie needs help" post !

I tried to find a way to iterate over a sequence (trying to stay generic 
here)
It seems the only way would be to use the map function. Is this correct ?

If that is the case how would i go about interrupting iteration ?

Sacha 


0
Reply no1386 (80) 3/17/2006 5:26:23 PM

> Yet another "newbie needs help" post !
>
> I tried to find a way to iterate over a sequence (trying to stay generic
> here)
> It seems the only way would be to use the map function. Is this correct ?
>
> If that is the case how would i go about interrupting iteration ?
>
> Sacha

Maybe you could use "do" and "elt". This will tend to be inefficient
when dealing with long lists, but it should be generic as you wish. In
that case, one of the clauses in "do" is meant for indicating when
iteration will stop.

You could also look into "loop" instead of "do".

0
Reply lavigne.eric (260) 3/17/2006 5:52:57 PM


Sacha wrote:
> Yet another "newbie needs help" post !
> 
> I tried to find a way to iterate over a sequence (trying to stay generic 
> here)
> It seems the only way would be to use the map function. Is this correct ?

Yes.

> If that is the case how would i go about interrupting iteration ?

(defun f (sequence)
   (map 'list (lambda (x)
                (when (> x 5)
                  (return-from f 'foo)))
        sequence))

Something like that?


Pascal

-- 
3rd European Lisp Workshop
July 3-4 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/
0
Reply pc56 (3895) 3/17/2006 5:57:09 PM

"Eric Lavigne" <lavigne.eric@gmail.com> wrote in message 
news:1142617977.443107.228350@v46g2000cwv.googlegroups.com...
>
>> Yet another "newbie needs help" post !
>>
>> I tried to find a way to iterate over a sequence (trying to stay generic
>> here)
>> It seems the only way would be to use the map function. Is this correct ?
>>
>> If that is the case how would i go about interrupting iteration ?
>>
>> Sacha
>
> Maybe you could use "do" and "elt". This will tend to be inefficient
> when dealing with long lists, but it should be generic as you wish. In
> that case, one of the clauses in "do" is meant for indicating when
> iteration will stop.
>
> You could also look into "loop" instead of "do".
>

I am to use this in a tight loop, i'd rather look into the efficient ways.
On a side note, i didn't see a way to use loop for that purpose.
May i ask how you'd do that ?

thanks for your answers,
Sacha 


0
Reply no1386 (80) 3/17/2006 6:12:30 PM

"Pascal Costanza" <pc@p-cos.net> wrote in message 
news:480bjmFh8djlU1@individual.net...
>> I tried to find a way to iterate over a sequence (trying to stay generic 
>> here)
>> It seems the only way would be to use the map function. Is this correct ?
>
> Yes.

Oh, this is slightly disapointing.

>> If that is the case how would i go about interrupting iteration ?
>
> (defun f (sequence)
>   (map 'list (lambda (x)
>                (when (> x 5)
>                  (return-from f 'foo)))
>        sequence))
>
> Something like that?


That would work, though in my specific case, i don't want to exit the 
function alltogether.
I guess it's time to dive in named blocks or maybe throw and catch stuff.

I wonder what's the cost of such things ...

Anyways, thanks for your always helpfull advice Pascal.
Sacha 


0
Reply no1386 (80) 3/17/2006 6:16:54 PM

"Pascal Costanza" <pc@p-cos.net> wrote in message 

> > (defun f (sequence)
> >   (map 'list (lambda (x)
> >                (when (> x 5)
> >                  (return-from f 'foo)))
> >        sequence))

"Sacha" <no@address.spam> writes:

> That would work, though in my specific case, i don't want to exit
> the function alltogether.  I guess it's time to dive in named blocks
> or maybe throw and catch stuff.

Block/return is the lexically-scoped variant of catch/throw, and here
it seems that the lexical variant is appropriate. You can also use
tagbody/go (i.e. lisp's version of goto).


I suggest however that you reconsider the requirement of being
"generic". In my experience, it's quite rare that you really need to
accept both lists and vectors: their access characteristics (in terms
of run-time complexity) are so very different that they tend to be
used for separate things. In the rare exceptions, an etypecase and
duplicated code often works well enough.

-- 
Frode Vatvedt Fjeld
0
Reply frodef (343) 3/17/2006 6:37:09 PM

> Block/return is the lexically-scoped variant of catch/throw, and here
> it seems that the lexical variant is appropriate. You can also use
> tagbody/go (i.e. lisp's version of goto).

thanks

> I suggest however that you reconsider the requirement of being
> "generic". In my experience, it's quite rare that you really need to
> accept both lists and vectors: their access characteristics (in terms
> of run-time complexity) are so very different that they tend to be
> used for separate things. In the rare exceptions, an etypecase and
> duplicated code often works well enough.

I think i'll just do that, and update the code so that it only accepts 
vectors.
I don't really need to stay generic, that was more for the sake of it =P

Sacha 


0
Reply no1386 (80) 3/17/2006 6:46:37 PM

> I am to use this in a tight loop, i'd rather look into the efficient ways.
> On a side note, i didn't see a way to use loop for that purpose.
> May i ask how you'd do that ?
>

   (loop
     for element in sequence
     collect (do-something-to element)
     until (> element 5))

This performs some action on each element (do-something-to) and
collects the results in a list (the return value of loop). If it runs
into an element that is greater than 5, it will terminate early and
return whatever it collected so far.

0
Reply lavigne.eric (260) 3/17/2006 6:55:26 PM

"Eric Lavigne" <lavigne.eric@gmail.com> writes:

>    (loop
>      for element in sequence
>      collect (do-something-to element)
>      until (> element 5))
> 
> This performs some action on each element

But only if sequence is a list..

-- 
Frode Vatvedt Fjeld
0
Reply frodef (343) 3/17/2006 7:07:23 PM

"Eric Lavigne" <lavigne.eric@gmail.com> wrote in message 
news:1142621726.491765.80910@u72g2000cwu.googlegroups.com...
>
>> I am to use this in a tight loop, i'd rather look into the efficient 
>> ways.
>> On a side note, i didn't see a way to use loop for that purpose.
>> May i ask how you'd do that ?
>>
>
>   (loop
>     for element in sequence
>     collect (do-something-to element)
>     until (> element 5))
>
> This performs some action on each element (do-something-to) and
> collects the results in a list (the return value of loop). If it runs
> into an element that is greater than 5, it will terminate early and
> return whatever it collected so far.


Oh but this won't work with all types of sequences :

(loop for char in "coucou" do (print char))

Error: "coucou" is not of type LIST.
  1 (abort) Return to level 0.
  2 Return to top loop level 0.

Type :b for backtrace, :c <option number> to proceed,  or :? for other 
options

Sacha 


0
Reply no1386 (80) 3/17/2006 7:10:46 PM

Sacha wrote:
> "Eric Lavigne" <lavigne.eric@gmail.com> wrote in message 
> news:1142621726.491765.80910@u72g2000cwu.googlegroups.com...
>>> I am to use this in a tight loop, i'd rather look into the efficient 
>>> ways.
>>> On a side note, i didn't see a way to use loop for that purpose.
>>> May i ask how you'd do that ?
>>>
>>   (loop
>>     for element in sequence
>>     collect (do-something-to element)
>>     until (> element 5))
>>
>> This performs some action on each element (do-something-to) and
>> collects the results in a list (the return value of loop). If it runs
>> into an element that is greater than 5, it will terminate early and
>> return whatever it collected so far.
> 
> 
> Oh but this won't work with all types of sequences :
> 
> (loop for char in "coucou" do (print char))
> 

CL-USER 5 > (loop for char across "coucou" do (print char))

#\c
#\o
#\u
#\c
#\o
#\u
NIL

CL-USER 6 >
0
Reply spam398 (546) 3/18/2006 12:38:22 AM

>>>   (loop
>>>     for element in sequence
>>>     collect (do-something-to element)
>>>     until (> element 5))
>>>
>>
>> Oh but this won't work with all types of sequences :
>>
>> (loop for char in "coucou" do (print char))
>>
>
> CL-USER 5 > (loop for char across "coucou" do (print char))
>
> #\c
> #\o
> #\u
> #\c
> #\o
> #\u
> NIL
>
> CL-USER 6 >

haha well sure, but now i'm stuck with vectors !
Remember the goal was to make it generic.

I wonder why they didn't allow the loop macro to genericaly iterate over a 
sequence.
Can't be much more of a syntactic mess than it is right now anyways =P

Sacha 


0
Reply no1386 (80) 3/18/2006 1:29:42 AM

> I wonder why they didn't allow the loop macro to genericaly iterate over a
> sequence.
> Can't be much more of a syntactic mess than it is right now anyways =P
>


Well actually i think i know why.
Might be because the macro doesn't know what's the actual
type of the sequence. This is only known at best after compilation,
at worst at runtime.

Sacha 


0
Reply no1386 (80) 3/18/2006 1:33:45 AM

"Sacha" <no@address.spam> writes:
> I wonder why they didn't allow the loop macro to genericaly iterate over a 
> sequence.

Because there's no efficient generic iteration operator.

You can use ELT, but it's O(N) on lists, for each access, therefore
O(N�) for the loop.


> Can't be much more of a syntactic mess than it is right now anyways =P

This is not a syntax problem.  You get the sequence at run time, so
you have to choose between CDR or AREF at run time.

You can do your own GLOOP (or checkout ITERATE or some similar package)
which would map:

   (gloop for item inside sequence do (stuff item))

to:

  (if (listp sequence)
     (loop for item in seqeunce do (stuff item))
     (loop for item on seqeunce do (stuff item)))





Or you can write:

  (loop with iterator = (iterator container)
        for item = (iterator-next iterator)
        while item
        do (stuff item))


(defun iterator-next (iterator) (funcall iterator))
    
(defmethod iterator ((self null))
  (lambda () (values nil t)))

(defmethod iterator ((self cons))
  (lambda () (let ((done (not self))) (values (pop self) done))))

(defmethod iterator ((self vector))
  (let ((i 0))
    (lambda () 
        (if (< i (length self))
           (multiple-values-prog1 (values (aref self i) nil) (incf i))
           (values nil t)))))

;; and you can add a method of any kind of container...

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

"By filing this bug report you have challenged the honor of my
family. Prepare to die!"
0
Reply usenet39 (458) 3/18/2006 1:51:49 AM

> You can do your own GLOOP (or checkout ITERATE or some similar package)
> which would map:
>
>   (gloop for item inside sequence do (stuff item))
>
> to:
>
>  (if (listp sequence)
>     (loop for item in seqeunce do (stuff item))
>     (loop for item on seqeunce do (stuff item)))
>
>
> Or you can write:
>
>  (loop with iterator = (iterator container)
>        for item = (iterator-next iterator)
>        while item
>        do (stuff item))
>
>
> (defun iterator-next (iterator) (funcall iterator))
>
> (defmethod iterator ((self null))
>  (lambda () (values nil t)))
>
> (defmethod iterator ((self cons))
>  (lambda () (let ((done (not self))) (values (pop self) done))))
>
> (defmethod iterator ((self vector))
>  (let ((i 0))
>    (lambda ()
>        (if (< i (length self))
>           (multiple-values-prog1 (values (aref self i) nil) (incf i))
>           (values nil t)))))
>

Very nice indeed.

It strikes me that an hypothetical statically typed lisp would allow for
a macro specialization.

Like this :
;;we know the type of sequence (through some kind of a pre-compilation step)
(defmacro my-loop (var sequence &body body)
  (if (listp sequence)
     `(loop for ,var in ,sequence ....)
     `(loop for ,var on ,sequence ...)))

or

(defmacromethod my-loop (var (sequence list) &body body)
 ....)
(defmacromethod my-loop (var (sequence vector) &body body)
 ...)

That would be good stuff...
Though this would be at the cost of dynamic typing.
Can't have the best of both worlds i guess.

Sacha


0
Reply no1386 (80) 3/18/2006 3:02:20 AM

"Sacha" <no@address.spam> writes:
> It strikes me that an hypothetical statically typed lisp would allow for
> a macro specialization.
>
> Like this :
> ;;we know the type of sequence (through some kind of a pre-compilation step)
> (defmacro my-loop (var sequence &body body)
>   (if (listp sequence)
>      `(loop for ,var in ,sequence ....)
>      `(loop for ,var on ,sequence ...)))
>
> or
>
> (defmacromethod my-loop (var (sequence list) &body body)
>  ....)
> (defmacromethod my-loop (var (sequence vector) &body body)
>  ...)
>
> That would be good stuff...
> Though this would be at the cost of dynamic typing.
> Can't have the best of both worlds i guess.

Well, macros are expanded before compilation, before the compiler has
an opportunity to do any type inference.

But this would be theorically possible in a compiler macro.
(see: DEFINE-COMPILER-MACRO).

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

"What is this talk of "release"?  Klingons do not make software
"releases".  Our software "escapes" leaving a bloody trail of
designers and quality assurance people in its wake."
0
Reply usenet39 (458) 3/18/2006 3:43:28 AM

"Sacha" <no@address.spam> writes:

> "Pascal Costanza" <pc@p-cos.net> wrote in message 
> news:480bjmFh8djlU1@individual.net...
> >> I tried to find a way to iterate over a sequence (trying to stay generic 
> >> here)
> >> It seems the only way would be to use the map function. Is this correct ?
> >
> > Yes.
> 
> Oh, this is slightly disapointing.

Don't be too disapointed, DOSEQUENCE is only 4 lines of code:
http://groups.google.com/group/comp.lang.lisp/msg/4e21bb46df444036

It works (almost) just like DOLIST.  So you can write, e.g.:

  (defun foo (sequence)
    (let ((found nil))
      (dosequence (x sequence)
        (when (> x 5)
          (setf found x)
          (return)))
      (when found (format t "I found ~d~%" found))
      found))

  (foo '(1 2 3 4)) => nil
  (foo #(1 2 30 40))
  =>
     I found 30
     30

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | Free Mumia Abu-Jamal! |
     ,--'    _,'   | Abolish the racist    |
    /       /      | death penalty!        |
   (   -.  |       `-----------------------'
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
0
Reply tfb4 (471) 3/18/2006 10:34:36 AM

"Thomas F. Burdick" <tfb@conquest.OCF.Berkeley.EDU> wrote in message 
news:xcv64mckpmr.fsf@conquest.OCF.Berkeley.EDU...
> "Sacha" <no@address.spam> writes:
>
>> "Pascal Costanza" <pc@p-cos.net> wrote in message
>> news:480bjmFh8djlU1@individual.net...
>> >> I tried to find a way to iterate over a sequence (trying to stay 
>> >> generic
>> >> here)
>> >> It seems the only way would be to use the map function. Is this 
>> >> correct ?
>> >
>> > Yes.
>>
>> Oh, this is slightly disapointing.
>
> Don't be too disapointed, DOSEQUENCE is only 4 lines of code:
> http://groups.google.com/group/comp.lang.lisp/msg/4e21bb46df444036
>
> It works (almost) just like DOLIST.  So you can write, e.g.:
>
>  (defun foo (sequence)
>    (let ((found nil))
>      (dosequence (x sequence)
>        (when (> x 5)
>          (setf found x)
>          (return)))
>      (when found (format t "I found ~d~%" found))
>      found))
>
>  (foo '(1 2 3 4)) => nil
>  (foo #(1 2 30 40))
>  =>
>     I found 30
>     30


Thank you.
It's about time that i start building an utility library.

Sacha 


0
Reply no1386 (80) 3/18/2006 4:55:13 PM

"jayessay" <nospam@foo.com> wrote in message 
news:m33bhf38sz.fsf@rigel.goldenthreadtech.com...
> "Sacha" <no@address.spam> writes:
>
>
>> It strikes me that an hypothetical statically typed lisp would allow for
>> a macro specialization.
>
> You "just" need type inference.  As part of a system I've built, fully
> generic iteration/comprehension utilizes type inference to _typically_
> generate the specific code; falling back to runtime dispatch for those
> cases which can't be determined.
>
> /Jon

Well i won't ask how you do this, as it would probably fly
a couple miles over my head  =P

Sacha 


0
Reply no1386 (80) 3/18/2006 6:25:59 PM

"Sacha" <no@address.spam> writes:


> It strikes me that an hypothetical statically typed lisp would allow for
> a macro specialization.

You "just" need type inference.  As part of a system I've built, fully
generic iteration/comprehension utilizes type inference to _typically_
generate the specific code; falling back to runtime dispatch for those
cases which can't be determined.

/Jon

-- 
'j' - a n t h o n y at romeo/charley/november com
0
Reply nospam3258 (1248) 3/18/2006 6:30:04 PM

Pascal Bourguignon wrote:

> "Sacha" <no@address.spam> writes:
> > I wonder why they didn't allow the loop macro to genericaly iterate over
> > a sequence.
> 
> Because there's no efficient generic iteration operator.
> 
> You can use ELT, but it's O(N) on lists, for each access, therefore
> O(N�) for the loop.
> 
> 
> > Can't be much more of a syntactic mess than it is right now anyways =P
> 
> This is not a syntax problem.  You get the sequence at run time, so
> you have to choose between CDR or AREF at run time.
> 
> You can do your own GLOOP (or checkout ITERATE or some similar package)
> which would map:
> 
>    (gloop for item inside sequence do (stuff item))
> 
> to:
> 
>   (if (listp sequence)
>      (loop for item in seqeunce do (stuff item))
>      (loop for item on seqeunce do (stuff item)))
> 
> 
> 
> 
> 
> Or you can write:
> 
>   (loop with iterator = (iterator container)
>         for item = (iterator-next iterator)
>         while item
>         do (stuff item))
> 
> 
> (defun iterator-next (iterator) (funcall iterator))
>     
> (defmethod iterator ((self null))
>   (lambda () (values nil t)))
> 
> (defmethod iterator ((self cons))
>   (lambda () (let ((done (not self))) (values (pop self) done))))
> 
> (defmethod iterator ((self vector))
>   (let ((i 0))
>     (lambda () 
>         (if (< i (length self))
>            (multiple-values-prog1 (values (aref self i) nil) (incf i))
>            (values nil t)))))
> 
> ;; and you can add a method of any kind of container...
> 
>            

Arc:

arc> (each x '(5 6) (pr x))
56nil
arc> (each x "ah" (pr x))
ahnil
0
Reply w_a_x_man (2778) 5/13/2011 10:13:40 AM

On 13 Mag, 12:13, "WJ" <w_a_x_...@yahoo.com> wrote:
> Arc:
>
> arc> (each x '(5 6) (pr x))
> 56nil
> arc> (each x "ah" (pr x))
> ahnil

1000 thanks for joining the Arc community!
Now we're finally more than 3!!!!
0
Reply java.oke (196) 5/13/2011 10:15:11 AM

21 Replies
24 Views

(page loaded in 0.273 seconds)

Similiar Articles:


















7/8/2012 7:22:00 AM


Reply: