unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* stream-for-each 2 or more bug
@ 2004-09-08  1:37 Kevin Ryde
  2004-09-08 18:37 ` Andy Wingo
  0 siblings, 1 reply; 3+ messages in thread
From: Kevin Ryde @ 2004-09-08  1:37 UTC (permalink / raw)


[-- Attachment #1: Type: text/plain, Size: 4903 bytes --]

        * streams.scm (stream-for-each-many): Correction, should recurse into
        itself, not stream-for-each-one.

I started some words about streams too.  stream-filter and stream-ref
from sicp would be nice additions.


3.1.6 Streams
-------------

Streams represent a sequence of values, each of which is calculated
only when required.  This allows large or even infinite sequences to be
represented, and manipulated with familiar operations like "car",
"cdr", "map" or "fold".  In such manipulations only as much as needed
is actually held in memory at any one time.  The functions in this
section are available from

     (use-modules (ice-9 streams))

   Streams are implemented using promises (*note Delayed Evaluation::),
this is how the underlying calculation of values is made only when
needed, and the values thereafter retained so the calculation is not
repeated.

Here is a simple example producing a stream of all odd numbers,

     (define odds (make-stream (lambda (state)
                                 (cons state (+ state 2)))
                               1))
     (stream-car odds)              => 1
     (stream-car (stream-cdr odds)) => 3

`stream-map' could be used to derive a stream of odd squares,

     (define (square n) (* n n))
     (define oddsquares (stream-map square odds))

   These are infinite sequences, so it's not possible to convert them to
