From: Carl Shapiro
Subject: LOOP destructuring and multiple values
Date: 
Message-ID: <ouywvs2owq6.fsf@panix6.panix.com>
Within a LOOP expression I would like to use something similar to its
destructuring capabilities to handle functions that return multiple
values.  For example:

	(loop for (string eofp) = (read-line stream)
	      ...

Is there any way to do something like this with the Common Lisp LOOP
macro?  Are there any specific LOOP implementations that could be
extended to do such a thing?

	
	

From: Barry Margolin
Subject: Re: LOOP destructuring and multiple values
Date: 
Message-ID: <KXnT3.112$PK1.4006@burlma1-snr2>
In article <···············@panix6.panix.com>,
Carl Shapiro  <·······@panix.com> wrote:
>Within a LOOP expression I would like to use something similar to its
>destructuring capabilities to handle functions that return multiple
>values.  For example:
>
>	(loop for (string eofp) = (read-line stream)
>	      ...
>
>Is there any way to do something like this with the Common Lisp LOOP
>macro?  Are there any specific LOOP implementations that could be
>extended to do such a thing?

(loop for (string eofp) = (values-list (read-line stream)) ...)

(loop with string eofp
  do (multiple-value-setq (string eofp) (read-line stream))
     ...)

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, 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: Christopher R. Barry
Subject: Re: LOOP destructuring and multiple values
Date: 
Message-ID: <87u2n5razk.fsf@2xtreme.net>
Barry Margolin <······@bbnplanet.com> writes:

> In article <···············@panix6.panix.com>,
> Carl Shapiro  <·······@panix.com> wrote:
> >Within a LOOP expression I would like to use something similar to its
> >destructuring capabilities to handle functions that return multiple
> >values.  For example:
> >
> >	(loop for (string eofp) = (read-line stream)
> >	      ...
> >
> >Is there any way to do something like this with the Common Lisp LOOP
> >macro?  Are there any specific LOOP implementations that could be
> >extended to do such a thing?
> 
> (loop for (string eofp) = (values-list (read-line stream)) ...)
> 
> (loop with string eofp
>   do (multiple-value-setq (string eofp) (read-line stream))
>      ...)

Just a couple weeks ago I had to do this exact same thing. I went
with:

  (loop with eofp
        for string = (multiple-value-setq (string eofp)
		       (read-line stream nil nil))
        while string
        do ...
        until eofp)

Originally I went with your first version (you got VALUES-LIST mixed
up with MULTIPLE-VALUE-LIST, which does the exact opposite), except
this conses up a list only to immediately destructure it and was thus
unacceptable. I prefer to do bindings in FOR clauses, but I guess your
second way is probably the best overall. There really should be a
succinct _and_ efficient way to do this....

Christopher
From: Christopher R. Barry
Subject: Re: LOOP destructuring and multiple values
Date: 
Message-ID: <87r9i9r2oo.fsf@2xtreme.net>
Carl Shapiro <·······@panix.com> writes:

> Within a LOOP expression I would like to use something similar to its
> destructuring capabilities to handle functions that return multiple
> values.  For example:
> 
> 	(loop for (string eofp) = (read-line stream)
> 	      ...
> 
> Is there any way to do something like this with the Common Lisp LOOP
> macro?  Are there any specific LOOP implementations that could be
> extended to do such a thing?

Yes. In Allegro CL's "src/" subdirectory, as well as in the CMU
sources, you will find the source code to LOOP. You'll want to check
out ADD-LOOP-PATH, DEFINE-LOOP-<blah>-PATH, etc. These are neither
simple nor intuitive to use, and I don't know where you can find
documentation for them.

Christopher
From: Pierre R. Mai
Subject: Re: LOOP destructuring and multiple values
Date: 
Message-ID: <87hfj5dym2.fsf@orion.dent.isdn.cs.tu-berlin.de>
--Multipart_Tue_Nov__2_10:36:05_1999-1
Content-Type: text/plain; charset=US-ASCII

······@2xtreme.net (Christopher R. Barry) writes:

> Carl Shapiro <·······@panix.com> writes:
> 
> > Is there any way to do something like this with the Common Lisp LOOP
> > macro?  Are there any specific LOOP implementations that could be
> > extended to do such a thing?
> 
> Yes. In Allegro CL's "src/" subdirectory, as well as in the CMU
> sources, you will find the source code to LOOP. You'll want to check
> out ADD-LOOP-PATH, DEFINE-LOOP-<blah>-PATH, etc. These are neither
> simple nor intuitive to use, and I don't know where you can find
> documentation for them.

I once digged into MIT loop to implement some looping paths, and wrote
up a couple of sentences on what is what in MIT loop on the way.  I've
appended the file, which also implements a couple of specialized looping
paths, below.  Though the code won't work because the functionality it
is built atop is missing, the examples should give an idea about how to
write new paths.

Ignore the copyright bearing header for this file and use as you
wish.  Have fun...

Regs, Pierre.


--Multipart_Tue_Nov__2_10:36:05_1999-1
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="loop.cl"
Content-Transfer-Encoding: 8bit

;;;; NewESIM --- The Next Generation Implementation of ESIM
;;;; This is copyrighted software.  See documentation for terms.
;;;; 
;;;; loop.cl --- Loop path extensions for MIT Loop
;;;; 
;;;; Checkout Tag: $Name$
;;;; $Id$

(in-package :ANSI-LOOP)
(esim-doc:file-version "$Header$")

;;;; %File Description:
;;;; 
;;;; This introduces some nifty extensions to loop.  For this to work,
;;;; you need to have an MIT Loop compatible version loaded and
;;;; accessible in package ANSI-LOOP.
;;;; 

;;;; General Documentation of MIT LOOP extensions
;;;;
;;;; Additional iteration paths (to be used with being clauses) are
;;;; defined via add-loop-path.  It takes the following arguments:
;;;;
;;;; - list of markers/keywords identifying this path
;;;; - function implementing the path (see below)
;;;; - the loop universe to add this path to
;;;; - keyword arguments to specify valid prepositions, user data, etc.
;;;;
;;;; The function that implements the path gets the following parameters:
;;;;
;;;; - variable being iterated on
;;;; - data-type specification of the variable
;;;; - list of preposition phrases
;;;; - the user-data as a rest parameter, if specified
;;;;
;;;; The function has to return a list of either 6 or 10 elements.  If only
;;;; 6 elements are provided, the last 4 elements are appended to get the full
;;;; 10 elements.  The meaning of the elements:
;;;;
;;;; 1) List of bindings to perform at the beginning(?), of the form
;;;;    var, (var), (var initial-value) or (var initial-value data-type).
;;;;    loop-make-iteration-variable is called for each element, passing nil
;;;;    for missing arguments.
;;;; 2) Prologue forms (these are reverse nconced onto *loop-prologue*).
;;;; 3) pre-step-tests
;;;;    Single form.  The collected list of these is passed to make-endtest.
;;;; 4) steps
;;;;    List of forms.
;;;;    The nconced list of these is passed to loop-make-psetq.
;;;; 5) post-step-tests
;;;;    Single form.  The collected list of these is passed to make-endtest.
;;;; 6) pseudo-steps
;;;;    List of forms.
;;;;    The nconced list of these is passed to loop-make-desetq.
;;;;
;;;; The following, if present are identical in meaning to the previous 4
;;;; elements, with the difference that these are used for the first
;;;; iteration only, and the others for the rest.  If they are not present,
;;;; they are treated as identical to the previous 4 elements.
;;;;
;;;; 7) pre-loop-pre-step-tests
;;;;    Single form.  The collected list of these is passed to make-endtest.
;;;; 8) pre-loop-steps
;;;;    List of forms.
;;;;    The nconced list of these is passed to loop-make-psetq.
;;;; 9) pre-loop-post-step-tests
;;;;    Single form.  The collected list of these is passed to make-endtest.
;;;;10) pre-loop-pseudo-steps
;;;;    List of forms.
;;;;    The nconced list of these is passed to loop-make-desetq.
;;;;
;;;; The last 4 or 8 values are passed along to loop-hack-iteration,
;;;; and are indeed identical to the sole elements returned from main
;;;; iteration drivers or for-sub-dispatches.  See
;;;; loop-ansi-for-equals for a simple example of an for-sub-dispatch.
;;;;

