Next: streams examples, Previous: streams match, Up: streams [Index]
Streams, being the signature structured data type of functional programming languages, find useful expression in conjunction with higher–order functions. Some of these higher–order functions, and their relationship to streams, are described below.
The identity and constant procedures are frequently useful as the
recursive base for maps and folds; (identity obj)
always returns
obj, and (const obj)
creates a procedure that takes any
number of arguments and always returns the same obj, no matter its
arguments:
(define (identity obj) obj) (define (const obj) (lambda x obj))
Many of the stream procedures take a unary predicate that accepts an
element of a stream and returns a boolean. Procedure (negate
pred)
takes a unary predicate and returns a new unary predicate that,
when called, returns the opposite boolean value as the original
predicate.
(define (negate pred) (lambda (x) (not (pred x))))
negate
is useful for procedures like stream-take-while
that take a predicate, allowing them to be used in the opposite
direction from which they were written; for instance, with the predicate
reversed, stream-take-while
becomes stream-take-until
.
stream-remove
is the opposite of stream-filter
:
(define-stream (stream-remove pred strm) (stream-filter (negate pred) strm))
A section is a procedure which has been partially applied to some of its
arguments; for instance, (double x)
, which returns twice its
argument, is a partial application of the multiply operator to the
number 2. Sections come in two kinds:
The procedure lsec
takes a procedure and some prefix of its
arguments and returns a new procedure in which those arguments are
partially applied; the procedure rsec
takes a procedure and some
reversed suffix of its arguments and returns a new procedure in which
those arguments are partially applied:
(define (lsec proc . args) (lambda x (apply proc (append args x)))) (define (rsec proc . args) (lambda x (apply proc (reverse (append (reverse args) (reverse x))))))
Since most of the stream procedures take a stream as their last (rightmost) argument, left sections are particularly useful in conjunction with streams.
(define stream-sum (lsec stream-fold + 0))
Function composition creates a new function by partially applying
multiple functions, one after the other. In the simplest case there are
only two functions, f and g, composed as (compose f
g)
; the composition can be bound to create a new function, as in:
(define fg (compose f g))
the procedure compose
takes one or more procedures and returns a
new procedure that performs the same action as the individual procedures
would if called in succession:
(define (compose . fns) (let comp ((fns fns)) (cond ((null? fns) 'error) ((null? (cdr fns)) (car fns)) (else (lambda args (call-with-values (lambda () (apply (comp (cdr fns)) args)) (car fns)))))))
compose
works with sections to create succinct but highly
expressive procedure definitions. The expression to compute the squares
of the integers from 1 to 10 given above at stream-unfold
could
be written by composing stream-map
, stream-take-while
, and
stream-iterate
:
((compose (lsec stream-map (rsec expt 2)) (lsec stream-take-while (negate (rsec > 10))) (lsec stream-iterate (rsec + 1))) 1)
Next: streams examples, Previous: streams match, Up: streams [Index]