a list, but they could be printed (infinitely) with for example

     (stream-for-each (lambda (n nsq)
                        (format #t "~a squared is ~a\n" n nsq))
                      odds oddsquares)
     -|
     1 squared is 1
     3 squared is 9
     5 squared is 25
     7 squared is 49
     ...


 -- Function: make-stream proc initial-state
     Return a new stream which is the results of calling PROC
     successively.

     Each call is `(PROC state)', it should return a pair, the `car'
     being the value for the stream, and the `cdr' being the new STATE
     for the next call.  For the first call the STATE is the given
     INITIAL-STATE.  At the end of the stream, PROC should return
     something other than a pair.

 -- Function: stream-car stream
     Return the first element from STREAM.  STREAM must not be empty.

 -- Function: stream-cdr stream
     Return a stream which is the second and subsequent elements of
     STREAM.  STREAM must not be empty.

 -- Function: stream-null? stream
     Return true if STREAM is empty.

 -- Function: list->stream list
 -- Function: vector->stream vector
     Return a stream with the contents of LIST or VECTOR.

     LIST or VECTOR should not be modified subsequently, it's
     unspecified whether changes there will be reflected in the stream
     returned.

 -- Function: port->stream port readproc
     Return a stream which gives the values obtained by reading from
     PORT using READPROC.  Each read call made is `(READPROC PORT)', it
     should return an EOF object (*note Reading::) at the end of input.

     For example a stream of characters from a file,

          (port->stream (open-input-file "/foo/bar.txt") read-char)

 -- Function: stream->list stream
     Return a list which is the entire contents of STREAM.

 -- Function: stream->reversed-list stream
     Return a list which is the entire contents of STREAM, but in
     reverse order.

 -- Function: stream->list&length stream
     Return two values (*note Multiple Values::) being a list which is
     the entire contents of STREAM, and the number of elements in that
     list.

 -- Function: stream->reversed-list&length stream
     Return two values (*note Multiple Values::) being a list which is
     the entire contents of STREAM, but in reverse order, and the number
     of elements in that list.

 -- Function: stream->vector stream
     Return a vector which is the entire contents of STREAM.

 -- Function: stream-fold proc init stream0 ... streamN
     Apply PROC successively over the elements of the given streams,
     from first to last.  Return the result from the last PROC call.

     Each call is `(PROC elem0 ... elemN prev)', where each ELEM is
     from the corresponding STREAM.  PREV is the return from the
     previous PROC call, or the given INIT for the first call.

 -- Function: stream-for-each proc stream0 ... streamN
     Call PROC on the elements from the given STREAMs.  The return
     value is unspecified.

     Each call is `(PROC elem0 ... elemN)', where each ELEM is from the
     corresponding STREAM.  `stream-for-each' stops when it reaches the
     end of any of the STREAMs.

 -- Function: stream-map proc stream0 ... streamN
     Return a new stream which is the results of applying PROC to the
     elements of the given STREAMs.

     Each call is `(PROC elem0 ... elemN)', where each ELEM is from the
     corresponding STREAM.  The new stream ends when the end of any of
     the given STREAMs is reached.




[-- Attachment #2: streams.scm.for-each.diff --]
[-- Type: text/plain, Size: 466 bytes --]

--- streams.scm.~1.8.~	2003-04-07 08:05:00.000000000 +1000
+++ streams.scm	2004-09-04 12:22:07.000000000 +1000
@@ -190,7 +190,7 @@
   (if (not (or-map stream-null? streams))
       (begin
         (apply f (map stream-car streams))
-        (stream-for-each-one f (map stream-cdr streams)))))
+        (stream-for-each-many f (map stream-cdr streams)))))
 
 (define (stream-map f stream . rest)
   "Returns a newly allocated stream, each element being the result of

[-- Attachment #3: streams.test --]
[-- Type: text/plain, Size: 2209 bytes --]

;;;; streams.test --- test Guile ice-9 streams module -*- scheme -*-
;;;;
;;;; Copyright (C) 2004 Free Software Foundation, Inc.
;;;; 
;;;; This program is free software; you can redistribute it and/or modify
;;;; it under the terms of the GNU General Public License as published by
;;;; the Free Software Foundation; either version 2, or (at your option)
;;;; any later version.
;;;; 
;;;; This program is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;;; GNU General Public License for more details.
;;;; 
;;;; You should have received a copy of the GNU General Public License
;;;; along with this software; see the file COPYING.  If not, write to
;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
;;;; Boston, MA 02111-1307 USA

(define-module (test-suite test-streams)
  :use-module (test-suite lib)
  :use-module (ice-9 streams))


;;;
;;; stream-for-each
;;;

(with-test-prefix "stream-for-each"

  (with-test-prefix "1 streams"

    (pass-if "empty"
      (let ((lst '()))
	(stream-for-each (lambda (x)
			   (set! lst (cons x lst)))
			 (list->stream '()))
	(equal? '() lst)))

    (pass-if "123"
      (let ((lst '()))
	(stream-for-each (lambda (x)
			   (set! lst (cons x lst)))
			 (list->stream '(1 2 3)))
	(equal? '(3 2 1) lst))))

  (with-test-prefix "2 streams"

    (pass-if "empty empty"
      (let ((lst '()))
	(stream-for-each (lambda (x y)
			   (set! lst (cons* x y lst)))
			 (list->stream '())
			 (list->stream '()))
	(equal? '() lst)))

    (pass-if "123 456"
      (let ((lst '()))
	(stream-for-each (lambda (x y)
			   (set! lst (cons* x y lst)))
			 (list->stream '(1 2 3))
			 (list->stream '(4 5 6)))
	(equal? '(3 6 2 5 1 4) lst)))

    (pass-if "12 456"
      (let ((lst '()))
	(stream-for-each (lambda (x y)
			   (set! lst (cons* x y lst)))
			 (list->stream '(1 2))
			 (list->stream '(4 5 6)))
	(equal? '(2 5 1 4) lst)))

    (pass-if "123 45"
      (let ((lst '()))
	(stream-for-each (lambda (x y)
			   (set! lst (cons* x y lst)))
			 (list->stream '(1 2 3))
			 (list->stream '(4 5)))
	(equal? '(2 5 1 4) lst)))))

[-- Attachment #4: Type: text/plain, Size: 143 bytes --]

_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: stream-for-each 2 or more bug
  2004-09-08  1:37 stream-for-each 2 or more bug Kevin Ryde
@ 2004-09-08 18:37 ` Andy Wingo
  2004-09-10 21:49   ` Kevin Ryde
  0 siblings, 1 reply; 3+ messages in thread
From: Andy Wingo @ 2004-09-08 18:37 UTC (permalink / raw)


Hi Kevin,

I'm sure I'm not the only one sitting slack-jawed when yet another one
of your well-written, well-documented patches shows up on the list. Just
wanted to let you know your work is appreciated, and that it's too bad
users have to wait until 1.8 to see them!

H

On Wed, 2004-09-08 at 11:37 +1000, Kevin Ryde wrote:
> I started some words about streams too.  stream-filter and stream-ref
> from sicp would be nice additions.

(define (stream-ref stream n)
  "Returns the @var{n}th element of @var{stream}."
  (if (negative? n) (error "Index must be nonnegative:" n))
  (let lp ((stream stream) (n n))
    (cond ((stream-null? stream) (error "Index out of range:" n))
          ((zero? n) (stream-car stream))
          (else (lp (stream-cdr stream) (1- n))))))

(define (stream-filter pass? stream)
  "Selects from @var{stream} only those elements that satisfy the
predicate @var{pass?}."
  (cond
   ((stream-null? stream) stream)
   ((pass? (stream-car stream))
    (stream-cons (stream-car stream)
                 (stream-filter pass? (stream-cdr stream))))
   (else
    (stream-filter pass? (stream-cdr stream)))))

(define (stream-remove deny? stream)
  "Removes from @var{stream} those elements that satisfy the predicate
@var{deny?}."
  (stream-filter (lambda (x) (not (deny? x))) stream))

Here's one that I've found to be useful, but I don't know how general it
is:

(define (stream-flatten stream)
  "Returns a stream that that will return all elements of @var{stream},
recursing into any contained streams. For example,
@example
  (stream->list
   (stream-flatten (list->stream (list 1 2
                                       (list->stream (list 3 4 5))
                                       6 7))))
  @result{} (1 2 3 4 5 6 7)
@end example"
  (cond
   ((stream-null? stream) stream)
   ((null? (stream-car stream))
    (stream-flatten (stream-cdr stream)))
   ((stream? (stream-car stream))
    (let lp ((recursed (stream-flatten (stream-car stream))))
      (if (stream-null? recursed)
          (stream-flatten (stream-cdr stream))
          (stream-cons (stream-car recursed)
                       (lp (stream-cdr recursed))))))
   (else
    (stream-cons (stream-car stream)
                 (stream-flatten (stream-cdr stream))))))

Regards,
-- 
Andy Wingo <wingo@pobox.com>
http://ambient.2y.net/wingo/


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: stream-for-each 2 or more bug
  2004-09-08 18:37 ` Andy Wingo
@ 2004-09-10 21:49   ` Kevin Ryde
  0 siblings, 0 replies; 3+ messages in thread
From: Kevin Ryde @ 2004-09-10 21:49 UTC (permalink / raw)
  Cc: guile-devel

Andy Wingo <wingo@pobox.com> writes:
>
> it's too bad users have to wait until 1.8 to see them!

The bug fixes (outright bugs) are in the 1.6 branch too, 1.6.5 is
supposed to be out soon. :)

> (define (stream-filter pass? stream)
>   "Selects from @var{stream} only those elements that satisfy the
> predicate @var{pass?}."
>   (cond
>    ((stream-null? stream) stream)
>    ((pass? (stream-car stream))

I was thinking of something with make-stream, like (untested)

    (define (stream-filter pred stream)
      (define (gen stream)
        (let ((pair (force stream)))
          (and (pair? pair)
               (if (pred (car pair))
                   pair
                   (gen (cdr pair))))))
      (make-stream gen stream))

Or maybe explicitly fiddling with delay/force to save some function
calls.

>     (stream-cons (stream-car stream)
>                  (stream-filter pass? (stream-cdr stream))))

I don't think stream-cons exists actually.  What sicp shows is a
macro, I guess that's necessary for recursive definitions.  Not sure
if a macro is good thing or not though, overall.


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2004-09-10 21:49 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-09-08  1:37 stream-for-each 2 or more bug Kevin Ryde
2004-09-08 18:37 ` Andy Wingo
2004-09-10 21:49   ` Kevin Ryde

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).