;;;; This defines a loop path for the lines of a stream.
;;; Syntax: loop for var being the lines of stream
;;; Syntax: loop for var being each line in stream

(defun loop-lines-iteration-path (variable data-type prep-phrases)
  (cond ((or (cdr prep-phrases) (not (member (caar prep-phrases) '(:in :of))))
	 (loop-error "Too many prepositions!"))
	((null prep-phrases) (loop-error "Missing OF or IN in ~S iteration path.")))
  (unless (symbolp variable)
    (loop-error "Destructuring is not valid for line iteration."))
  (let ((stream-var (loop-gentemp 'loop-line-)))
    `(((,variable nil ,data-type) (,stream-var ,(cadar prep-phrases)))
      ()
      ()
      ()
      (not (setq ,variable (read-line ,stream-var nil nil)))
      ())))

(add-loop-path '(line lines) 'loop-lines-iteration-path *loop-ansi-universe*
	       :preposition-groups '((:of :in))
	       :inclusive-permitted nil)

;;;; This defines a loop path for the split lines of a stream.
;;; Syntax: loop for var being the split-lines of stream by char
;;; Syntax: loop for var being each split-line in stream on char

;;; This should be remolded back into the general line iteration path,
;;; using optional preposition-phrases.

#|
(defun loop-split-lines-iteration-path (variable data-type prep-phrases)
  (cond ((or (cddr prep-phrases) (not (member (caar prep-phrases) '(:in :of)))
             (not (member (caadr prep-phrases) '(:by :on))))
	 (loop-error "Too many prepositions!"))
	((null prep-phrases) (loop-error "Missing OF or IN in ~S iteration path.")))
  (cond
   ((consp variable)
    (let ((stream-var (loop-gentemp 'loop-split-line-))
          (by-var (loop-gentemp 'loop-split-line-by-))
          (line-var (loop-gentemp 'loop-split-line-line-))
          (step-var (loop-gentemp 'loop-split-line-step-)))
      `(((,variable nil ,data-type) (,stream-var ,(cadar prep-phrases))
         (,by-var ,(cadadr prep-phrases))
         (,line-var nil)
         (,step-var nil))
        ()
        ()
        ()
        (not (when (setq ,line-var (read-line ,stream-var nil nil))
               (setq ,step-var (pmlib:partition ,by-var ,line-var :keep-empty-subseqs t))))
        (,variable ,step-var))))
   (t
    (let ((stream-var (loop-gentemp 'loop-split-line-))
          (by-var (loop-gentemp 'loop-split-line-by-))
          (line-var (loop-gentemp 'loop-split-line-line-)))
      `(((,variable nil ,data-type) (,stream-var ,(cadar prep-phrases))
         (,by-var ,(cadadr prep-phrases))
         (,line-var nil))
        ()
        ()
        ()
        (not (when (setq ,line-var (read-line ,stream-var nil nil))
               (setq ,variable (cl-user::split ,by-var ,line-var :keep-empty-subseqs t))))
        ())))))

(add-loop-path '(split-line split-lines) 'loop-split-lines-iteration-path 
               *loop-ansi-universe*
	       :preposition-groups '((:of :in) (:by :on))
	       :inclusive-permitted nil)
|#

(defun loop-instances-iteration-path (variable data-type prep-phrases)
  (cond ((or (cdr prep-phrases) (not (member (caar prep-phrases) '(:in :of))))
	 (loop-error "Too many prepositions!"))
	((null prep-phrases) (loop-error "Missing OF or IN in ~S iteration path.")))
  (unless (symbolp variable)
    (loop-error "Destructuring is not valid for instance iteration."))
  (let ((step-var (loop-gentemp 'loop-instance-step-)))
    `(((,variable nil ,data-type)
       (,step-var (cons nil (pmlib:retrieve (quote ,(cadar prep-phrases))))))
      ()
      ()
      ()
      (not (when (setq ,step-var (cdr ,step-var))
	     (setq ,variable (car ,step-var))))
      ())))

(add-loop-path '(instance instances)
	       'loop-instances-iteration-path *loop-ansi-universe*
	       :preposition-groups '((:of :in))
	       :inclusive-permitted nil)

--Multipart_Tue_Nov__2_10:36:05_1999-1
Content-Type: text/plain; charset=US-ASCII



-- 
Pierre Mai <····@acm.org>         PGP and GPG keys at your nearest Keyserver
  "One smaller motivation which, in part, stems from altruism is Microsoft-
   bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]

--Multipart_Tue_Nov__2_10:36:05_1999-1--