3.14.1 Sequences

► |  | The Racket Reference

1 | Language Model
2 | Syntactic Forms
3 | Datatypes
4 | Structures
5 | Classes and Objects
6 | Units
7 | Contracts
8 | Pattern Matching
9 | Control Flow
10 | Concurrency and Parallelism
11 | Macros
12 | Input and Output
13 | Reflection and Security
14 | Operating System
15 | Memory Management
16 | Unsafe Operations
17 | Running Racket
| Bibliography
| Index

► | 3 | Datatypes

3.1 | Booleans and Equality
3.2 | Numbers
3.3 | Strings
3.4 | Byte Strings
3.5 | Characters
3.6 | Symbols
3.7 | Regular Expressions
3.8 | Keywords
3.9 | Pairs and Lists
3.10 | Mutable Pairs and Lists
3.11 | Vectors
3.12 | Boxes
3.13 | Hash Tables
3.14 | Sequences and Streams
3.15 | Dictionaries
3.16 | Sets
3.17 | Procedures
3.18 | Void and Undefined

▼ | 3.14 | Sequences and Streams

3.14.1 | Sequences
3.14.2 | Streams
3.14.3 | Generators

► | 3.14.1 | Sequences

3.14.1.1 | Sequence Predicate and Constructors
3.14.1.2 | Sequence Conversion
3.14.1.3 | Sequence Combinations

On this page:

3.14.1.1`` Sequence Predicate and Constructors
sequence?
in-range
in-naturals
in-list
in-mlist
in-vector
in-string
in-bytes
in-port
in-input-port-bytes
in-input-port-chars
in-lines
in-bytes-lines
in-hash
in-hash-keys
in-hash-values
in-hash-pairs
in-directory
in-producer
in-value
in-indexed
in-sequences
in-cycle
in-parallel
in-values-sequence
in-values*-sequence
stop-before
stop-after
make-do-sequence
prop: sequence
3.14.1.2`` Sequence Conversion
sequence->stream
sequence-generate
sequence-generate*
3.14.1.3`` Sequence Combinations
empty-sequence
sequence->list
sequence-length
sequence-ref
sequence-tail
sequence-append
sequence-map
sequence-andmap
sequence-ormap
sequence-for-each
sequence-fold
sequence-count
sequence-filter
sequence-add-between

top ← prev up next →

##### 3.14.1`` Sequences

> > > Sequence Constructors in The Racket Guide introduces sequences.

A sequence encapsulates an ordered collection of values. The elements of a sequence can be extracted with one of the for syntactic forms, with the procedures returned by sequence-generate, or by converting the sequence into a stream.

The sequence datatype overlaps with many other datatypes. Among built-in datatypes, the sequence datatype includes the following:

- exact nonnegative integers (see below)

- strings (see Strings)

- byte strings (see Byte Strings)

- lists (see Pairs and Lists)

- mutable lists (see Mutable Pairs and Lists)

- vectors (see Vectors)

- hash tables (see Hash Tables)

- dictionaries (see Dictionaries)

- sets (see Sets)

- input ports (see Ports)

- streams (see Streams)

An exact number k that is a non-negative integer acts as a sequence similar to (in-range k), except that k by itself is not a stream.

Custom sequences can be defined using structure type properties. The easiest method to define a custom sequence is to use the gen:stream generic interface. Streams are a suitable abstraction for data structures that are directly iterable. For example, a list is directly iterable with first and rest. On the other hand, vectors are not directly iterable: iteration has to go through an index. For data structures that are not directly iterable, the iterator for the data structure can be defined to be a stream (e.g., a structure containing the index of a vector).

For example, unrolled linked lists (represented as a list of vectors) themselves do not fit the stream abstraction, but have index-based iterators that can be represented as streams:

