3.14 Sequences
Sequence Constructors in Guide: Racket introduces sequences.
A sequence encapsulates an ordered stream of values. The elements of a sequence can be extracted with one of the for syntactic forms or with the procedures returned by sequence-generate.
The sequence datatype overlaps with many other datatypes. Among built-in datatypes, the sequence datatype includes the following:
lists (see Pairs and Lists)
vectors (see Vectors)
hash tables (see Hash Tables)
strings (see Strings)
byte strings (see Byte Strings)
input ports (see Ports)
In addition, make-do-sequence creates a sequence given a thunk that returns procedures to implement a generator, and the prop:sequence property can be associated with a structure type.
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 cause the bytes to be read from the port.
Inidvidual 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 Sequence Predicate and Constructors
(in-range end) → sequence? |
end : number? |
(in-range start end [step]) → sequence? |
start : number? |
end : number? |
step : number? = 1 |
(in-naturals [start]) → sequence? |
start : exact-nonnegative-integer? = 0 |
See Pairs and Lists for information on using lists as sequences.
(in-vector vec [start stop step]) → sequence? |
vec : vector? |
start : exact-nonnegative-integer? = 0 |
stop : (or/c exact-nonnegative-integer? #f) = #f |
step : (and/c exact-integer? (not/c zero?)) = 1 |
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 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. The start and stop values are not checked against the size of vec, so access can fail when an element is demanded from the sequence.
An in-vector application can provide better performance for vector iteration when it appears directly in a for clause.
(in-string str [start stop step]) → sequence? |
str : string? |
start : exact-nonnegative-integer? = 0 |
stop : (or/c exact-nonnegative-integer? #f) = #f |
step : (and/c exact-integer? (not/c zero?)) = 1 |
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.
(in-bytes bstr [start stop step]) → sequence? |
bstr : bytes? |
start : exact-nonnegative-integer? = 0 |
stop : (or/c exact-nonnegative-integer? #f) = #f |
step : (and/c exact-integer? (not/c zero?)) = 1 |
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.
(in-port [r in]) → sequence? |
r : (input-port? . -> . any/c) = read |
in : input-port? = (current-input-port) |
(in-input-port-bytes in) → sequence? |
in : input-port? |
(in-input-port-chars in) → sequence? |
in : input-port? |
(in-lines [in mode]) → sequence? | ||||||||||||
in : input-port? = (current-input-port) | ||||||||||||
|
(in-bytes-lines [in mode]) → sequence? | ||||||||||||
in : input-port? = (current-input-port) | ||||||||||||
|
See Hash Tables for information on using hash tables as sequences.
(in-hash-keys hash) → sequence? |
hash : hash? |
(in-hash-values hash) → sequence? |
hash : hash? |
(in-hash-pairs hash) → sequence? |
hash : hash? |
(in-directory [dir]) → sequence? |
dir : (or/c #f path-string?) = #f |
(in-producer producer stop args ...) → sequence? |
producer : procedure? |
stop : any/c |
args : any/c |
(in-indexed seq) → sequence? |
seq : sequence? |
(in-sequences seq ...) → sequence? |
seq : sequence? |
(in-parallel seq ...) → sequence? |
seq : sequence? |
(make-do-sequence thunk) → sequence? | ||||||||||||
|
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 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).
The fifth result is like the fourth result, but it takes the current element value(s) instead of the current position.
The sixth result is like the fourth result, but it takes both the current position and the current element values(s) and determines a sequence end after the current element is already included in the sequence.
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 the other two functions always return #t.
Examples: | ||||||||||
| ||||||||||
| ||||||||||
'(engine boxcar caboose) |
3.14.2 Sequence Generators
3.14.3 Iterator Generators
(generator () body ...) |
Note: The first form must be (). In the future, the () position will hold argument names that are used for the initial generator call.
Examples: | |||||||
| |||||||
> (g) | |||||||
'a | |||||||
> (g) | |||||||
'b | |||||||
> (g) | |||||||
'c | |||||||
> (g) | |||||||
0 | |||||||
> (g) | |||||||
0 |
To use an existing generator as a sequence, you should use in-producer with a stop-value known to the generator.
Examples: | |||||||
> (define my-stop-value (gensym)) | |||||||
| |||||||
| |||||||
'(a b c) |
(infinite-generator body ...) |
Examples: | ||||
| ||||
> (welcome) | ||||
'hello | ||||
> (welcome) | ||||
'goodbye | ||||
> (welcome) | ||||
'hello | ||||
> (welcome) | ||||
'goodbye |
(in-generator expr ...) → sequence? |
expr : any? |
Example: | ||||||
| ||||||
'(a b c) |
(yield expr ...) |
Values can be passed back to the generator after invoking yield by passing the arguments to the generator instance. Note that a value cannot be passed back to the generator until after the first yield has been invoked.
Examples: |
> (define my-generator (generator () (yield 1) (yield 2 3 4))) |
> (my-generator) |
1 |
> (my-generator) |
2 |
3 |
4 |
Examples: | |||||
| |||||
> (pass-values-generator) | |||||
2 | |||||
> (pass-values-generator 5) | |||||
6 | |||||
> (pass-values-generator 12) | |||||
12 |
(generator-state g) → symbol? |
g : any? |
'fresh - The generator has been freshly created and has not been invoked yet. Values cannot be passed to a fresh generator.
'suspended - Control within the generator has been suspended due to a call to yield. The generator can be invoked.
'running - The generator is currently executing. This state can only be returned if generator-state is invoked inside the generator.
'done - The generator has executed its entire body and will not call yield anymore.
Examples: | ||
> (define my-generator (generator () (yield 1) (yield 2))) | ||
> (generator-state my-generator) | ||
'fresh | ||
> (my-generator) | ||
1 | ||
> (generator-state my-generator) | ||
'suspended | ||
> (my-generator) | ||
2 | ||
> (generator-state my-generator) | ||
'suspended | ||
> (my-generator) | ||
> (generator-state my-generator) | ||
'done | ||
> (define introspective-generator (generator () ((yield 1)))) | ||
> (introspective-generator) | ||
1 | ||
| ||
'running | ||
> (generator-state introspective-generator) | ||
'done | ||
> (introspective-generator) | ||
'running |
(sequence->generator s) → (-> any?) |
s : sequence? |
(sequence->repeated-generator s) → (-> any?) |
s : sequence? |