mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 03:40:34 +02:00
Add full documentation for SRFI-41.
* doc/ref/misc-modules.texi (Streams): Add cross-reference to SRFI-41. * doc/ref/srfi-modules.texi (SRFI-41): Replace stub with full documentation. (SRFI-41 Stream Fundamentals, SRFI-41 Stream Primitives, SRFI-41 Stream Library): New subsubsections.
This commit is contained in:
parent
50d08cd894
commit
80b809f114
2 changed files with 704 additions and 2 deletions
|
@ -1573,6 +1573,9 @@ modifies the queue @var{list} then it must either maintain
|
|||
@section Streams
|
||||
@cindex streams
|
||||
|
||||
This section documents Guile's legacy stream module. For a more
|
||||
complete and portable stream library, @pxref{SRFI-41}.
|
||||
|
||||
A stream represents 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'',
|
||||
|
|
|
@ -3793,8 +3793,707 @@ scope and the result from that @var{thunk} is the return from
|
|||
@subsection SRFI-41 - Streams
|
||||
@cindex SRFI-41
|
||||
|
||||
See @uref{http://srfi.schemers.org/srfi-41/srfi-41.html, the
|
||||
specification of SRFI-41}.
|
||||
This subsection is based on the
|
||||
@uref{http://srfi.schemers.org/srfi-41/srfi-41.html, specification of
|
||||
SRFI-41} by Philip L.@: Bewig.
|
||||
|
||||
@c The copyright notice and license text of the SRFI-41 specification is
|
||||
@c reproduced below:
|
||||
|
||||
@c Copyright (C) Philip L. Bewig (2007). All Rights Reserved.
|
||||
|
||||
@c Permission is hereby granted, free of charge, to any person obtaining a
|
||||
@c copy of this software and associated documentation files (the
|
||||
@c "Software"), to deal in the Software without restriction, including
|
||||
@c without limitation the rights to use, copy, modify, merge, publish,
|
||||
@c distribute, sublicense, and/or sell copies of the Software, and to
|
||||
@c permit persons to whom the Software is furnished to do so, subject to
|
||||
@c the following conditions:
|
||||
|
||||
@c The above copyright notice and this permission notice shall be included
|
||||
@c in all copies or substantial portions of the Software.
|
||||
|
||||
@c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
@c OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
@c MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
@c NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
@c LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
@c OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
@c WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@noindent
|
||||
This SRFI implements streams, sometimes called lazy lists, a sequential
|
||||
data structure containing elements computed only on demand. A stream is
|
||||
either null or is a pair with a stream in its cdr. Since elements of a
|
||||
stream are computed only when accessed, streams can be infinite. Once
|
||||
computed, the value of a stream element is cached in case it is needed
|
||||
again. SRFI-41 can be made available with:
|
||||
|
||||
@example
|
||||
(use-modules (srfi srfi-41))
|
||||
@end example
|
||||
|
||||
@menu
|
||||
* SRFI-41 Stream Fundamentals::
|
||||
* SRFI-41 Stream Primitives::
|
||||
* SRFI-41 Stream Library::
|
||||
@end menu
|
||||
|
||||
@node SRFI-41 Stream Fundamentals
|
||||
@subsubsection SRFI-41 Stream Fundamentals
|
||||
|
||||
SRFI-41 Streams are based on two mutually-recursive abstract data types:
|
||||
An object of the @code{stream} abstract data type is a promise that,
|
||||
when forced, is either @code{stream-null} or is an object of type
|
||||
@code{stream-pair}. An object of the @code{stream-pair} abstract data
|
||||
type contains a @code{stream-car} and a @code{stream-cdr}, which must be
|
||||
a @code{stream}. The essential feature of streams is the systematic
|
||||
suspensions of the recursive promises between the two data types.
|
||||
|
||||
The object stored in the @code{stream-car} of a @code{stream-pair} is a
|
||||
promise that is forced the first time the @code{stream-car} is accessed;
|
||||
its value is cached in case it is needed again. The object may have any
|
||||
type, and different stream elements may have different types. If the
|
||||
@code{stream-car} is never accessed, the object stored there is never
|
||||
evaluated. Likewise, the @code{stream-cdr} is a promise to return a
|
||||
stream, and is only forced on demand.
|
||||
|
||||
@node SRFI-41 Stream Primitives
|
||||
@subsubsection SRFI-41 Stream Primitives
|
||||
|
||||
This library provides eight operators: constructors for
|
||||
@code{stream-null} and @code{stream-pair}s, type predicates for streams
|
||||
and the two kinds of streams, accessors for both fields of a
|
||||
@code{stream-pair}, and a lambda that creates procedures that return
|
||||
streams.
|
||||
|
||||
@deffn {Constant} stream-null
|
||||
A promise that, when forced, is a single object, distinguishable from
|
||||
all other objects, that represents the null stream. @code{stream-null}
|
||||
is immutable and unique.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Syntax} stream-cons object-expr stream-expr
|
||||
Creates a newly-allocated stream containing a promise that, when forced,
|
||||
is a @code{stream-pair} with @var{object-expr} in its @code{stream-car}
|
||||
and @var{stream-expr} in its @code{stream-cdr}. Neither
|
||||
@var{object-expr} nor @var{stream-expr} is evaluated when
|
||||
@code{stream-cons} is called.
|
||||
|
||||
Once created, a @code{stream-pair} is immutable; there is no
|
||||
@code{stream-set-car!} or @code{stream-set-cdr!} that modifies an
|
||||
existing stream-pair. There is no dotted-pair or improper stream as
|
||||
with lists.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream? object
|
||||
Returns true if @var{object} is a stream, otherwise returns false. If
|
||||
@var{object} is a stream, its promise will not be forced. If
|
||||
@code{(stream? obj)} returns true, then one of @code{(stream-null? obj)}
|
||||
or @code{(stream-pair? obj)} will return true and the other will return
|
||||
false.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-null? object
|
||||
Returns true if @var{object} is the distinguished null stream, otherwise
|
||||
returns false. If @var{object} is a stream, its promise will be forced.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-pair? object
|
||||
Returns true if @var{object} is a @code{stream-pair} constructed by
|
||||
@code{stream-cons}, otherwise returns false. If @var{object} is a
|
||||
stream, its promise will be forced.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-car stream
|
||||
Returns the object stored in the @code{stream-car} of @var{stream}. An
|
||||
error is signalled if the argument is not a @code{stream-pair}. This
|
||||
causes the @var{object-expr} passed to @code{stream-cons} to be
|
||||
evaluated if it had not yet been; the value is cached in case it is
|
||||
needed again.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-cdr stream
|
||||
Returns the stream stored in the @code{stream-cdr} of @var{stream}. An
|
||||
error is signalled if the argument is not a @code{stream-pair}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Syntax} stream-lambda formals body @dots{}
|
||||
Creates a procedure that returns a promise to evaluate the @var{body} of
|
||||
the procedure. The last @var{body} expression to be evaluated must
|
||||
yield a stream. As with normal @code{lambda}, @var{formals} may be a
|
||||
single variable name, in which case all the formal arguments are
|
||||
collected into a single list, or a list of variable names, which may be
|
||||
null if there are no arguments, proper if there are an exact number of
|
||||
arguments, or dotted if a fixed number of arguments is to be followed by
|
||||
zero or more arguments collected into a list. @var{Body} must contain
|
||||
at least one expression, and may contain internal definitions preceding
|
||||
any expressions to be evaluated.
|
||||
@end deffn
|
||||
|
||||
@example
|
||||
(define strm123
|
||||
(stream-cons 1
|
||||
(stream-cons 2
|
||||
(stream-cons 3
|
||||
stream-null))))
|
||||
|
||||
(stream-car strm123) @result{} 1
|
||||
(stream-car (stream-cdr strm123) @result{} 2
|
||||
|
||||
(stream-pair?
|
||||
(stream-cdr
|
||||
(stream-cons (/ 1 0) stream-null))) @result{} #f
|
||||
|
||||
(stream? (list 1 2 3)) @result{} #f
|
||||
|
||||
(define iter
|
||||
(stream-lambda (f x)
|
||||
(stream-cons x (iter f (f x)))))
|
||||
|
||||
(define nats (iter (lambda (x) (+ x 1)) 0))
|
||||
|
||||
(stream-car (stream-cdr nats)) @result{} 1
|
||||
|
||||
(define stream-add
|
||||
(stream-lambda (s1 s2)
|
||||
(stream-cons
|
||||
(+ (stream-car s1) (stream-car s2))
|
||||
(stream-add (stream-cdr s1)
|
||||
(stream-cdr s2)))))
|
||||
|
||||
(define evens (stream-add nats nats))
|
||||
|
||||
(stream-car evens) @result{} 0
|
||||
(stream-car (stream-cdr evens)) @result{} 2
|
||||
(stream-car (stream-cdr (stream-cdr evens))) @result{} 4
|
||||
@end example
|
||||
|
||||
@node SRFI-41 Stream Library
|
||||
@subsubsection SRFI-41 Stream Library
|
||||
|
||||
@deffn {Scheme Syntax} define-stream (name args @dots{}) body @dots{}
|
||||
Creates a procedure that returns a stream, and may appear anywhere a
|
||||
normal @code{define} may appear, including as an internal definition.
|
||||
It may contain internal definitions of its own. The defined procedure
|
||||
takes arguments in the same way as @code{stream-lambda}.
|
||||
@code{define-stream} is syntactic sugar on @code{stream-lambda}; see
|
||||
also @code{stream-let}, which is also a sugaring of
|
||||
@code{stream-lambda}.
|
||||
|
||||
A simple version of @code{stream-map} that takes only a single input
|
||||
stream calls itself recursively:
|
||||
|
||||
@example
|
||||
(define-stream (stream-map proc strm)
|
||||
(if (stream-null? strm)
|
||||
stream-null
|
||||
(stream-cons
|
||||
(proc (stream-car strm))
|
||||
(stream-map proc (stream-cdr strm))))))
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} list->stream list
|
||||
Returns a newly-allocated stream containing the elements from
|
||||
@var{list}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} port->stream [port]
|
||||
Returns a newly-allocated stream containing in its elements the
|
||||
characters on the port. If @var{port} is not given it defaults to the
|
||||
current input port. The returned stream has finite length and is
|
||||
terminated by @code{stream-null}.
|
||||
|
||||
It looks like one use of @code{port->stream} would be this:
|
||||
|
||||
@example
|
||||
(define s ;wrong!
|
||||
(with-input-from-file filename
|
||||
(lambda () (port->stream))))
|
||||
@end example
|
||||
|
||||
But that fails, because @code{with-input-from-file} is eager, and closes
|
||||
the input port prematurely, before the first character is read. To read
|
||||
a file into a stream, say:
|
||||
|
||||
@example
|
||||
(define-stream (file->stream filename)
|
||||
(let ((p (open-input-file filename)))
|
||||
(stream-let loop ((c (read-char p)))
|
||||
(if (eof-object? c)
|
||||
(begin (close-input-port p)
|
||||
stream-null)
|
||||
(stream-cons c
|
||||
(loop (read-char p)))))))
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Syntax} stream object-expr @dots{}
|
||||
Creates a newly-allocated stream containing in its elements the objects,
|
||||
in order. The @var{object-expr}s are evaluated when they are accessed,
|
||||
not when the stream is created. If no objects are given, as in
|
||||
(stream), the null stream is returned. See also @code{list->stream}.
|
||||
|
||||
@example
|
||||
(define strm123 (stream 1 2 3))
|
||||
|
||||
; (/ 1 0) not evaluated when stream is created
|
||||
(define s (stream 1 (/ 1 0) -1))
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream->list [n] stream
|
||||
Returns a newly-allocated list containing in its elements the first
|
||||
@var{n} items in @var{stream}. If @var{stream} has less than @var{n}
|
||||
items, all the items in the stream will be included in the returned
|
||||
list. If @var{n} is not given it defaults to infinity, which means that
|
||||
unless @var{stream} is finite @code{stream->list} will never return.
|
||||
|
||||
@example
|
||||
(stream->list 10
|
||||
(stream-map (lambda (x) (* x x))
|
||||
(stream-from 0)))
|
||||
@result{} (0 1 4 9 16 25 36 49 64 81)
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-append stream @dots{}
|
||||
Returns a newly-allocated stream containing in its elements those
|
||||
elements contained in its input @var{stream}s, in order of input. If
|
||||
any of the input streams is infinite, no elements of any of the
|
||||
succeeding input streams will appear in the output stream. See also
|
||||
@code{stream-concat}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-concat stream
|
||||
Takes a @var{stream} consisting of one or more streams and returns a
|
||||
newly-allocated stream containing all the elements of the input streams.
|
||||
If any of the streams in the input @var{stream} is infinite, any
|
||||
remaining streams in the input stream will never appear in the output
|
||||
stream. See also @code{stream-append}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-constant object @dots{}
|
||||
Returns a newly-allocated stream containing in its elements the
|
||||
@var{object}s, repeating in succession forever.
|
||||
|
||||
@example
|
||||
(stream-constant 1) @result{} 1 1 1 @dots{}
|
||||
(stream-constant #t #f) @result{} #t #f #t #f #t #f @dots{}
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-drop n stream
|
||||
Returns the suffix of the input @var{stream} that starts at the next
|
||||
element after the first @var{n} elements. The output stream shares
|
||||
structure with the input @var{stream}; thus, promises forced in one
|
||||
instance of the stream are also forced in the other instance of the
|
||||
stream. If the input @var{stream} has less than @var{n} elements,
|
||||
@code{stream-drop} returns the null stream. See also
|
||||
@code{stream-take}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-drop-while pred stream
|
||||
Returns the suffix of the input @var{stream} that starts at the first
|
||||
element @var{x} for which @code{(pred x)} returns false. The output
|
||||
stream shares structure with the input @var{stream}. See also
|
||||
@code{stream-take-while}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-filter pred stream
|
||||
Returns a newly-allocated stream that contains only those elements
|
||||
@var{x} of the input @var{stream} which satisfy the predicate
|
||||
@code{pred}.
|
||||
|
||||
@example
|
||||
(stream-filter odd? (stream-from 0))
|
||||
@result{} 1 3 5 7 9 @dots{}
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-fold proc base stream
|
||||
Applies a binary procedure @var{proc} to @var{base} and the first
|
||||
element of @var{stream} to compute a new @var{base}, then applies the
|
||||
procedure to the new @var{base} and the next element of @var{stream} to
|
||||
compute a succeeding @var{base}, and so on, accumulating a value that is
|
||||
finally returned as the value of @code{stream-fold} when the end of the
|
||||
stream is reached. @var{stream} must be finite, or @code{stream-fold}
|
||||
will enter an infinite loop. See also @code{stream-scan}, which is
|
||||
similar to @code{stream-fold}, but useful for infinite streams. For
|
||||
readers familiar with other functional languages, this is a left-fold;
|
||||
there is no corresponding right-fold, since right-fold relies on finite
|
||||
streams that are fully-evaluated, in which case they may as well be
|
||||
converted to a list.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-for-each proc stream @dots{}
|
||||
Applies @var{proc} element-wise to corresponding elements of the input
|
||||
@var{stream}s for side-effects; it returns nothing.
|
||||
@code{stream-for-each} stops as soon as any of its input streams is
|
||||
exhausted.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-from first [step]
|
||||
Creates a newly-allocated stream that contains @var{first} as its first
|
||||
element and increments each succeeding element by @var{step}. If
|
||||
@var{step} is not given it defaults to 1. @var{first} and @var{step}
|
||||
may be of any numeric type. @code{stream-from} is frequently useful as
|
||||
a generator in @code{stream-of} expressions. See also
|
||||
@code{stream-range} for a similar procedure that creates finite streams.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-iterate proc base
|
||||
Creates a newly-allocated stream containing @var{base} in its first
|
||||
element and applies @var{proc} to each element in turn to determine the
|
||||
succeeding element. See also @code{stream-unfold} and
|
||||
@code{stream-unfolds}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-length stream
|
||||
Returns the number of elements in the @var{stream}; it does not evaluate
|
||||
its elements. @code{stream-length} may only be used on finite streams;
|
||||
it enters an infinite loop with infinite streams.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Syntax} stream-let tag ((var expr) @dots{}) body @dots{}
|
||||
Creates a local scope that binds each variable to the value of its
|
||||
corresponding expression. It additionally binds @var{tag} to a
|
||||
procedure which takes the bound variables as arguments and @var{body} as
|
||||
its defining expressions, binding the @var{tag} with
|
||||
@code{stream-lambda}. @var{tag} is in scope within body, and may be
|
||||
called recursively. When the expanded expression defined by the
|
||||
@code{stream-let} is evaluated, @code{stream-let} evaluates the
|
||||
expressions in its @var{body} in an environment containing the
|
||||
newly-bound variables, returning the value of the last expression
|
||||
evaluated, which must yield a stream.
|
||||
|
||||
@code{stream-let} provides syntactic sugar on @code{stream-lambda}, in
|
||||
the same manner as normal @code{let} provides syntactic sugar on normal
|
||||
@code{lambda}. However, unlike normal @code{let}, the @var{tag} is
|
||||
required, not optional, because unnamed @code{stream-let} is
|
||||
meaningless.
|
||||
|
||||
For example, @code{stream-member} returns the first @code{stream-pair}
|
||||
of the input @var{strm} with a @code{stream-car} @var{x} that satisfies
|
||||
@code{(eql? obj x)}, or the null stream if @var{x} is not present in
|
||||
@var{strm}.
|
||||
|
||||
@example
|
||||
(define-stream (stream-member eql? obj strm)
|
||||
(stream-let loop ((strm strm))
|
||||
(cond ((stream-null? strm) strm)
|
||||
((eql? obj (stream-car strm)) strm)
|
||||
(else (loop (stream-cdr strm))))))
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-map proc stream @dots{}
|
||||
Applies @var{proc} element-wise to corresponding elements of the input
|
||||
@var{stream}s, returning a newly-allocated stream containing elements
|
||||
that are the results of those procedure applications. The output stream
|
||||
has as many elements as the minimum-length input stream, and may be
|
||||
infinite.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Syntax} stream-match stream clause @dots{}
|
||||
Provides pattern-matching for streams. The input @var{stream} is an
|
||||
expression that evaluates to a stream. Clauses are of the form
|
||||
@code{(pattern [fender] expression)}, consisting of a @var{pattern} that
|
||||
matches a stream of a particular shape, an optional @var{fender} that
|
||||
must succeed if the pattern is to match, and an @var{expression} that is
|
||||
evaluated if the pattern matches. There are four types of patterns:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
() matches the null stream.
|
||||
|
||||
@item
|
||||
(@var{pat0} @var{pat1} @dots{}) matches a finite stream with length
|
||||
exactly equal to the number of pattern elements.
|
||||
|
||||
@item
|
||||
(@var{pat0} @var{pat1} @dots{} @code{.} @var{pat-rest}) matches an
|
||||
infinite stream, or a finite stream with length at least as great as the
|
||||
number of pattern elements before the literal dot.
|
||||
|
||||
@item
|
||||
@var{pat} matches an entire stream. Should always appear last in the
|
||||
list of clauses; it's not an error to appear elsewhere, but subsequent
|
||||
clauses could never match.
|
||||
@end itemize
|
||||
|
||||
Each pattern element may be either:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
An identifier, which matches any stream element. Additionally, the
|
||||
value of the stream element is bound to the variable named by the
|
||||
identifier, which is in scope in the @var{fender} and @var{expression}
|
||||
of the corresponding @var{clause}. Each identifier in a single pattern
|
||||
must be unique.
|
||||
|
||||
@item
|
||||
A literal underscore (@code{_}), which matches any stream element but
|
||||
creates no bindings.
|
||||
@end itemize
|
||||
|
||||
The @var{pattern}s are tested in order, left-to-right, until a matching
|
||||
pattern is found; if @var{fender} is present, it must evaluate to a true
|
||||
value for the match to be successful. Pattern variables are bound in
|
||||
the corresponding @var{fender} and @var{expression}. Once the matching
|
||||
@var{pattern} is found, the corresponding @var{expression} is evaluated
|
||||
and returned as the result of the match. An error is signaled if no
|
||||
pattern matches the input @var{stream}.
|
||||
|
||||
@code{stream-match} is often used to distinguish null streams from
|
||||
non-null streams, binding @var{head} and @var{tail}:
|
||||
|
||||
@example
|
||||
(define (len strm)
|
||||
(stream-match strm
|
||||
(() 0)
|
||||
((head . tail) (+ 1 (len tail)))))
|
||||
@end example
|
||||
|
||||
Fenders can test the common case where two stream elements must be
|
||||
identical; the @code{else} pattern is an identifier bound to the entire
|
||||
stream, not a keyword as in @code{cond}.
|
||||
|
||||
@example
|
||||
(stream-match strm
|
||||
((x y . _) (equal? x y) 'ok)
|
||||
(else 'error))
|
||||
@end example
|
||||
|
||||
A more complex example uses two nested matchers to match two different
|
||||
stream arguments; @code{(stream-merge lt? . strms)} stably merges two or
|
||||
more streams ordered by the @code{lt?} predicate:
|
||||
|
||||
@example
|
||||
(define-stream (stream-merge lt? . strms)
|
||||
(define-stream (merge xx yy)
|
||||
(stream-match xx (() yy) ((x . xs)
|
||||
(stream-match yy (() xx) ((y . ys)
|
||||
(if (lt? y x)
|
||||
(stream-cons y (merge xx ys))
|
||||
(stream-cons x (merge xs yy))))))))
|
||||
(stream-let loop ((strms strms))
|
||||
(cond ((null? strms) stream-null)
|
||||
((null? (cdr strms)) (car strms))
|
||||
(else (merge (car strms)
|
||||
(apply stream-merge lt?
|
||||
(cdr strms)))))))
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Syntax} stream-of expr clause @dots{}
|
||||
Provides the syntax of stream comprehensions, which generate streams by
|
||||
means of looping expressions. The result is a stream of objects of the
|
||||
type returned by @var{expr}. There are four types of clauses:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
(@var{var} @code{in} @var{stream-expr}) loops over the elements of
|
||||
@var{stream-expr}, in order from the start of the stream, binding each
|
||||
element of the stream in turn to @var{var}. @code{stream-from} and
|
||||
@code{stream-range} are frequently useful as generators for
|
||||
@var{stream-expr}.
|
||||
|
||||
@item
|
||||
(@var{var} @code{is} @var{expr}) binds @var{var} to the value obtained
|
||||
by evaluating @var{expr}.
|
||||
|
||||
@item
|
||||
(@var{pred} @var{expr}) includes in the output stream only those
|
||||
elements @var{x} which satisfy the predicate @var{pred}.
|
||||
@end itemize
|
||||
|
||||
The scope of variables bound in the stream comprehension is the clauses
|
||||
to the right of the binding clause (but not the binding clause itself)
|
||||
plus the result expression.
|
||||
|
||||
When two or more generators are present, the loops are processed as if
|
||||
they are nested from left to right; that is, the rightmost generator
|
||||
varies fastest. A consequence of this is that only the first generator
|
||||
may be infinite and all subsequent generators must be finite. If no
|
||||
generators are present, the result of a stream comprehension is a stream
|
||||
containing the result expression; thus, @samp{(stream-of 1)} produces a
|
||||
finite stream containing only the element 1.
|
||||
|
||||
@example
|
||||
(stream-of (* x x)
|
||||
(x in (stream-range 0 10))
|
||||
(even? x))
|
||||
@result{} 0 4 16 36 64
|
||||
|
||||
(stream-of (list a b)
|
||||
(a in (stream-range 1 4))
|
||||
(b in (stream-range 1 3)))
|
||||
@result{} (1 1) (1 2) (2 1) (2 2) (3 1) (3 2)
|
||||
|
||||
(stream-of (list i j)
|
||||
(i in (stream-range 1 5))
|
||||
(j in (stream-range (+ i 1) 5)))
|
||||
@result{} (1 2) (1 3) (1 4) (2 3) (2 4) (3 4)
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-range first past [step]
|
||||
Creates a newly-allocated stream that contains @var{first} as its first
|
||||
element and increments each succeeding element by @var{step}. The
|
||||
stream is finite and ends before @var{past}, which is not an element of
|
||||
the stream. If @var{step} is not given it defaults to 1 if @var{first}
|
||||
is less than past and -1 otherwise. @var{first}, @var{past} and
|
||||
@var{step} may be of any real numeric type. @code{stream-range} is
|
||||
frequently useful as a generator in @code{stream-of} expressions. See
|
||||
also @code{stream-from} for a similar procedure that creates infinite
|
||||
streams.
|
||||
|
||||
@example
|
||||
(stream-range 0 10) @result{} 0 1 2 3 4 5 6 7 8 9
|
||||
(stream-range 0 10 2) @result{} 0 2 4 6 8
|
||||
@end example
|
||||
|
||||
Successive elements of the stream are calculated by adding @var{step} to
|
||||
@var{first}, so if any of @var{first}, @var{past} or @var{step} are
|
||||
inexact, the length of the output stream may differ from
|
||||
@code{(ceiling (- (/ (- past first) step) 1)}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-ref stream n
|
||||
Returns the @var{n}th element of stream, counting from zero. An error
|
||||
is signaled if @var{n} is greater than or equal to the length of stream.
|
||||
|
||||
@example
|
||||
(define (fact n)
|
||||
(stream-ref
|
||||
(stream-scan * 1 (stream-from 1))
|
||||
n))
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-reverse stream
|
||||
Returns a newly-allocated stream containing the elements of the input
|
||||
@var{stream} but in reverse order. @code{stream-reverse} may only be
|
||||
used with finite streams; it enters an infinite loop with infinite
|
||||
streams. @code{stream-reverse} does not force evaluation of the
|
||||
elements of the stream.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-scan proc base stream
|
||||
Accumulates the partial folds of an input @var{stream} into a
|
||||
newly-allocated output stream. The output stream is the @var{base}
|
||||
followed by @code{(stream-fold proc base (stream-take i stream))} for
|
||||
each of the first @var{i} elements of @var{stream}.
|
||||
|
||||
@example
|
||||
(stream-scan + 0 (stream-from 1))
|
||||
@result{} (stream 0 1 3 6 10 15 @dots{})
|
||||
|
||||
(stream-scan * 1 (stream-from 1))
|
||||
@result{} (stream 1 1 2 6 24 120 @dots{})
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-take n stream
|
||||
Returns a newly-allocated stream containing the first @var{n} elements
|
||||
of the input @var{stream}. If the input @var{stream} has less than
|
||||
@var{n} elements, so does the output stream. See also
|
||||
@code{stream-drop}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-take-while pred stream
|
||||
Takes a predicate and a @code{stream} and returns a newly-allocated
|
||||
stream containing those elements @code{x} that form the maximal prefix
|
||||
of the input stream which satisfy @var{pred}. See also
|
||||
@code{stream-drop-while}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-unfold map pred gen base
|
||||
The fundamental recursive stream constructor. It constructs a stream by
|
||||
repeatedly applying @var{gen} to successive values of @var{base}, in the
|
||||
manner of @code{stream-iterate}, then applying @var{map} to each of the
|
||||
values so generated, appending each of the mapped values to the output
|
||||
stream as long as @code{(pred? base)} returns a true value. See also
|
||||
@code{stream-iterate} and @code{stream-unfolds}.
|
||||
|
||||
The expression below creates the finite stream @samp{0 1 4 9 16 25 36 49
|
||||
64 81}. Initially the @var{base} is 0, which is less than 10, so
|
||||
@var{map} squares the @var{base} and the mapped value becomes the first
|
||||
element of the output stream. Then @var{gen} increments the @var{base}
|
||||
by 1, so it becomes 1; this is less than 10, so @var{map} squares the
|
||||
new @var{base} and 1 becomes the second element of the output stream.
|
||||
And so on, until the base becomes 10, when @var{pred} stops the
|
||||
recursion and stream-null ends the output stream.
|
||||
|
||||
@example
|
||||
(stream-unfold
|
||||
(lambda (x) (expt x 2)) ; map
|
||||
(lambda (x) (< x 10)) ; pred?
|
||||
(lambda (x) (+ x 1)) ; gen
|
||||
0) ; base
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-unfolds proc seed
|
||||
Returns @var{n} newly-allocated streams containing those elements
|
||||
produced by successive calls to the generator @var{proc}, which takes
|
||||
the current @var{seed} as its argument and returns @var{n}+1 values
|
||||
|
||||
(@var{proc} @var{seed}) @result{} @var{seed} @var{result_0} @dots{} @var{result_n-1}
|
||||
|
||||
where the returned @var{seed} is the input @var{seed} to the next call
|
||||
to the generator and @var{result_i} indicates how to produce the next
|
||||
element of the @var{i}th result stream:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
(@var{value}): @var{value} is the next car of the result stream.
|
||||
|
||||
@item
|
||||
@code{#f}: no value produced by this iteration of the generator
|
||||
@var{proc} for the result stream.
|
||||
|
||||
@item
|
||||
(): the end of the result stream.
|
||||
@end itemize
|
||||
|
||||
It may require multiple calls of @var{proc} to produce the next element
|
||||
of any particular result stream. See also @code{stream-iterate} and
|
||||
@code{stream-unfold}.
|
||||
|
||||
@example
|
||||
(define (stream-partition pred? strm)
|
||||
(stream-unfolds
|
||||
(lambda (s)
|
||||
(if (stream-null? s)
|
||||
(values s '() '())
|
||||
(let ((a (stream-car s))
|
||||
(d (stream-cdr s)))
|
||||
(if (pred? a)
|
||||
(values d (list a) #f)
|
||||
(values d #f (list a))))))
|
||||
strm))
|
||||
|
||||
(call-with-values
|
||||
(lambda ()
|
||||
(stream-partition odd?
|
||||
(stream-range 1 6)))
|
||||
(lambda (odds evens)
|
||||
(list (stream->list odds)
|
||||
(stream->list evens))))
|
||||
@result{} ((1 3 5) (2 4))
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
@deffn {Scheme Procedure} stream-zip stream @dots{}
|
||||
Returns a newly-allocated stream in which each element is a list (not a
|
||||
stream) of the corresponding elements of the input @var{stream}s. The
|
||||
output stream is as long as the shortest input @var{stream}, if any of
|
||||
the input @var{stream}s is finite, or is infinite if all the input
|
||||
@var{stream}s are infinite.
|
||||
@end deffn
|
||||
|
||||
@node SRFI-42
|
||||
@subsection SRFI-42 - Eager Comprehensions
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue