/
sequences.scrbl
1708 lines (1425 loc) · 66.3 KB
/
sequences.scrbl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#lang scribble/doc
@(require "mz.rkt"
scribble/scheme
(for-syntax racket/base)
(for-label racket/generator
racket/generic
compatibility/mlist
syntax/stx))
@(define (info-on-seq where what)
@margin-note{See @secref[where] for information on using @|what| as
sequences.})
@(define (for-element-reachability what)
@elem{See @racket[for] for information on the reachability of @|what| elements
during an iteration.})
@title[#:style 'toc #:tag "sequences+streams"]{Sequences and Streams}
@tech{Sequences} and @tech{streams} abstract over iteration of elements in a
collection. Sequences allow iteration with @racket[for] macros or with sequence
operations such as @racket[sequence-map]. Streams are functional sequences that
can be used either in a generic way or a stream-specific way. @tech{Generators}
are closely related stateful objects that can be converted to a sequence and
vice-versa.
@local-table-of-contents[]
@; ======================================================================
@section[#:tag "sequences"]{Sequences}
@(define sequence-evaluator
(let ([evaluator (make-base-eval)])
(evaluator '(require racket/generic racket/list racket/stream racket/sequence
racket/contract racket/dict))
evaluator))
@guideintro["sequences"]{sequences}
A @deftech{sequence} encapsulates an ordered collection of values.
The elements of a sequence can be extracted with one of the
@racket[for] syntactic forms, with the procedures returned by
@racket[sequence-generate], or by converting the sequence into a
@tech{stream}.
The sequence datatype overlaps with many other datatypes. Among
built-in datatypes, the sequence datatype includes the following:
@itemize[
@item{exact nonnegative integers (see below)}
@item{strings (see @secref["strings"])}
@item{byte strings (see @secref["bytestrings"])}
@item{lists (see @secref["pairs"])}
@item{mutable lists (see @secref["mpairs"])}
@item{vectors (see @secref["vectors"])}
@item{flvectors (see @secref["flvectors"])}
@item{fxvectors (see @secref["fxvectors"])}
@item{hash tables (see @secref["hashtables"])}
@item{dictionaries (see @secref["dicts"])}
@item{sets (see @secref["sets"])}
@item{input ports (see @secref["ports"])}
@item{streams (see @secref["streams"])}
]
An @tech{exact number} @racket[_k] that is a non-negative
@tech{integer} acts as a sequence similar to @racket[(in-range _k)],
except that @racket[_k] by itself is not a @tech{stream}.
Custom sequences can be defined using structure type properties. The
easiest method to define a custom sequence is to use the
@racket[gen:stream] @tech{generic interface}. Streams are a suitable
abstraction for data structures that are directly iterable. For
example, a list is directly iterable with @racket[first] and
@racket[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 @deftech{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[#:eval sequence-evaluator
(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)
]
The @racket[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 @racket[make-do-sequence]
function creates a sequence given a thunk that returns procedures to
implement a sequence, and the @racket[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. @elemtag["sequence-state"]{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 @deftech{initiate}d by a @racket[for] form,
@racket[sequence->stream], @racket[sequence-generate], or
@racket[sequence-generate*]. Concretely, the thunk passed to
@racket[make-do-sequence] is called to @tech{initiate} the sequence
each time the sequence is used. Accordingly, different sequences behave
differently when they are @tech{initiate}d multiple times.
@examples[#:eval sequence-evaluator
#:label #f
(define (double-initiate s1)
(code:comment "initiate the sequence twice")
(define-values (more?.1 next.1) (sequence-generate s1))
(define-values (more?.2 next.2) (sequence-generate s1))
(code:comment "alternate fetching from sequence via the two initiations")
(list (next.1) (next.2) (next.1) (next.2)))
(double-initiate (open-input-string "abcdef"))
(double-initiate (list 97 98 99 100))
(double-initiate (in-naturals 97))]
Also, subsequent elements in a sequence may be ``consumed'' just by calling the
first result of @racket[sequence-generate], even if the second
result is never called.
@examples[#:eval sequence-evaluator
#:label #f
(define (double-initiate-and-use-more? s1)
(code:comment "initiate the sequence twice")
(define-values (more?.1 next.1) (sequence-generate s1))
(define-values (more?.2 next.2) (sequence-generate s1))
(code:comment "alternate fetching from sequence via the two initiations")
(code:comment "but this time call `more?` in between")
(list (next.1) (more?.1) (next.2) (more?.2)
(next.1) (more?.1) (next.2) (more?.2)))
(double-initiate-and-use-more? (open-input-string "abcdef"))]
In this example, the state embedded in the first call to @racket[sequence-generate]
``takes'' the @racket[98] just by virtue of the invocation of @racket[_more?.1].
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.
@; ----------------------------------------------------------------------
@subsection{Sequence Predicate and Constructors}
@defproc[(sequence? [v any/c]) boolean?]{
Returns @racket[#t] if @racket[v] can be used as a @tech{sequence},
@racket[#f] otherwise.
@examples[#:eval sequence-evaluator
(sequence? 42)
(sequence? '(a b c))
(sequence? "word")
(sequence? #\x)]}
@defproc*[([(in-range [end real?]) stream?]
[(in-range [start real?] [end real?] [step real? 1]) stream?])]{
Returns a sequence (that is also a @tech{stream}) whose elements are
numbers. The single-argument case @racket[(in-range end)] is
equivalent to @racket[(in-range 0 end 1)]. The first number in the
sequence is @racket[start], and each successive element is generated
by adding @racket[step] to the previous element. The sequence stops
before an element that would be greater or equal to @racket[end] if
@racket[step] is non-negative, or less or equal to @racket[end] if
@racket[step] is negative. @speed[in-range "number"]
@examples[#:label "Example: gaussian sum" #:eval sequence-evaluator
(for/sum ([x (in-range 10)]) x)]
@examples[#:label "Example: sum of even numbers" #:eval sequence-evaluator
(for/sum ([x (in-range 0 100 2)]) x)]
When given zero as @racket[step], @racket[in-range] returns an infinite
sequence. It may also return infinite sequences when @racket[step] is a very
small number, and either @racket[step] or the sequence elements are
floating-point numbers.
}
@defproc[(in-inclusive-range [start real?] [end real?] [step real? 1]) stream?]{
Similar to @racket[in-range], but the sequence stopping condition is changed so that
the last element is allowed to be equal to @racket[end]. @speed[in-inclusive-range "number"]
@examples[#:eval sequence-evaluator
(sequence->list (in-inclusive-range 7 11))
(sequence->list (in-inclusive-range 7 11 2))
(sequence->list (in-inclusive-range 7 10 2))
]
@history[#:added "8.0.0.13"]
}
@defproc[(in-naturals [start exact-nonnegative-integer? 0]) stream?]{
Returns an infinite sequence (that is also a @tech{stream}) of exact
integers starting with @racket[start], where each element is one
more than the preceding element. @speed[in-naturals "integer"]
@examples[#:eval sequence-evaluator
(for/list ([k (in-naturals)]
[x (in-range 10)])
(list k x))]
}
@defproc[(in-list [lst list?]) stream?]{
Returns a sequence (that is also a @tech{stream}) that is equivalent
to using @racket[lst] directly as a sequence.
@info-on-seq["pairs" "lists"]
@speed[in-list "list"]
@for-element-reachability["list"]
@examples[#:eval sequence-evaluator
(for/list ([x (in-list '(3 1 4))])
`(,x ,(* x x)))]
@history[#:changed "6.7.0.4" @elem{Improved element-reachability guarantee for lists in @racket[for].}]}
@defproc[(in-mlist [mlst mlist?]) sequence?]{
Returns a sequence equivalent to @racket[mlst]. Although the
expectation is that @racket[mlst] is @tech{mutable list}, @racket[in-mlist]
initially checks only whether @racket[mlst] is a @tech{mutable pair} or @racket[null],
since it could change during iteration.
@info-on-seq["mpairs" "mutable lists"]
@speed[in-mlist "mutable list"]
@examples[#:eval sequence-evaluator
(for/list ([x (in-mlist (mcons "RACKET" (mcons "LANG" '())))])
(string-length x))]
}
@defproc[(in-vector [vec vector?]
[start exact-nonnegative-integer? 0]
[stop (or/c exact-integer? #f) #f]
[step (and/c exact-integer? (not/c zero?)) 1])
sequence?]{
Returns a sequence equivalent to @racket[vec] when no optional
arguments are supplied.
@info-on-seq["vectors" "vectors"]
The optional arguments @racket[start], @racket[stop], and
@racket[step] are analogous to @racket[in-range], except that a
@racket[#f] value for @racket[stop] is equivalent to
@racket[(vector-length vec)]. That is, the first element in the
sequence is @racket[(vector-ref vec start)], and each successive
element is generated by adding @racket[step] to index of the
previous element. The sequence stops before an index that would be
greater or equal to @racket[end] if @racket[step] is non-negative,
or less or equal to @racket[end] if @racket[step] is negative.
If @racket[start] is not a valid index, then the
@exnraise[exn:fail:contract], except when @racket[start], @racket[stop], and
@racket[(vector-length vec)] are equal, in which case the result is an
empty sequence.
@examples[#:eval sequence-evaluator
(for ([x (in-vector (vector 1) 1)]) x)
(eval:error (for ([x (in-vector (vector 1) 2)]) x))
(for ([x (in-vector (vector) 0 0)]) x)
(for ([x (in-vector (vector 1) 1 1)]) x)]
If @racket[stop] is not in [-1, @racket[(vector-length vec)]],
then the @exnraise[exn:fail:contract].
If @racket[start] is less than
@racket[stop] and @racket[step] is negative, then the
@exnraise[exn:fail:contract]. Similarly, if @racket[start]
is more than @racket[stop] and @racket[step] is positive, then the
@exnraise[exn:fail:contract].
@speed[in-vector "vector"]
@examples[#:eval sequence-evaluator
(define (histogram vector-of-words)
(define a-hash (make-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"))]
}
@defproc[(in-string [str string?]
[start exact-nonnegative-integer? 0]
[stop (or/c exact-integer? #f) #f]
[step (and/c exact-integer? (not/c zero?)) 1])
sequence?]{
Returns a sequence equivalent to @racket[str] when no optional
arguments are supplied.
@info-on-seq["strings" "strings"]
The optional arguments @racket[start], @racket[stop], and
@racket[step] are as in @racket[in-vector].
@speed[in-string "string"]
@examples[#:eval sequence-evaluator
(define (line-count str)
(for/sum ([ch (in-string str)])
(if (char=? #\newline ch) 1 0)))
(line-count "this string\nhas\nthree \nnewlines")]
}
@defproc[(in-bytes [bstr bytes?]
[start exact-nonnegative-integer? 0]
[stop (or/c exact-integer? #f) #f]
[step (and/c exact-integer? (not/c zero?)) 1])
sequence?]{
Returns a sequence equivalent to @racket[bstr] when no optional
arguments are supplied.
@info-on-seq["bytestrings" "byte strings"]
The optional arguments @racket[start], @racket[stop], and
@racket[step] are as in @racket[in-vector].
@speed[in-bytes "byte string"]
@examples[#:eval sequence-evaluator
(define (has-eof? bs)
(for/or ([ch (in-bytes bs)])
(= ch 0)))
(has-eof? #"this byte string has an \0embedded zero byte")
(has-eof? #"this byte string does not")]
}
@defproc[(in-port [r (input-port? . -> . any/c) read]
[in input-port? (current-input-port)])
sequence?]{
Returns a sequence whose elements are produced by calling @racket[r]
on @racket[in] until it produces @racket[eof].}
@defproc[(in-input-port-bytes [in input-port?]) sequence?]{
Returns a sequence equivalent to @racket[(in-port read-byte in)].}
@defproc[(in-input-port-chars [in input-port?]) sequence?]{
Returns a sequence whose elements are read as characters from
@racket[in] (equivalent to @racket[(in-port read-char in)]).}
@defproc[(in-lines [in input-port? (current-input-port)]
[mode (or/c 'linefeed 'return 'return-linefeed 'any 'any-one) 'any])
sequence?]{
Returns a sequence equivalent to
@racket[(in-port (lambda (p) (read-line p mode)) in)]. Note that
the default mode is @racket['any], whereas the default mode of
@racket[read-line] is @racket['linefeed].}
@defproc[(in-bytes-lines [in input-port? (current-input-port)]
[mode (or/c 'linefeed 'return 'return-linefeed 'any 'any-one) 'any])
sequence?]{
Returns a sequence equivalent to
@racket[(in-port (lambda (p) (read-bytes-line p mode)) in)]. Note
that the default mode is @racket['any], whereas the default mode of
@racket[read-bytes-line] is @racket['linefeed].}
@defproc*[([(in-hash [hash hash?]) sequence?]
[(in-hash [hash hash?] [bad-index-v any/c]) sequence?])]{
Returns a sequence equivalent to @racket[hash], except when @racket[bad-index-v]
is supplied.
If @racket[bad-index-v] is supplied, then @racket[bad-index-v] is
returned as both the key and the value in the case that the
@racket[hash] is modified concurrently so that iteration does not have a
@tech{valid hash index}. Providing @racket[bad-index-v] is particularly
useful when iterating through a hash table with weakly held keys, since
entries can be removed asynchronously (i.e., after @racket[in-hash] has
committed to another iteration, but before it can access the entry for the
next iteration).
@examples[
(define table (hash 'a 1 'b 2))
(for ([(key value) (in-hash table)])
(printf "key: ~a value: ~a\n" key value))]
@info-on-seq["hashtables" "hash tables"]
@history[#:changed "7.0.0.10" @elem{Added the optional @racket[bad-index-v] argument.}]}
@defproc*[([(in-hash-keys [hash hash?]) sequence?]
[(in-hash-keys [hash hash?] [bad-index-v any/c]) sequence?])]{
Returns a sequence whose elements are the keys of @racket[hash], using
@racket[bad-index-v] in the same way as @racket[in-hash].
@examples[
(define table (hash 'a 1 'b 2))
(for ([key (in-hash-keys table)])
(printf "key: ~a\n" key))]
@history[#:changed "7.0.0.10" @elem{Added the optional @racket[bad-index-v] argument.}]}
@defproc*[([(in-hash-values [hash hash?]) sequence?]
[(in-hash-values [hash hash?] [bad-index-v any/c]) sequence?])]{
Returns a sequence whose elements are the values of @racket[hash], using
@racket[bad-index-v] in the same way as @racket[in-hash].
@examples[
(define table (hash 'a 1 'b 2))
(for ([value (in-hash-values table)])
(printf "value: ~a\n" value))]
@history[#:changed "7.0.0.10" @elem{Added the optional @racket[bad-index-v] argument.}]}
@defproc*[([(in-hash-pairs [hash hash?]) sequence?]
[(in-hash-pairs [hash hash?] [bad-index-v any/c]) sequence?])]{
Returns a sequence whose elements are pairs, each containing a key
and its value from @racket[hash] (as opposed to using @racket[hash]
directly as a sequence to get the key and value as separate values
for each element).
The @racket[bad-index-v] argument, if supplied, is used in the same
way as by @racket[in-hash]. When an invalid index is encountered,
the pair in the sequence with have @racket[bad-index-v] as both its
@racket[car] and @racket[cdr].
@examples[
(define table (hash 'a 1 'b 2))
(for ([key+value (in-hash-pairs table)])
(printf "key and value: ~a\n" key+value))]
@history[#:changed "7.0.0.10" @elem{Added the optional @racket[bad-index-v] argument.}]}
@deftogether[(
@defproc[(in-mutable-hash
[hash (and/c hash? (not/c immutable?) hash-strong?)])
sequence?]
@defproc[#:link-target? #f
(in-mutable-hash
[hash (and/c hash? (not/c immutable?) hash-strong?)] [bad-index-v any/c])
sequence?]
@defproc[(in-mutable-hash-keys
[hash (and/c hash? (not/c immutable?) hash-strong?)])
sequence?]
@defproc[#:link-target? #f
(in-mutable-hash-keys
[hash (and/c hash? (not/c immutable?) hash-strong?)] [bad-index-v any/c])
sequence?]
@defproc[(in-mutable-hash-values
[hash (and/c hash? (not/c immutable?) hash-strong?)])
sequence?]
@defproc[#:link-target? #f
(in-mutable-hash-values
[hash (and/c hash? (not/c immutable?) hash-strong?)] [bad-index-v any/c])
sequence?]
@defproc[(in-mutable-hash-pairs
[hash (and/c hash? (not/c immutable?) hash-strong?)])
sequence?]
@defproc[#:link-target? #f
(in-mutable-hash-pairs
[hash (and/c hash? (not/c immutable?) hash-strong?)] [bad-index-v any/c])
sequence?]
@defproc[(in-immutable-hash
[hash (and/c hash? immutable?)])
sequence?]
@defproc[#:link-target? #f
(in-immutable-hash
[hash (and/c hash? immutable?)] [bad-index-v any/c])
sequence?]
@defproc[(in-immutable-hash-keys
[hash (and/c hash? immutable?)])
sequence?]
@defproc[#:link-target? #f
(in-immutable-hash-keys
[hash (and/c hash? immutable?)] [bad-index-v any/c])
sequence?]
@defproc[(in-immutable-hash-values
[hash (and/c hash? immutable?)])
sequence?]
@defproc[#:link-target? #f
(in-immutable-hash-values
[hash (and/c hash? immutable?)] [bad-index-v any/c])
sequence?]
@defproc[(in-immutable-hash-pairs
[hash (and/c hash? immutable?)])
sequence?]
@defproc[#:link-target? #f
(in-immutable-hash-pairs
[hash (and/c hash? immutable?)] [bad-index-v any/c])
sequence?]
@defproc[(in-weak-hash
[hash (and/c hash? hash-weak?)])
sequence?]
@defproc[#:link-target? #f
(in-weak-hash
[hash (and/c hash? hash-weak?)] [bad-index-v any/c])
sequence?]
@defproc[(in-weak-hash-keys
[hash (and/c hash? hash-weak?)])
sequence?]
@defproc[#:link-target? #f
(in-weak-hash-keys
[hash (and/c hash? hash-weak?)] [bad-index-v any/c])
sequence?]
@defproc[(in-weak-hash-values
[hash (and/c hash? hash-weak?)])
sequence?]
@defproc[#:link-target? #f
(in-weak-hash-keys
[hash (and/c hash? hash-weak?)] [bad-index-v any/c])
sequence?]
@defproc[(in-weak-hash-pairs
[hash (and/c hash? hash-weak?)])
sequence?]
@defproc[#:link-target? #f
(in-weak-hash-pairs
[hash (and/c hash? hash-weak?)] [bad-index-v any/c])
sequence?]
@defproc[(in-ephemeron-hash
[hash (and/c hash? hash-ephemeron?)])
sequence?]
@defproc[#:link-target? #f
(in-ephemeron-hash
[hash (and/c hash? hash-ephemeron?)] [bad-index-v any/c])
sequence?]
@defproc[(in-ephemeron-hash-keys
[hash (and/c hash? hash-ephemeron?)])
sequence?]
@defproc[#:link-target? #f
(in-ephemeron-hash-keys
[hash (and/c hash? hash-ephemeron?)] [bad-index-v any/c])
sequence?]
@defproc[(in-ephemeron-hash-values
[hash (and/c hash? hash-ephemeron?)])
sequence?]
@defproc[#:link-target? #f
(in-ephemeron-hash-keys
[hash (and/c hash? hash-ephemeron?)] [bad-index-v any/c])
sequence?]
@defproc[(in-ephemeron-hash-pairs
[hash (and/c hash? hash-ephemeron?)])
sequence?]
@defproc[#:link-target? #f
(in-ephemeron-hash-pairs
[hash (and/c hash? hash-ephemeron?)] [bad-index-v any/c])
sequence?]
)]{
Sequence constructors for specific kinds of hash tables.
These may perform better than the analogous @racket[in-hash]
forms.
@history[#:added "6.4.0.6"
#:changed "7.0.0.10" @elem{Added the optional @racket[bad-index-v] argument.}
#:changed "8.0.0.10" @elem{Added @schemeidfont{ephemeron} variants.}]
}
@defproc[(in-directory [dir (or/c #f path-string?) #f]
[use-dir? ((and/c path? complete-path?) . -> . any/c)
(lambda (dir-path) #t)])
sequence?]{
Returns a sequence that produces all of the paths for files,
directories, and links within @racket[dir], except for the
contents of any directory for which @racket[use-dir?] returns
@racket[#f]. If @racket[dir] is not
@racket[#f], then every produced path starts with @racket[dir] as
its prefix. If @racket[dir] is @racket[#f], then paths in and
relative to the current directory are produced.
An @racket[in-directory] sequence traverses nested subdirectories
recursively (filtered by @racket[use-dir?]).
To generate a sequence that includes only the immediate
content of a directory, use the result of @racket[directory-list] as
a sequence.
The immediate content of each directory is reported as sorted by
@racket[path<?], and the content of a subdirectory is reported
before subsequent paths within the directory.
@examples[
(eval:alts (current-directory (path-only (collection-file-path "main.rkt" "info")))
(void))
(eval:alts (for/list ([f (in-directory)])
f)
(map string->path '("compiled"
"compiled/main_rkt.dep"
"compiled/main_rkt.zo"
"main.rkt")))
(eval:alts (for/list ([f (in-directory "compiled")])
f)
(map string->path '("compiled/main_rkt.dep"
"compiled/main_rkt.zo")))
(eval:alts (for/list ([f (in-directory #f (lambda (p)
(not (regexp-match? #rx"compiled" p))))])
f)
(map string->path '("compiled" "main.rkt")))
]
@history[#:changed "6.0.0.1" @elem{Added @racket[use-dir?] argument.}
#:changed "6.6.0.4" @elem{Added guarantee of sorted results.}]}
@defproc*[([(in-producer [producer procedure?])
sequence?]
[(in-producer [producer procedure?] [stop any/c] [arg any/c] ...)
sequence?])]{
Returns a sequence that contains values from sequential calls to
@racket[producer], which would usually use some state to do its work.
If a @racket[stop] value is not given, the sequence goes on
infinitely, and therefore it is common to use it with a finite sequence
or using @racket[#:break] etc. If a @racket[stop] value is given, it
is used to identify a value that marks the end of the sequence (and
the @racket[stop] value is not included in the sequence);
@racket[stop] can be a predicate that is applied to the results of
@racket[producer], or it can be a value that is tested against the
result of with @racket[eq?]. (The @racket[stop] argument must be a
predicate if the stop value is itself a function or if
@racket[producer] returns multiple values.)
If additional @racket[arg]s are specified, they are passed to every
call to @racket[producer].
@examples[
(define (counter)
(define n 0)
(lambda ([d 1]) (set! n (+ d n)) n))
(for/list ([x (in-producer (counter))] [y (in-range 4)]) x)
(for/list ([x (in-producer (counter))] #:break (= x 5)) x)
(for/list ([x (in-producer (counter) 5)]) x)
(for/list ([x (in-producer (counter) 5 1/2)]) x)
(for/list ([x (in-producer read eof (open-input-string "1 2 3"))]) x)]
}
@defproc[(in-value [v any/c]) sequence?]{
Returns a sequence that produces a single value: @racket[v].
This form is mostly useful for @racket[let]-like bindings in forms
such as @racket[for*/list]---but a @racket[#:do] clause form, added
more recently, covers many of the same uses.
}
@defproc[(in-indexed [seq sequence?]) sequence?]{
Returns a sequence where each element has two values: the value
produced by @racket[seq], and a non-negative exact integer starting
with @racket[0]. The elements of @racket[seq] must be
single-valued.
@(examples
#:eval sequence-evaluator
(for ([(ch i) (in-indexed "hello")])
(printf "The char at position ~a is: ~a\n" i ch)))
}
@defproc[(in-sequences [seq sequence?] ...) sequence?]{
Returns a sequence that is made of all input sequences, one after
the other. Each @racket[seq] is @tech{initiate}d only after the
preceding @racket[seq] is exhausted. If a single @racket[seq] is
provided, then @racket[seq] is returned; otherwise, the elements of
each @racket[seq] must all have the same number of values.}
@defproc[(in-cycle [seq sequence?] ...) sequence?]{
Similar to @racket[in-sequences], but the sequences are repeated in
an infinite cycle, where each @racket[seq] is @tech{initiate}d
afresh in each iteration. Beware that if no @racket[seq]s are
provided or if all @racket[seq]s become empty, then the sequence
produced by @racket[in-cycle] never returns when an element is
demanded---or even when the sequence is @tech{initiate}d, if all
@racket[seq]s are initially empty.}
@defproc[(in-parallel [seq sequence?] ...) sequence?]{
Returns a sequence where each element has as many values as the
number of supplied @racket[seq]s; the values, in order, are the
values of each @racket[seq]. The elements of each @racket[seq] must
be single-valued.}
@defproc[(in-values-sequence [seq sequence?]) sequence?]{
Returns a sequence that is like @racket[seq], but it combines
multiple values for each element from @racket[seq] as a list of
elements.}
@defproc[(in-values*-sequence [seq sequence?]) sequence?]{
Returns a sequence that is like @racket[seq], but when an element of
@racket[seq] has multiple values or a single list value, then the
values are combined in a list. In other words,
@racket[in-values*-sequence] is like @racket[in-values-sequence],
except that non-list, single-valued elements are not wrapped in a
list.
}
@defproc[(stop-before [seq sequence?] [pred (any/c . -> . any)])
sequence?]{
Returns a sequence that contains the elements of @racket[seq] (which
must be single-valued), but only until the last element for which
applying @racket[pred] to the element produces @racket[#t], after
which the sequence ends.
}
@defproc[(stop-after [seq sequence?] [pred (any/c . -> . any)])
sequence?]{
Returns a sequence that contains the elements of @racket[seq] (which
must be single-valued), but only until the element (inclusive) for
which applying @racket[pred] to the element produces @racket[#t],
after which the sequence ends.
}
@defproc[(make-do-sequence
[thunk (or/c (-> (values (any/c . -> . any)
(any/c . -> . any/c)
any/c
(or/c (any/c . -> . any/c) #f)
(or/c (any/c ... . -> . any/c) #f)
(or/c (any/c any/c ... . -> . any/c) #f)))
(-> (values (any/c . -> . any)
(or/c (any/c . -> . any/c) #f)
(any/c . -> . any/c)
any/c
(or/c (any/c . -> . any/c) #f)
(or/c (any/c ... . -> . any/c) #f)
(or/c (any/c any/c ... . -> . any/c) #f))))])
sequence?]{
Returns a sequence whose elements are generated according to @racket[thunk].
The sequence is @tech{initiate}d when @racket[thunk] is called.
The initiated sequence is defined in
terms of a @defterm{position}, which is initialized to @racket[_init-pos],
and the @defterm{element}, which may consist of multiple values.
The @racket[thunk] procedure must return either six or seven values.
However, use @racket[initiate-sequence] to return these multiple values,
as opposed to listing the values directly.
If @racket[thunk] returns six values:
@itemize[
@item{The first result is a @racket[_pos->element] procedure that
takes the current position and returns the value(s) for the
current element.}
@item{The second result is a @racket[_next-pos] procedure that
takes the current position and returns the next position.}
@item{The third result is a @racket[_init-pos] value, which is the initial position.}
@item{The fourth result is a @racket[_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, @racket[_continue-with-pos?] can be @racket[#f] to
indicate that the sequence should always include the current
value(s). This function is checked on each position before
@racket[_pos->element] is used.}
@item{The fifth result is a @racket[_continue-with-val?] function
that is like @racket[_continue-with-pos?], but it takes the current element
value(s) as arguments instead of the current position. Alternatively, @racket[_continue-with-val?]
can be @racket[#f] to indicate that the sequence
should always include the value(s) at the current position.}
@item{The sixth result is a @racket[_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, @racket[_continue-after-pos+val?] can be @racket[#f] to indicate
that the sequence can always continue after the current
value(s).}]
If @racket[thunk] returns seven values, the first result is still
the @racket[_pos->element] procedure.
However, the second result is now an @racket[_early-next-pos]
procedure that is described further below. Alternatively,
@racket[_early-next-pos] can be @racket[#f], which is equivalent
to the identity function.
Other results' positions are shifted by one,
so the third result is now @racket[_next-pos], and
the fourth result is now @racket[_init-pos], etc.
The @racket[_early-next-pos] procedure takes the current position and returns an updated position.
This updated position is used for @racket[_next-pos] and
@racket[_continue-after-pos+val?], but not with
@racket[_continue-with-pos?] (which uses the original current
position). The intent of @racket[_early-next-pos] is to support a
sequence where the position must be incremented to avoid keeping a
value reachable while a loop processes the sequence value, so
@racket[_early-next-pos] is applied just after
@racket[_pos->element]. The @racket[_continue-after-pos+val?] function
needs to be @racket[#f] to avoid retaining values to supply to that function.
Each of the procedures listed above is called only once per
position. Among the procedures @racket[_continue-with-pos?], @racket[_continue-with-val?], and @racket[_continue-after-pos+val?], as soon as one of the
procedures returns @racket[#f], the sequence ends, and none are
called again. Typically, one of the functions determines the end
condition, and @racket[#f] is used in place of the other two
functions.
@history[#:changed "6.7.0.4" @elem{Added support for the optional second result.}]}
@defthing[prop:sequence struct-type-property?]{
Associates a procedure to a structure type that takes an instance of
the structure and returns a sequence. If @racket[v] is an instance
of a structure type with this property, then @racket[(sequence? v)]
produces @racket[#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)]
Using @racket[make-do-sequence]:
@let-syntax[([car (make-element-id-transformer
(lambda (id) #'@racketidfont{car}))])
@examples[
(require racket/sequence)
(struct train (car next)
#:property prop:sequence
(lambda (t)
(make-do-sequence
(lambda ()
(initiate-sequence
#:pos->element train-car
#:next-pos train-next
#:init-pos t
#:continue-with-pos? (lambda (t) t))))))
(for/list ([c (train 'engine
(train 'boxcar
(train 'caboose
#f)))])
c)]]}
@; ----------------------------------------------------------------------
@subsection{Sequence Conversion}
@defproc[(sequence->stream [seq sequence?]) stream?]{
Converts a sequence to a @tech{stream}, which supports the
@racket[stream-first] and @racket[stream-rest] operations. Creation
of the stream eagerly @tech{initiates} the sequence, but the stream
lazily draws elements from the sequence, caching each element so
that @racket[stream-first] produces the same result each time is
applied to a stream.
If extracting an element from @racket[seq] involves a side-effect,
then the effect is performed each time that either
@racket[stream-first] or @racket[stream-rest] is first used to
access or skip an element.
Note that a @elemref["sequence-state"]{sequence itself can have
state}, so multiple calls to @racket[sequence->stream] on the same
@racket[seq] are not necessarily independent.
@examples[
#:eval sequence-evaluator
(define inport (open-input-bytes (bytes 1 2 3 4 5)))
(define strm (sequence->stream inport))
(stream-first strm)
(stream-first (stream-rest strm))
(stream-first strm)
(define strm2 (sequence->stream inport))
(stream-first strm2)
(stream-first (stream-rest strm2))
]}
@defproc[(sequence-generate [seq sequence?])
(values (-> boolean?) (-> any))]{
@tech{Initiates} a sequence and returns two thunks to extract
elements from the sequence. The first returns @racket[#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 @exnraise[exn:fail:contract].
Note that a @elemref["sequence-state"]{sequence itself can have
state}, so multiple calls to @racket[sequence-generate] on the same
@racket[seq] are not necessarily independent.
@examples[
#:eval sequence-evaluator
(define inport (open-input-bytes (bytes 1 2 3 4 5)))
(define-values (more? get) (sequence-generate inport))
(more?)
(get)
(get)
(define-values (more2? get2) (sequence-generate inport))
(list (get2) (get2) (get2))
(more2?)
]}
@defproc[(sequence-generate* [seq sequence?])
(values (or/c list? #f)
(-> (values (or/c list? #f) procedure?)))]{
Like @racket[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 @racket[#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 @racket[sequence-generate*], but
for the second element of the sequence, and so on. If the thunk is
called when the element result is @racket[#f] (indicating no further
values in the sequence), the @exnraise[exn:fail:contract].}
@; ----------------------------------------------------------------------
@subsection[#:tag "more-sequences"]{Additional Sequence Operations}
@note-lib[racket/sequence]
@defthing[empty-sequence sequence?]{
A sequence with no elements.}
@defproc[(sequence->list [s sequence?]) list?]{
Returns a list whose elements are the elements of @racket[s], each
of which must be a single value. If @racket[s] is infinite, this
function does not terminate.}
@defproc[(sequence-length [s sequence?])
exact-nonnegative-integer?]{
Returns the number of elements of @racket[s] by extracting and
discarding all of them. If @racket[s] is infinite, this function
does not terminate.}
@defproc[(sequence-ref [s sequence?] [i exact-nonnegative-integer?])
any]{
Returns the @racket[i]th element of @racket[s] (which may be
multiple values).}
@defproc[(sequence-tail [s sequence?] [i exact-nonnegative-integer?])
sequence?]{
Returns a sequence equivalent to @racket[s], except that the first
@racket[i] elements are omitted.
In case @tech[#:key "initiate"]{initiating} @racket[s] involves a
side effect, the sequence @racket[s] is not @tech{initiate}d until
the resulting sequence is @tech{initiate}d, at which point the first
@racket[i] elements are extracted from the sequence.
}
@defproc[(sequence-append [s sequence?] ...)
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 @racket[s]s are @tech{streams}, the result is also a
@tech{stream}.
}
@defproc[(sequence-map [f procedure?]
[s sequence?])
sequence?]{
Returns a sequence that contains @racket[f] applied to each element
of @racket[s]. The new sequence is constructed lazily.
If @racket[s] is a @tech{stream}, then the result is also a
@tech{stream}.
}
@defproc[(sequence-andmap [f (-> any/c ... boolean?)]
[s sequence?])
boolean?]{
Returns @racket[#t] if @racket[f] returns a true result on every