From: Matthew D Swank
Subject: Iterating through custom collections
Date: 
Message-ID: <pan.2006.03.26.18.48.25.788597@c.net>
Is there any way to use the extended loop macro (or iterate) with custom
collections (e.g. lazy-lists, generators, etc.)?

Matt

-- 
"You do not really understand something unless you can
 explain it to your grandmother." — Albert Einstein.

From: Russell McManus
Subject: Re: Iterating through custom collections
Date: 
Message-ID: <87ek0okqpm.fsf@cl-user.org>
Matthew D Swank <·······································@c.net> writes:

> Is there any way to use the extended loop macro (or iterate) with custom
> collections (e.g. lazy-lists, generators, etc.)?

This isn't as nice as I'd like, but it sorta works:

(defgeneric next (iterator)
  (:documentation "return the next item."))

(defgeneric has-next (iterator)
  (:documentation
   "Returns boolean whether iterator has a next item."))

(defclass list-iterator ()
  ((list :initform nil :initarg :list)))

(defmethod has-next ((i list-iterator))
  (with-slots (list) i
    (not (null list))))

(defmethod next ((i list-iterator))
  (with-slots (list) i
    (prog1 (car list) (setf list (cdr list)))))

(let* ((l (list 0 1 2 3 4))
       (i (make-instance 'list-iterator :list l)))
  (loop while (has-next i)
    collect (next i)))

-russ
From: ···············@yahoo.com
Subject: Re: Iterating through custom collections
Date: 
Message-ID: <1143474174.015013.27770@z34g2000cwc.googlegroups.com>
The next method for list-iterator destructively alters the list.  So
I'd say a list-iterator should always be created by a constructor that
copies the underlying list.

(defun make-list-iterator (list)
  (make-instance 'list-iterator :list (copy-list list)))

Also, next could be written

(defmethod next ((i list-iterator))
  (with-slots (list) i
    (pop list)))
From: Pascal Costanza
Subject: Re: Iterating through custom collections
Date: 
Message-ID: <48qfncFlilacU1@individual.net>
···············@yahoo.com wrote:
> The next method for list-iterator destructively alters the list.

No, it doesn't. ?!?

What's altered is the list slot, but not the list itself...

Pascal

-- 
3rd European Lisp Workshop
July 3-4 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/
From: Pascal Costanza
Subject: Re: Iterating through custom collections
Date: 
Message-ID: <48q6ttFl99sdU1@individual.net>
Russell McManus wrote:
> Matthew D Swank <·······································@c.net> writes:
> 
> 
>>Is there any way to use the extended loop macro (or iterate) with custom
>>collections (e.g. lazy-lists, generators, etc.)?
> 
> 
> This isn't as nice as I'd like, but it sorta works:
> 
> (defgeneric next (iterator)
>   (:documentation "return the next item."))
> 
> (defgeneric has-next (iterator)
>   (:documentation
>    "Returns boolean whether iterator has a next item."))

The Lisp naming convention would suggest nextp rather than hash-next.

But anyway, this is probably not what the OP had it mind.


Pascal

-- 
3rd European Lisp Workshop
July 3-4 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/
From: Alexis Gallagher
Subject: Re: Iterating through custom collections
Date: 
Message-ID: <RLRVf.40338$zr.1758@newsfe7-gui.ntli.net>
Iterate is probably what you want. Download it
(http://common-lisp.net/project/iterate/releases/iterate-current.tar.gz)
and have a look at section 7 ("Rolling Your Own") of the manual 
iter-man.pdf:

"iterate is extensible—you can write new clauses that embody new
iteration patterns. You might want to write a new driver clause for a 
data structure of your own, or you might want to write a clause that 
collects or manipulates elements in a way not provided by iterate"

I love iterate. My only complaint is that they haven't stuffed more of 
its documenation into its docstring comment, so you end up wanting to 
have the pdf manual at hand.

alexis

Matthew D Swank wrote:
> Is there any way to use the extended loop macro (or iterate) with
> custom collections (e.g. lazy-lists, generators, etc.)?
> 
> Matt
> 
From: rydis (Martin Rydstr|m) @CD.Chalmers.SE
Subject: Re: Iterating through custom collections
Date: 
Message-ID: <w4c7j6fsvhp.fsf@bianca.cd.chalmers.se>
Matthew D Swank <·······································@c.net> writes:
> Is there any way to use the extended loop macro (or iterate) with custom
> collections (e.g. lazy-lists, generators, etc.)?

Most implementations I've seen have a LOOP based on the Symbolics
LOOP, which is in the CMU AI repository. It is extensible. Some
implementations, like CMUCL, have removed the interface for extending
it, but last I checked, it worked just fine to simply load the extra
file from the Symbolics LOOP and extend away.

This is not ANSI CL, of course.

',mr

-- 
[Emacs] is written in Lisp, which is the only computer language that is
beautiful.  -- Neal Stephenson, _In the Beginning was the Command Line_
From: Alan Crowe
Subject: Re: Iterating through custom collections
Date: 
Message-ID: <86acbb7mpz.fsf@cawtech.freeserve.co.uk>
Matthew D Swank <·······································@c.net> writes:
> Is there any way to use the extended loop macro (or iterate) with custom
> collections (e.g. lazy-lists, generators, etc.)?
> 
> Matt

If "any way" includes hard ways then yes, shadow loop with
your own version that spots your own clauses and bodges them
into a standard loop with ... for x = this then that until
done ...

For example I define a "range" that works like a list of
numbers, though I've called the methods head and tail
instead of car and cdr, and I just store the start and stop
values not all the numbers in between.
 
CL-USER> (defclass range ()
           ((low :accessor low :initarg :start :initform 0)
            (high :accessor high :initarg :end :initform 10)))

CL-USER> (defmethod head ((object range))
           (if (< (low object)
                  (high object))
               (low object)
               (error "Fell off end of range.")))

CL-USER> (defmethod tail ((object range))
           (let ((next (+ (low object) 1)))
             (if (>= next (high object))
                 nil
                 (make-instance 'range :start next :end (high object)))))

Now we create a version of loop that recognises an "along" clause

CL-USER> (defmacro myloop (&rest clauses)
           (let ((position (position 'along clauses)))
             (if position
                 (let ((var (nth (- position 1) clauses))
                       (form (nth (+ position 1) clauses)))
                   (append '(loop)
                           (subseq clauses 0 (- position 1))
                           (build-custom-iterator var form)
                           (subseq clauses (+ position 2))))
                 clauses)))

CL-USER> (defun build-custom-iterator (var form)
           (let ((pointer (gensym)))
             `(,pointer = ,form then (tail ,pointer)
               for ,var = (head ,pointer)
               while ,pointer)))

Try it out in conjunction with other loop clauses

CL-USER> (myloop for i across #(fe fo fi fum)
                 for j along (make-instance 'range :start 10 :end 13)
                 for k in '(a b c)
                 collect (list i j k))

=> ((FE 10 A) (FO 11 B) (FI 12 C))

Actually I'm surprised that this worked, I thought that
bodging in a `while' ahead of a `for' would break it, but
apparently not. This needs more work to cope with multiple
along clauses, but it looks doable.

Alan Crowe
Edinburgh
Scotland