551 lines
17 KiB
Racket
551 lines
17 KiB
Racket
#lang scribble/doc
|
|
@require["mz.ss"]
|
|
@require[scribble/scheme]
|
|
@require[(for-syntax scheme/base)]
|
|
|
|
@define-syntax[(defc_r stx)
|
|
(syntax-case stx ()
|
|
[(_ x ...)
|
|
(let ([xs (map syntax-e (syntax->list #'(x ...)))])
|
|
(let ([name (string->symbol
|
|
(string-append
|
|
"c"
|
|
(apply string-append (map symbol->string xs))
|
|
"r"))]
|
|
[contract (let loop ([l (reverse xs)])
|
|
(cond
|
|
[(null? (cdr l)) 'pair?]
|
|
[(eq? (car l) 'a) `(cons/c ,(loop (cdr l)) any/c)]
|
|
[(eq? (car l) 'd) `(cons/c any/c ,(loop (cdr l)))]))]
|
|
[equiv (let loop ([l xs])
|
|
(cond
|
|
[(null? l) 'p]
|
|
[(eq? (car l) 'a) `(car ,(loop (cdr l)))]
|
|
[(eq? (car l) 'd) `(cdr ,(loop (cdr l)))]))])
|
|
(with-syntax ([name name]
|
|
[contract (let loop ([c contract][pos 0])
|
|
(if (pair? c)
|
|
(let* ([a (loop (car c) (add1 pos))]
|
|
[b (loop (cdr c) (+ 1 pos (syntax-span a)))]
|
|
[span (+ 1 (syntax-span a) (syntax-span b))])
|
|
(datum->syntax #'here
|
|
(cons a b)
|
|
(list (syntax-source stx)
|
|
1
|
|
pos
|
|
(add1 pos)
|
|
span)))
|
|
(datum->syntax #'here c
|
|
(list (syntax-source stx) 1 pos (add1 pos) 1))))]
|
|
[equiv equiv])
|
|
#'(defproc (name [v contract]) any/c
|
|
"Returns " (to-element 'equiv)))))])]
|
|
|
|
@title[#:tag "pairs"]{Pairs and Lists}
|
|
|
|
A @deftech{pair} combines exactly two values. The first value is
|
|
accessed with the @scheme[car] procedure, and the second value is
|
|
accessed with the @scheme[cdr] procedure. Pairs are not mutable (but
|
|
see @secref["mpairs"]).
|
|
|
|
A @deftech{list} is recursively defined: it is either the constant
|
|
@scheme[null], or it is a pair whose second value is a list.
|
|
|
|
A list can be used as a single-valued sequence (see
|
|
@secref["sequences"]). The elements of the list serve as elements
|
|
of the sequence. See also @scheme[in-list].
|
|
|
|
Cyclic data structures can be created using only immutable pairs via
|
|
@scheme[read] or @scheme[make-reader-graph]. If starting with a pair
|
|
and using some number of @scheme[cdr]s returns to the starting pair,
|
|
then the pair is not a list.
|
|
|
|
@; ----------------------------------------
|
|
@section{Pair Constructors and Selectors}
|
|
|
|
@defproc[(pair? [v any/c]) boolean?]{Returns @scheme[#t] if @scheme[v] is
|
|
a pair, @scheme[#f] otherwise.}
|
|
|
|
@defproc[(null? [v any/c]) boolean?]{Returns @scheme[#t] if @scheme[v] is
|
|
the empty list, @scheme[#f] otherwise.}
|
|
|
|
@defproc[(cons [a any/c] [d any/c]) pair?]{Returns a pair whose first
|
|
element is @scheme[a] and second element is @scheme[d].}
|
|
|
|
@defproc[(car [p pair?]) any/c]{Returns the first element of the
|
|
pair @scheme[p].}
|
|
|
|
@defproc[(cdr [p pair?]) any/c]{Returns the second element of the
|
|
pair @scheme[p].}
|
|
|
|
@defthing[null null?]{The empty list.}
|
|
|
|
|
|
@defproc[(list? [v any/c]) boolean?]{Returns @scheme[#t] if @scheme[v]
|
|
is a list: either the empty list, or a pair whose second element is a
|
|
list. This procedure takes amortized constant time.}
|
|
|
|
@defproc[(list [v any/c] ...) list?]{Returns a newly allocated list
|
|
containing the @scheme[v]s as its elements.}
|
|
|
|
@defproc[(list* [v any/c] ... [tail any/c]) any/c]{
|
|
|
|
Like @scheme[list], but the last argument is used as the tail of
|
|
the result, instead of the final element. The result is a list
|
|
only if the last argument is a list.}
|
|
|
|
@defproc[(build-list [n exact-nonnegative-integer?]
|
|
[proc (exact-nonnegative-integer? . -> . any)])
|
|
list?]{
|
|
|
|
Creates a list of @scheme[n] elements by applying @scheme[proc] to the
|
|
integers from @scheme[0] to @scheme[(sub1 n)] in order. If
|
|
@scheme[_lst] is the resulting list, then @scheme[(list-ref _lst _i)]
|
|
is the value produced by @scheme[(proc _i)].
|
|
|
|
@examples[
|
|
(build-list 10 values)
|
|
(build-list 5 (lambda (x) (* x x)))
|
|
]}
|
|
|
|
@; ----------------------------------------
|
|
@section{List Operations}
|
|
|
|
@defproc[(length [lst list?])
|
|
nonnegative-exact-integer?]{
|
|
|
|
Returns the number of elements in @scheme[lst].}
|
|
|
|
|
|
@defproc[(list-ref [lst list?][pos nonnegative-exact-integer?])
|
|
any/c]{
|
|
|
|
Returns the element of @scheme[lst] at position @scheme[pos], where
|
|
the list's first element is position @scheme[0]. If the list has
|
|
@scheme[pos] or fewer elements, then the
|
|
@exnraise[exn:fail:contract].}
|
|
|
|
|
|
@defproc[(list-tail [lst list?][pos nonnegative-exact-integer?])
|
|
any/c]{
|
|
|
|
Returns the list after the first @scheme[pos] elements of
|
|
@scheme[lst]. If the list has @scheme[pos] or fewer elements, then the
|
|
@exnraise[exn:fail:contract].}
|
|
|
|
|
|
@defproc*[([(append [lst list?] ...) list?]
|
|
[(append [lst list?] ... [v any/c]) any/c])]{
|
|
|
|
When given all list arguments, the result is a lists that contains all
|
|
of the elements of the given lists in order. The last argument is used
|
|
directly in the tail of the result.
|
|
|
|
The last argument need not be a list, in which case the result is an
|
|
``improper list'' ...}
|
|
|
|
@defproc[(reverse [lst list?]) list?]{
|
|
|
|
Returns a list that has the same elements as @scheme[lst], but in
|
|
reverse order.}
|
|
|
|
|
|
@; ----------------------------------------
|
|
@section{List Iteration}
|
|
|
|
@defproc[(map [proc procedure?] [lst list?] ...+)
|
|
list?]{
|
|
|
|
Applies @scheme[proc] to the elements of the @scheme[lst]s from the
|
|
first elements to the last, returning @scheme[#f] as soon as any
|
|
application returns @scheme[#f]. The @scheme[proc] argument must
|
|
accept the same number of arguments as the number of supplied
|
|
@scheme[lst]s, and all @scheme[lst]s must have the same number of
|
|
elements. The result is a list containing each result of
|
|
@scheme[proc].}
|
|
|
|
|
|
@defproc[(andmap [proc procedure?] [lst list?] ...+)
|
|
any]{
|
|
|
|
Similar to @scheme[map], except that
|
|
|
|
@itemize{
|
|
|
|
@item{the result is @scheme[#f] if any application of @scheme[proc] produces
|
|
@scheme[#f], in which case @scheme[proc] is not applied to later
|
|
elements of the @scheme[lst]s; or}
|
|
|
|
@item{the result is that of @scheme[proc] applied to the last elements
|
|
of the @scheme[lsts]s; more specifically, the application of
|
|
@scheme[proc] to the last elements in the @scheme[lst]s is in tail
|
|
position with respect to the @scheme[andmap] call.}
|
|
|
|
}
|
|
|
|
If the @scheme[lst]s are empty, then @scheme[#t] is returned.}
|
|
|
|
@examples[
|
|
(andmap positive? '(1 2 3))
|
|
(andmap positive? '(1 2 a))
|
|
(andmap positive? '(1 -2 a))
|
|
(andmap + '(1 2 3) '(4 5 6))
|
|
]
|
|
|
|
|
|
@defproc[(ormap [proc procedure?] [lst list?] ...+)
|
|
any]{
|
|
|
|
Similar to @scheme[map], except that
|
|
|
|
@itemize{
|
|
|
|
@item{the result is @scheme[#f] if every application of @scheme[proc] produces
|
|
@scheme[#f]; or}
|
|
|
|
@item{the result of the first applciation of @scheme[proc] to produces a
|
|
value other than @scheme[#f], in which case @scheme[proc] is not
|
|
applied to later elements of the @scheme[lst]s; more specifically,
|
|
the application of @scheme[proc] to the last elements in the
|
|
@scheme[lst]s is in tail position with respect to the
|
|
@scheme[andmap] call.}
|
|
|
|
}
|
|
|
|
If the @scheme[lst]s are empty, then @scheme[#f] is returned.}
|
|
|
|
@examples[
|
|
(ormap eq? '(a b c) '(a b c))
|
|
(ormap positive? '(1 2 a))
|
|
(ormap + '(1 2 3) '(4 5 6))
|
|
]
|
|
|
|
|
|
@defproc[(for-each [proc procedure?] [lst list?] ...+)
|
|
void?]{
|
|
|
|
Similar to @scheme[map], but @scheme[proc] is called only for its
|
|
effect, and its result (which can be any number of values) is
|
|
ignored.}
|
|
|
|
|
|
@defproc[(foldl [proc procedure?] [init any/c] [lst list?] ...+)
|
|
list?]{
|
|
|
|
Like @scheme[map], @scheme[foldl] applies a procedure to the
|
|
elements of one or more lists. Whereas @scheme[map] combines the return
|
|
values into a list, @scheme[foldl] combines the return values in an
|
|
arbitrary way that is determined by @scheme[proc].
|
|
|
|
If @scheme[foldl] is called with @math{n} lists, then @scheme[proc]
|
|
must take @math{n+1} arguments. The extra argument is the combined
|
|
return values so far. The @scheme[proc] is initially invoked with the
|
|
first item of each list, and the final argument is @scheme[init]. In
|
|
subsequent invocations of @scheme[proc], the last argument is the
|
|
return value from the previous invocation of @scheme[proc]. The input
|
|
@scheme[lst]s are traversed from left to right, and the result of the
|
|
whole @scheme[foldl] application is the result of the last
|
|
application of @scheme[proc]. If the @scheme[lst]s are empty, the
|
|
result is @scheme[init].
|
|
|
|
Unlike @scheme[foldr], @scheme[foldl] processes the @scheme[lst]s in
|
|
constant space (plus the space for each call to @scheme[proc]).
|
|
|
|
@examples[
|
|
(foldl cons '() '(1 2 3 4))
|
|
(foldl + 0 '(1 2 3 4))
|
|
]}
|
|
|
|
@defproc[(foldr [proc procedure?] [init any/c] [lst list?] ...+)
|
|
list?]{
|
|
|
|
Like @scheme[foldl], but the lists are traversed from right to left.
|
|
Unlike @scheme[foldl], @scheme[foldr] processes the @scheme[lst]s in
|
|
space proportional to the length of @scheme[lst]s (plus the space for
|
|
each call to @scheme[proc]).
|
|
|
|
@examples[
|
|
(foldr cons '() '(1 2 3 4))
|
|
(foldr (lambda (v l) (cons (add1 v) l)) '() '(1 2 3 4))
|
|
]}
|
|
|
|
@; ----------------------------------------
|
|
@section{List Filtering}
|
|
|
|
@defproc[(filter [proc procedure?] [lst list?])
|
|
list?]{
|
|
|
|
Returns a list with the elements of @scheme[lst] for which
|
|
@scheme[proc] produces a true value. The predicate @scheme[proc]
|
|
is applied to each element from first to last.}
|
|
|
|
|
|
@defproc[(remove [v any/c] [lst list?] [proc procedure? equal?])
|
|
list?]{
|
|
|
|
Returns a list that is like @scheme[lst], omitting the first element
|
|
of @scheme[lst] that is equal to @scheme[v] using the comparison
|
|
procedure @scheme[proc] (which must accept two arguments).}
|
|
|
|
|
|
@defproc[(remq [v any/c] [lst list?])
|
|
list?]{
|
|
|
|
Returns @scheme[(remove v lst eq?)].}
|
|
|
|
|
|
@defproc[(remv [v any/c] [lst list?])
|
|
list?]{
|
|
|
|
Returns @scheme[(remove v lst eqv?)].}
|
|
|
|
|
|
@defproc[(remove* [v-lst list?] [lst list?] [proc procedure? equal?])
|
|
list?]{
|
|
|
|
Like @scheme[remove], but removes from @scheme[lst] every instance of
|
|
every element of @scheme[v-lst].}
|
|
|
|
|
|
@defproc[(remq* [v any/c] [lst list?])
|
|
list?]{
|
|
|
|
Returns @scheme[(remove* v lst eq?)].}
|
|
|
|
|
|
@defproc[(remv* [v any/c] [lst list?])
|
|
list?]{
|
|
|
|
Returns @scheme[(remove* v lst eqv?)].}
|
|
|
|
|
|
@defproc[(sort [lst list?] [less-than? (any/c any/c . -> . any/c)])
|
|
list?]{
|
|
|
|
Returns a list sorted according to the @scheme[less-than?] procedure,
|
|
which takes two elements of @scheme[lst] and returns a true value if
|
|
the first is less than (i.e., should be sorted earlier) than the
|
|
second.
|
|
|
|
The sort is stable: if two elements of @scheme[lst] are ``equal''
|
|
(i.e., @scheme[proc] does not return a true value when given the pair
|
|
in either order), then the elements preserve their relative order
|
|
from @scheme[lst] in the output list.}
|
|
|
|
@; ----------------------------------------
|
|
@section{List Searching}
|
|
|
|
@defproc[(member [v any/c] [lst list?])
|
|
(or/c list? false/c)]{
|
|
|
|
Locates the first element of @scheme[lst] that is @scheme[equal?] to
|
|
@scheme[v]. If such an element exists, the tail of @scheme[lst]
|
|
starting with that element is returned. Otherwise, the result is
|
|
@scheme[#f].}
|
|
|
|
|
|
@defproc[(memv [v any/c] [lst list?])
|
|
(or/c list? false/c)]{
|
|
|
|
Like @scheme[member], but finds an element using @scheme[eqv?].}
|
|
|
|
|
|
@defproc[(memq [v any/c] [lst list?])
|
|
(or/c list? false/c)]{
|
|
|
|
Like @scheme[member], but finds an element using @scheme[eq?].}
|
|
|
|
|
|
@defproc[(memf [proc procedure?] [lst list?])
|
|
(or/c list? false/c)]{
|
|
|
|
Like @scheme[member], but finds an element using the predicate
|
|
@scheme[proc]; an element is found when @scheme[proc] applied to the
|
|
element returns a true value.}
|
|
|
|
|
|
@defproc[(findf [proc procedure?] [lst list?]) any/c]{
|
|
|
|
Like @scheme[memf], but returns the element or @scheme[#f]
|
|
instead of a tail of @scheme[lst] or @scheme[#f].}
|
|
|
|
|
|
@defproc[(assoc [v any/c] [lst (listof pair?)])
|
|
(or/c pair? false/c)]{
|
|
|
|
Locates the first element of @scheme[lst] whose @scheme[car] is
|
|
@scheme[equal?] to @scheme[v]. If such an element exists, the pair
|
|
(i.e., an element of @scheme[lst]) is returned. Otherwise, the result
|
|
is @scheme[#f].}
|
|
|
|
|
|
@defproc[(assv [v any/c] [lst (listof pair?)])
|
|
(or/c pair? false/c)]{
|
|
|
|
Like @scheme[assoc], but finds an element using @scheme[eqv?].}
|
|
|
|
|
|
@defproc[(assq [v any/c] [lst (listof pair?)])
|
|
(or/c pair? false/c)]{
|
|
|
|
Like @scheme[assoc], but finds an element using @scheme[eq?].}
|
|
|
|
|
|
@defproc[(assf [proc procedure?] [lst list?])
|
|
(or/c list? false/c)]{
|
|
|
|
Like @scheme[assoc], but finds an element using the predicate
|
|
@scheme[proc]; an element is found when @scheme[proc] applied to the
|
|
@scheme[car] of an @scheme[lst] element returns a true value.}
|
|
|
|
|
|
|
|
@; ----------------------------------------
|
|
@section{Pair Accessor Shorthands}
|
|
|
|
@defc_r[a a]
|
|
@defc_r[a d]
|
|
@defc_r[d a]
|
|
@defc_r[d d]
|
|
@defc_r[a a a]
|
|
@defc_r[a a d]
|
|
@defc_r[a d a]
|
|
@defc_r[a d d]
|
|
@defc_r[d a a]
|
|
@defc_r[d a d]
|
|
@defc_r[d d a]
|
|
@defc_r[d d d]
|
|
@defc_r[a a a a]
|
|
@defc_r[a a a d]
|
|
@defc_r[a a d a]
|
|
@defc_r[a a d d]
|
|
@defc_r[a d a a]
|
|
@defc_r[a d a d]
|
|
@defc_r[a d d a]
|
|
@defc_r[a d d d]
|
|
@defc_r[d a a a]
|
|
@defc_r[d a a d]
|
|
@defc_r[d a d a]
|
|
@defc_r[d a d d]
|
|
@defc_r[d d a a]
|
|
@defc_r[d d a d]
|
|
@defc_r[d d d a]
|
|
@defc_r[d d d d]
|
|
|
|
@; ----------------------------------------
|
|
@section{List Synonyms}
|
|
|
|
@note-lib[scheme/list]
|
|
|
|
@defthing[empty null?]{The empty list.}
|
|
|
|
@defproc[(cons? [v any/c]) boolean?]{The same as @scheme[(pair? v)].}
|
|
|
|
@defproc[(empty? [v any/c]) boolean?]{The same as @scheme[(null? v)].}
|
|
|
|
@defproc[(first [lst list?]) any/c]{The same as @scheme[(car lst)], but only for lists (that are not empty).}
|
|
|
|
@defproc[(rest [lst list?]) list?]{The same as @scheme[(cdr lst)], but only for lists (that are not empty).}
|
|
|
|
@defproc[(second [lst list?]) any]{Returns the second element of the list.}
|
|
|
|
@defproc[(third [lst list?]) any]{Returns the third element of the list.}
|
|
|
|
@defproc[(fourth [lst list?]) any]{Returns the fourth element of the list.}
|
|
|
|
@defproc[(fifth [lst list?]) any]{Returns the fifth element of the list.}
|
|
|
|
@defproc[(sixth [lst list?]) any]{Returns the sixth element of the list.}
|
|
|
|
@defproc[(seventh [lst list?]) any]{Returns the seventh element of the list.}
|
|
|
|
@defproc[(eighth [lst list?]) any]{Returns the eighth element of the list.}
|
|
|
|
@defproc[(ninth [lst list?]) any]{Returns the ninth element of the list.}
|
|
|
|
@defproc[(tenth [lst list?]) any]{Returns the tenth element of the list.}
|
|
|
|
@defproc[(last [lst list?]) any]{Returns the last element of the list.}
|
|
|
|
@; ----------------------------------------
|
|
@section{Immutable Cyclic Data}
|
|
|
|
@defproc[(make-reader-graph [v any/c]) any/c]{
|
|
|
|
Returns a value like @scheme[v], with placeholders created by
|
|
@scheme[make-placeholder] replaced with the values that they contain,
|
|
and with placeholders created by @scheme[make-hash-table-placeholder]
|
|
with an immutable hash table. No part of @scheme[v] is mutated;
|
|
instead, parts of @scheme[v] are copied as necessary to construct
|
|
the resulting graph, where at most one copy is created for any given
|
|
value.
|
|
|
|
Since the copied vales can be immutable, and since the copy is also
|
|
immutable, @scheme[make-reader-graph] can cycles involving only
|
|
immutable pairs, vectors, boxes, and hash tables.
|
|
|
|
Only the following kinds of values are copied and traversed to detect
|
|
placeholders:
|
|
|
|
@itemize{
|
|
|
|
@item{pairs}
|
|
|
|
@item{immutable pairs (as created by @scheme[mcons])}
|
|
|
|
@item{vectors, both mutable and immutable}
|
|
|
|
@item{boxes, both mutable and immutable}
|
|
|
|
@item{hash tables, both mutable and immutable}
|
|
|
|
@item{placeholders created by @scheme[make-placeholder] and
|
|
@scheme[make-hash-table-placeholder]}
|
|
|
|
}
|
|
|
|
Due to these restrictions, @scheme[make-reader-graph] creates exactly
|
|
the same sort of cyclic values as @scheme[read].
|
|
|
|
@examples[
|
|
(let* ([ph (make-placeholder #f)]
|
|
[x (cons 1 ph)])
|
|
(placeholder-set! ph x)
|
|
(make-reader-graph x))
|
|
]}
|
|
|
|
@defproc[(placeholder? [v any/c]) boolean?]{
|
|
|
|
Returns @scheme[#t] if @scheme[v] is a placeholder created by
|
|
@scheme[make-placeholder], @scheme[#f] otherwise.}
|
|
|
|
|
|
@defproc[(make-placeholder [v any/c]) placeholder?]{
|
|
|
|
Returns a placeholder for use with @scheme[placeholder-set!] and
|
|
@scheme[make-reader-graph]. The @scheme[v] argument supplies the
|
|
initial value for the placeholder.}
|
|
|
|
@defproc[(placeholder-set! [ph placeholder?] [datum any/c]) void?]{
|
|
|
|
Changes the value of @scheme[ph] to @scheme[v].}
|
|
|
|
@defproc[(placeholder-get [ph placeholder?]) any/c]{
|
|
|
|
Returns the value of @scheme[ph].}
|
|
|
|
|
|
@defproc[(hash-table-placeholder? [v any/c]) boolean?]{
|
|
|
|
Returns @scheme[#t] if @scheme[v] is a placeholder created by
|
|
@scheme[make-hash-table-placeholder], @scheme[#f] otherwise.}
|
|
|
|
|
|
@defproc[(make-hash-table-placeholder [assocs (listof pair?)]
|
|
[flag (one-of/c 'equal)]
|
|
...)
|
|
hash-table-placeholder?]{
|
|
|
|
Like @scheme[make-immutable-hash-table], but produces a table
|
|
placeholder for use with @scheme[make-reader-graph].}
|