Examples:
> > (struct unrolled-list-iterator (idx lst)
> #:methods gen:stream
> [(define (stream-empty? iter)
> (define lst (unrolled-list-iterator-lst iter))
> (or (null? lst)
> (and (>= (unrolled-list-iterator-idx iter)
> (vector-length (first lst)))
> (null? (rest lst)))))
> (define (stream-first iter)
> (vector-ref (first (unrolled-list-iterator-lst iter))
> (unrolled-list-iterator-idx iter)))
> (define (stream-rest iter)
> (define idx (unrolled-list-iterator-idx iter))
> (define lst (unrolled-list-iterator-lst iter))
> (if (>= idx (sub1 (vector-length (first lst))))
> (unrolled-list-iterator 0 (rest lst))
> (unrolled-list-iterator (add1 idx) lst)))])
> > (define (make-unrolled-list-iterator ul)
> (unrolled-list-iterator 0 (unrolled-list-lov ul)))
> > (struct unrolled-list (lov)
> #:property prop:sequence
> make-unrolled-list-iterator)
> > (define ul1 (unrolled-list '(#(cracker biscuit) #(cookie scone))))
> > (for/list ([x ul1]) x)
> '(cracker biscuit cookie scone)

The prop:sequence property provides more flexibility in specifying iteration, such as when a pre-processing step is needed to prepare the data for iteration. The make-do-sequence function creates a sequence given a thunk that returns procedures to implement a sequence, and the prop:sequence property can be associated with a structure type to implement its implicit conversion to a sequence.

For most sequence types, extracting elements from a sequence has no side-effect on the original sequence value; for example, extracting the sequence of elements from a list does not change the list. For other sequence types, each extraction implies a side effect; for example, extracting the sequence of bytes from a port causes the bytes to be read from the port. A sequence’s state may either span all uses of the sequence, as for a port, or it may be confined to each distinct time that a sequence is initiated by a for form, sequence->stream, sequence-generate, or sequence-generate*. Concretely, the thunk passed to make-do-sequence is called to initiate the sequence each time the sequence is used.

Individual elements of a sequence typically correspond to single values, but an element may also correspond to multiple values. For example, a hash table generates two values—a key and its value—for each element in the sequence.

##### 3.14.1.1`` Sequence Predicate and Constructors

> procedure (sequence? v) → boolean?
> v : any/c

Returns #t if v can be used as a sequence, #f otherwise.

> > (sequence? 42)
> #t
> > (sequence? '(a b c))
> #t
> > (sequence? "word")
> #t
> > (sequence? #\x)
> #f

> procedure (in-range end) → stream?
> end : number?
> (in-range start end [step]) → stream?
> start : number?
> end : number?
> step : number? = 1

Returns a sequence (that is also a stream) whose elements are numbers. The single-argument case (in-range end) is equivalent to (in-range 0 end 1). The first number in the sequence is start, and each successive element is generated by adding step to the previous element. The sequence stops before an element that would be greater or equal to end if step is non-negative, or less or equal to end if step is negative.
An in-range application can provide better performance for number iteration when it appears directly in a for clause.

Example: gaussian sum

> > (for/sum ([x (in-range 10)]) x)
> 45

Example: sum of even numbers

> > (for/sum ([x (in-range 0 100 2)]) x)
> 2450

> procedure (in-naturals [start]) → stream?
> start : exact-nonnegative-integer? = 0

Returns an infinite sequence (that is also a stream) of exact integers starting with start, where each element is one more than the preceding element.
An in-naturals application can provide better performance for integer iteration when it appears directly in a for clause.

> > (for/list ([k (in-naturals)]
> [x (in-range 10)])
> (list k x))
> '((0 0) (1 1) (2 2) (3 3) (4 4) (5 5) (6 6) (7 7) (8 8) (9 9))

> procedure (in-list lst) → stream?
> lst : list?

Returns a sequence (that is also a stream) that is equivalent to using lst directly as a sequence.

> > > See Pairs and Lists for information on using lists as sequences.

An in-list application can provide better performance for list iteration when it appears directly in a for clause.

> > (for/list ([x (in-list '(3 1 4))])
> `(,x ,(* x x)))
> '((3 9) (1 1) (4 16))

> procedure (in-mlist mlst) → sequence?
> mlst : mlist?

Returns a sequence equivalent to mlst.

> > > See Mutable Pairs and Lists for information on using mutable lists as sequences.

An in-mlist application can provide better performance for mutable list iteration when it appears directly in a for clause.

> > (for/list ([x (in-mlist (mcons "RACKET" (mcons "LANG" '())))])
> (string-length x))
> '(6 4)

> procedure (in-vector vec [start stop step]) → sequence?
> vec : vector?
> start : exact-nonnegative-integer? = 0
> stop : (or/c exact-integer? #f) = #f
> step : (and/c exact-integer? (not/c zero?)) = 1

Returns a sequence equivalent to vec when no optional arguments are supplied.

> > > See Vectors for information on using vectors as sequences.

The optional arguments start, stop, and step are analogous to in-range, except that a #f value for stop is equivalent to (vector-length vec). That is, the first element in the sequence is (vector-ref vec start), and each successive element is generated by adding step to index of the previous element. The sequence stops before an index that would be greater or equal to end if step is non-negative, or less or equal to end if step is negative.

If start is not a valid index, or stop is not in [-1, (vector-length vec)] then the exn:fail:contract exception is raised. If start is less than stop and step is negative, then the exn:fail:contract:mismatch exception is raised. Similarly, if start is more than stop and step is positive, then the exn:fail:contract:mismatch exception is raised.

An in-vector application can provide better performance for vector iteration when it appears directly in a for clause.

> > (define (histogram vector-of-words)
> (define a-hash (hash))
> (for ([word (in-vector vector-of-words)])
> (hash-set! a-hash word (add1 (hash-ref a-hash word 0))))
> a-hash)
> > (histogram #("hello" "world" "hello" "sunshine"))
> hash-set!: contract violation
> expected: (and/c hash? (not/c immutable?))
> given: '#hash()
> argument position: 1st
> other arguments...:
> "hello"
> 1

> procedure (in-string str [start stop step]) → sequence?
> str : string?
> start : exact-nonnegative-integer? = 0
> stop : (or/c exact-integer? #f) = #f
> step : (and/c exact-integer? (not/c zero?)) = 1

Returns a sequence equivalent to str when no optional arguments are supplied.

> > > See Strings for information on using strings as sequences.

The optional arguments start, stop, and step are as in in-vector.

An in-string application can provide better performance for string iteration when it appears directly in a for clause.

> > (define (line-count str)
> (for/sum ([ch (in-string str)])
> (if (char=? #\newline ch) 1 0)))
> > (line-count "this string\nhas\nthree \nnewlines")
> 3

> procedure (in-bytes bstr [start stop step]) → sequence?
> bstr : bytes?
> start : exact-nonnegative-integer? = 0
> stop : (or/c exact-integer? #f) = #f
> step : (and/c exact-integer? (not/c zero?)) = 1

Returns a sequence equivalent to bstr when no optional arguments are supplied.

> > > See Byte Strings for information on using byte strings as sequences.

The optional arguments start, stop, and step are as in in-vector.

An in-bytes application can provide better performance for byte string iteration when it appears directly in a for clause.

> > (define (has-eof? bs)
> (for/or ([ch (in-bytes bs)])
> (= ch 0)))
> > (has-eof? #"this byte string has an \0embedded zero byte")
> #t
> > (has-eof? #"this byte string does not")
> #f

> procedure (in-port [r in]) → sequence?
> r : (input-port? . -> . any/c) = read
> in : input-port? = (current-input-port)

Returns a sequence whose elements are produced by calling r on in until it produces eof.

> procedure (in-input-port-bytes in) → sequence?
> in : input-port?

Returns a sequence equivalent to (in-port read-byte in).

> procedure (in-input-port-chars in) → sequence?
> in : input-port?

Returns a sequence whose elements are read as characters from in (equivalent to (in-port read-char in)).

> procedure (in-lines [in mode]) → sequence?
> in : input-port? = (current-input-port)
> | mode |  | : |  | (or/c 'linefeed 'return 'return-linefeed 'any 'any-one)
> |  |  | = |  | 'any

Returns a sequence equivalent to (in-port (lambda (p) (read-line p mode)) in). Note that the default mode is 'any, whereas the default mode of read-line is 'linefeed.

> procedure (in-bytes-lines [in mode]) → sequence?
> in : input-port? = (current-input-port)
> | mode |  | : |  | (or/c 'linefeed 'return 'return-linefeed 'any 'any-one)
> |  |  | = |  | 'any

Returns a sequence equivalent to (in-port (lambda (p) (read-bytes-line p mode)) in). Note that the default mode is 'any, whereas the default mode of read-bytes-line is 'linefeed.

> procedure (in-hash hash) → sequence?
> hash : hash?

Returns a sequence equivalent to hash.

Examples:
> > (define table (hash 'a 1 'b 2))
> > (for ([(key value) (in-hash table)])
> (printf "key: ~a value: ~a\n" key value))
> key: b value: 2
> key: a value: 1

> > > See Hash Tables for information on using hash tables as sequences.

> procedure (in-hash-keys hash) → sequence?
> hash : hash?

Returns a sequence whose elements are the keys of hash.

Examples:
> > (define table (hash 'a 1 'b 2))
> > (for ([key (in-hash-keys table)])
> (printf "key: ~a\n" key))
> key: b
> key: a

> procedure (in-hash-values hash) → sequence?
> hash : hash?

Returns a sequence whose elements are the values of hash.

Examples:
> > (define table (hash 'a 1 'b 2))
> > (for ([value (in-hash-values table)])
> (printf "value: ~a\n" value))
> value: 2
> value: 1

> procedure (in-hash-pairs hash) → sequence?
> hash : hash?

Returns a sequence whose elements are pairs, each containing a key and its value from hash (as opposed to using hash directly as a sequence to get the key and value as separate values for each element).

Examples:
> > (define table (hash 'a 1 'b 2))
> > (for ([key+value (in-hash-pairs table)])
> (printf "key and value: ~a\n" key+value))
> key and value: (b . 2)
> key and value: (a . 1)

> procedure (in-directory [dir]) → sequence?
> dir : (or/c #f path-string?) = #f

Returns a sequence that produces all of the paths for files, directories, and links within dir. If dir is not #f, then every produced path starts with dir as its prefix. If dir is #f, then paths in and relative to the current directory are produced.

An in-directory sequence traverses nested subdirectories recursively. To generate a sequence that includes only the immediate content of a directory, use the result of directory-list as a sequence.

> procedure (in-producer producer stop arg ...) → sequence?
> producer : procedure?
> stop : any/c
> arg : any/c

Returns a sequence that contains values from sequential calls to producer, providing all args to every call to producer. A stop value returned by producer marks the end of the sequence (and the stop value is not included in the sequence); stop can be a predicate that is applied to the results of producer, or it can be a value that is tested against the result of with eq?. (The stop argument must be a predicate if the stop value is itself a function or if producer returns multiple values.)

> procedure (in-value v) → sequence?
> v : any/c

Returns a sequence that produces a single value: v. This form is mostly useful for let-like bindings in forms such as for*/list.

> procedure (in-indexed seq) → sequence?
> seq : sequence?

Returns a sequence where each element has two values: the value produced by seq, and a non-negative exact integer starting with 0. The elements of seq must be single-valued.

> procedure (in-sequences seq ...) → sequence?
> seq : sequence?

Returns a sequence that is made of all input sequences, one after the other. Each seq is initiated only after the preceding seq is exhausted. If a single seq is provided, then seq is returned; otherwise, the elements of each seq must all have the same number of values.

> procedure (in-cycle seq ...) → sequence?
> seq : sequence?

Similar to in-sequences, but the sequences are repeated in an infinite cycle, where each seq is initiated afresh in each iteration. Beware that if no seqs are provided or if all seqs become empty, then the sequence produced by in-cycle never returns when an element is demanded—or even when the sequence is initiated, if all seqs are initially empty.

> procedure (in-parallel seq ...) → sequence?
> seq : sequence?

Returns a sequence where each element has as many values as the number of supplied seqs; the values, in order, are the values of each seq. The elements of each seq must be single-valued.

> procedure (in-values-sequence seq) → sequence?
> seq : sequence?

Returns a sequence that is like seq, but it combines multiple values for each element from seq as a list of elements.

> procedure (in-values*-sequence seq) → sequence?
> seq : sequence?

Returns a sequence that is like seq, but when an element of seq has multiple values or a single list value, then the values are combined in a list. In other words, in-values*-sequence is like in-values-sequence, except that non-list, single-valued elements are not wrapped in a list.

> procedure (stop-before seq pred) → sequence?
> seq : sequence?
> pred : (any/c . -> . any)

Returns a sequence that contains the elements of seq (which must be single-valued), but only until the last element for which applying pred to the element produces #t, after which the sequence ends.

> procedure (stop-after seq pred) → sequence?
> seq : sequence?
> pred : (any/c . -> . any)

Returns a sequence that contains the elements of seq (which must be single-valued), but only until the element (inclusive) for which applying pred to the element produces #t, after which the sequence ends.

> procedure (make-do-sequence thunk) → sequence?
> | thunk |  | : |  |
> (-> (values (any/c . -> . any)
> (any/c . -> . any/c)
> any/c
> (or/c (any/c . -> . any/c) #f)
> (or/c (() () #:rest list? . ->* . any/c) #f)
> (or/c ((any/c) () #:rest list? . ->* . any/c) #f)))

Returns a sequence whose elements are generated by the procedures and initial value returned by the thunk, which is called to initiate the sequence. The initiated sequence is defined in terms of a position, which is initialized to the third result of the thunk, and the element, which may consist of multiple values.

The thunk results define the generated elements as follows:

- The first result is a pos->element procedure that takes the current position and returns the value(s) for the current element.

- The second result is a next-pos procedure that takes the current position and returns the next position.

- The third result is the initial position.

- The fourth result is a continue-with-pos? function that takes the current position and returns a true result if the sequence includes the value(s) for the current position, and false if the sequence should end instead of including the value(s). Alternatively, the fourth result can be #f to indicate that the sequence should always include the current value(s).

- The fifth result is a continue-with-val? function that is like the fourth result, but it takes the current element value(s) instead of the current position. Alternatively, the fifth result can be #f to indicate that the sequence should always include the value(s) at the current position.

- The sixth result is a continue-after-pos+val? procedure that takes both the current position and the current element value(s) and determines whether the sequence ends after the current element is already included in the sequence. Alternatively, the sixth result can be #f to indicate that the sequence can always continue after the current value(s).

Each of the procedures listed above is called only once per position. Among the last three procedures, as soon as one of the procedures returns #f, the sequence ends, and none are called again. Typically, one of the functions determines the end condition, and #f is used in place of the other two functions.

> value prop:sequence : struct-type-property?

Associates a procedure to a structure type that takes an instance of the structure and returns a sequence. If v is an instance of a structure type with this property, then (sequence? v) produces #t.

Using a pre-existing sequence:

Examples:
> > (struct my-set (table)
> #:property prop:sequence
> (lambda (s)
> (in-hash-keys (my-set-table s))))
> > (define (make-set . xs)
> (my-set (for/hash ([x (in-list xs)])
> (values x #t))))
> > (for/list ([c (make-set 'celeriac 'carrot 'potato)])
> c)
> '(carrot celeriac potato)

Using make-do-sequence:

Examples:
> > (define-struct train (car next)
> #:property prop:sequence
> (lambda (t)
> (make-do-sequence
> (lambda ()
> (values train-car train-next t
> (lambda (t) t)
> (lambda (v) #t)
> (lambda (t v) #t))))))
> > (for/list ([c (make-train 'engine
> (make-train 'boxcar
> (make-train 'caboose
> #f)))])
> c)
> '(engine boxcar caboose)

##### 3.14.1.2`` Sequence Conversion

> procedure (sequence->stream seq) → stream?
> seq : sequence?

Coverts a sequence to a stream, which supports the stream-first and stream-rest operations. Creation of the stream eagerly initiates the sequence, but the stream lazily draws elements from the sequence, caching each element so that stream-first produces the same result each time is applied to a stream.

If extracting an element from seq involves a side-effect, then the effect is performed each time that either stream-first or stream-rest is first used to access or skip an element.

> > procedure
> > (sequence-generate seq) |  | → |  |
> > (-> boolean?) |  | (-> any)
> seq : sequence?

Initiates a sequence and returns two thunks to extract elements from the sequence. The first returns #t if more values are available for the sequence. The second returns the next element (which may be multiple values) from the sequence; if no more elements are available, the exn:fail:contract exception is raised.

> procedure (sequence-generate* seq)
> | → |  |
> (or/c list? #f)
> (-> (values (or/c list? #f) procedure?))
> seq : sequence?

Like sequence-generate, but avoids state (aside from any inherent in the sequence) by returning a list of values for the sequence’s first element—or #f if the sequence is empty—and a thunk to continue with the sequence; the result of the thunk is the same as the result of sequence-generate*, but for the second element of the sequence, and so on. If the thunk is called when the element result is #f (indicating no further values in the sequence), the exn:fail:contract exception is raised.

##### 3.14.1.3`` Sequence Combinations

(require racket/sequence)

The bindings documented in this section are provided by the racket/sequence and racket libraries, but not racket/base.

> value empty-sequence : sequence?

A sequence with no elements.

> procedure (sequence->list s) → list?
> s : sequence?

Returns a list whose elements are the elements of s, each of which must be a single value. If s is infinite, this function does not terminate.

> procedure (sequence-length s) → exact-nonnegative-integer?
> s : sequence?

Returns the number of elements of s by extracting and discarding all of them. If s is infinite, this function does not terminate.

> procedure (sequence-ref s i) → any
> s : sequence?
> i : exact-nonnegative-integer?

Returns the ith element of s (which may be multiple values).

> procedure (sequence-tail s i) → sequence?
> s : sequence?
> i : exact-nonnegative-integer?

Returns a sequence equivalent to s, except that the first i elements are omitted.

In case initiating s involves a side effect, the sequence s is not initiated until the resulting sequence is initiated, at which point the first i elements are extracted from the sequence.

> procedure (sequence-append s ...) → sequence?
> s : sequence?

Returns a sequence that contains all elements of each sequence in the order they appear in the original sequences. The new sequence is constructed lazily.

If all given ss are streams, the result is also a stream.

> procedure (sequence-map f s) → sequence?
> f : procedure?
> s : sequence?

Returns a sequence that contains f applied to each element of s. The new sequence is constructed lazily.

If s is a stream, then the result is also a stream.

> procedure (sequence-andmap f s) → boolean?
> f : (-> any/c ... boolean?)
> s : sequence?

Returns #t if f returns a true result on every element of s. If s is infinite and f never returns a false result, this function does not terminate.

> procedure (sequence-ormap f s) → boolean?
> f : (-> any/c ... boolean?)
> s : sequence?

Returns #t if f returns a true result on some element of s. If s is infinite and f never returns a true result, this function does not terminate.

> procedure (sequence-for-each f s) → void?
> f : (-> any/c ... any)
> s : sequence?

Applies f to each element of s. If s is infinite, this function does not terminate.

> procedure (sequence-fold f i s) → any/c
> f : (-> any/c any/c ... any/c)
> i : any/c
> s : sequence?

Folds f over each element of s with i as the initial accumulator. If s is infinite, this function does not terminate. The f function takes the accumulator as its first argument and the next sequence element as its second.

> procedure (sequence-count f s) → exact-nonnegative-integer?
> f : procedure?
> s : sequence?

Returns the number of elements in s for which f returns a true result. If s is infinite, this function does not terminate.

> procedure (sequence-filter f s) → sequence?
> f : (-> any/c ... boolean?)
> s : sequence?

Returns a sequence whose elements are the elements of s for which f returns a true result. Although the new sequence is constructed lazily, if s has an infinite number of elements where f returns a false result in between two elements where f returns a true result, then operations on this sequence will not terminate during the infinite sub-sequence.

If s is a stream, then the result is also a stream.

> procedure (sequence-add-between s e) → sequence?
> s : sequence?
> e : any/c

Returns a sequence whose elements are the elements of s, but with e between each pair of elements in s. The new sequence is constructed lazily.

If s is a stream, then the result is also a stream.

Examples:
> > (let* ([all-reds (in-cycle '("red"))]
> [red-and-blues (sequence-add-between all-reds "blue")])
> (for/list ([n (in-range 10)]
> [elt red-and-blues])
> elt))
> '("red" "blue" "red" "blue" "red" "blue" "red" "blue" "red" "blue")
> > (for ([text (sequence-add-between '("veni" "vidi" "duci") ", ")])
> (display text))
> veni, vidi, duci

top ← prev up next →