(list-tabulate 4 values) => (0 1 2 3)
[procedure] (list-copy flist) -> flist
Copies the spine of the argument.
[procedure] (circular-list elt[1] elt[2] ...) -> list
Constructs a circular list of the elements.
(circular-list 'z 'q) => (z q z q z q ...)
[procedure] (iota count [start step]) -> list
Returns a list containing the elements
(start start+step ... start+(count-1)*step)
The start and step parameters default to 0 and 1, respectively.
This procedure takes its name from the APL primitive.
(iota 5) => (0 1 2 3 4)
(iota 5 0 -0.1) => (0 -0.1 -0.2 -0.3 -0.4)
Predicates
Note: the predicates proper-list?, circular-list?, and dotted-list?
partition the entire universe of Scheme values.
[procedure] (proper-list? x) -> boolean
Returns true iff x is a proper list -- a finite, nil-terminated
list.
More carefully: The empty list is a proper list. A pair whose cdr
is a proper list is also a proper list:
<proper-list> ::= () (Empty proper list)
| (cons <x> <proper-list>) (Proper-list pair)
Note that this definition rules out circular lists. This function
is required to detect this case and return false.
Nil-terminated lists are called "proper" lists by R5RS and Common
Lisp. The opposite of proper is improper.
R5RS binds this function to the variable list?.
(not (proper-list? x)) = (or (dotted-list? x) (circular-list? x))
[procedure] (circular-list? x) -> boolean
True if x is a circular list. A circular list is a value such that
for every n >= 0, cdr^n(x) is a pair.
Terminology: The opposite of circular is finite.
(not (circular-list? x)) = (or (proper-list? x) (dotted-list? x))
[procedure] (dotted-list? x) -> boolean
True if x is a finite, non-nil-terminated list. That is, there
exists an n >= 0 such that cdr^n(x) is neither a pair nor (). This
includes non-pair, non-() values (e.g. symbols, numbers), which are
considered to be dotted lists of length 0.
(not (dotted-list? x)) = (or (proper-list? x) (circular-list? x))
[procedure] (not-pair? x) -> boolean
(lambda (x) (not (pair? x)))
Provided as a procedure as it can be useful as the termination
condition for list-processing procedures that wish to handle all
finite lists, both proper and dotted.
[procedure] (list= elt= list[1] ...) -> boolean
Determines list equality, given an element-equality procedure.
Proper list A equals proper list B if they are of the same length,
and their corresponding elements are equal, as determined by elt=.
If the element-comparison procedure's first argument is from list
[i], then its second argument is from list[i+1], i.e. it is always
called as (elt= a b) for a an element of list A, and b an element
of list B.
In the n-ary case, every list[i] is compared to list[i+1] (as
opposed, for example, to comparing list[1] to every list[i], for i>
1). If there are no list arguments at all, list= simply returns
true.
It is an error to apply list= to anything except proper lists.
While implementations may choose to extend it to circular lists,
note that it cannot reasonably be extended to dotted lists, as it
provides no way to specify an equality procedure for comparing the
list terminators.
Note that the dynamic order in which the elt= procedure is applied
to pairs of elements is not specified. For example, if list= is
applied to three lists, A, B, and C, it may first completely
compare A to B, then compare B to C, or it may compare the first
elements of A and B, then the first elements of B and C, then the
second elements of A and B, and so forth.
The equality procedure must be consistent with eq?. That is, it
must be the case that
(eq? x y) => (elt= x y).
Note that this implies that two lists which are eq? are always list=,
as well; implementations may exploit this fact to "short-cut"
the element-by-element comparisons.
(list= eq?) => #t ; Trivial cases
(list= eq? '(a)) => #t
Selectors
[procedure] (first pair) -> object
[procedure] (second pair) -> object
[procedure] (third pair) -> object
[procedure] (fourth pair) -> object
[procedure] (fifth pair) -> object
[procedure] (sixth pair) -> object
[procedure] (seventh pair) -> object
[procedure] (eighth pair) -> object
[procedure] (ninth pair) -> object
[procedure] (tenth pair) -> object
Synonyms for car, cadr, caddr, ...
(third '(a b c d e)) => c
[procedure] (car+cdr pair) -> [x y]
The fundamental pair deconstructor:
(lambda (p) (values (car p) (cdr p)))
This can, of course, be implemented more efficiently by a compiler.
[procedure] (take x i) -> list
[procedure] (drop x i) -> object
take returns the first i elements of list x.
drop returns all but the first i elements of list x.
(take '(a b c d e) 2) => (a b)
(drop '(a b c d e) 2) => (c d e)
x may be any value -- a proper, circular, or dotted list:
(take '(1 2 3 . d) 2) => (1 2)
(drop '(1 2 3 . d) 2) => (3 . d)
(take '(1 2 3 . d) 3) => (1 2 3)
(drop '(1 2 3 . d) 3) => d
For a legal i, take and drop partition the list in a manner which
can be inverted with append:
(append (take x i) (drop x i)) = x
drop is exactly equivalent to performing i cdr operations on x; the
returned value shares a common tail with x. If the argument is a
list of non-zero length, take is guaranteed to return a
freshly-allocated list, even in the case where the entire list is
taken, e.g. (take lis (length lis)).
[procedure] (take-right flist i) -> object
[procedure] (drop-right flist i) -> list
take-right returns the last i elements of flist.
drop-right returns all but the last i elements of flist.
(take-right '(a b c d e) 2) => (d e)
(drop-right '(a b c d e) 2) => (a b c)
The returned list may share a common tail with the argument list.
flist may be any finite list, either proper or dotted:
(take-right '(1 2 3 . d) 2) => (2 3 . d)
(drop-right '(1 2 3 . d) 2) => (1)
(take-right '(1 2 3 . d) 0) => d
(drop-right '(1 2 3 . d) 0) => (1 2 3)
For a legal i, take-right and drop-right partition the list in a
manner which can be inverted with append:
(append (take flist i) (drop flist i)) = flist
take-right's return value is guaranteed to share a common tail with
flist. If the argument is a list of non-zero length, drop-right is
guaranteed to return a freshly-allocated list, even in the case
where nothing is dropped, e.g. (drop-right lis 0).
[procedure] (take! x i) -> list
[procedure] (drop-right! flist i) -> list
take! and drop-right! are "linear-update" variants of take and
drop-right: the procedure is allowed, but not required, to alter
the argument list to produce the result.
If x is circular, take! may return a shorter-than-expected list:
(take! (circular-list 1 3 5) 8) => (1 3)
(take! (circular-list 1 3 5) 8) => (1 3 5 1 3 5 1 3)
[procedure] (split-at x i) -> [list object]
[procedure] (split-at! x i) -> [list object]
split-at splits the list x at index i, returning a list of the
first i elements, and the remaining tail. It is equivalent to
(values (take x i) (drop x i))
split-at! is the linear-update variant. It is allowed, but not
required, to alter the argument list to produce the result.
(split-at '(a b c d e f g h) 3) =>
(a b c)
(d e f g h)
[procedure] (last pair) -> object
[procedure] (last-pair pair) -> pair
last returns the last element of the non-empty, finite list pair.
last-pair returns the last pair in the non-empty, finite list pair.
(last '(a b c)) => c
(last-pair '(a b c)) => (c)
Miscellaneous
[procedure] (length list) -> integer
[procedure] (length+ clist) -> integer or #f
Both length and length+ return the length of the argument. It is an
error to pass a value to length which is not a proper list (finite
and nil-terminated). In particular, this means an implementation
may diverge or signal an error when length is applied to a circular
list.
length+, on the other hand, returns #F when applied to a circular
list.
The length of a proper list is a non-negative integer n such that
cdr applied n times to the list produces the empty list.
[procedure] (append! list[1] ...) -> list
append! is the "linear-update" variant of append -- it is allowed,
but not required, to alter cons cells in the argument lists to
construct the result list. The last argument is never altered; the
result list shares structure with this parameter.
[procedure] (concatenate list-of-lists) -> value
[procedure] (concatenate! list-of-lists) -> value
These functions append the elements of their argument together.
That is, concatenate returns
(apply append list-of-lists)
or, equivalently,
(reduce-right append '() list-of-lists)
concatenate! is the linear-update variant, defined in terms of
append! instead of append.
Note that some Scheme implementations do not support passing more
than a certain number (e.g., 64) of arguments to an n-ary
procedure. In these implementations, the (apply append ...) idiom
would fail when applied to long lists, but concatenate would
continue to function properly.
As with append and append!, the last element of the input list may
be any value at all.
[procedure] (reverse! list) -> list
reverse! is the linear-update variant of reverse. It is permitted,
but not required, to alter the argument's cons cells to produce the
reversed list.
[procedure] (append-reverse rev-head tail) -> list
[procedure] (append-reverse! rev-head tail) -> list
append-reverse returns (append (reverse rev-head) tail). It is
provided because it is a common operation -- a common
list-processing style calls for this exact operation to transfer
values accumulated in reverse order onto the front of another list,
and because the implementation is significantly more efficient than
the simple composition it replaces. (But note that this pattern of
iterative computation followed by a reverse can frequently be
rewritten as a recursion, dispensing with the reverse and
append-reverse steps, and shifting temporary, intermediate storage
from the heap to the stack, which is typically a win for reasons of
cache locality and eager storage reclamation.)
append-reverse! is just the linear-update variant -- it is allowed,
but not required, to alter rev-head's cons cells to construct the
result.
[procedure] (zip clist[1] clist[2] ...) -> list
(lambda lists (apply map list lists))
If zip is passed n lists, it returns a list as long as the shortest
of these lists, each element of which is an n-element list
comprised of the corresponding elements from the parameter lists.
(zip '(one two three)
'(1 2 3)
'(odd even odd even odd even odd even))
=> ((one 1 odd) (two 2 even) (three 3 odd))
(zip '(1 2 3)) => ((1) (2) (3))
At least one of the argument lists must be finite:
(zip '(3 1 4 1) (circular-list #f #t))
=> ((3 #f) (1 #t) (4 #f) (1 #t))
[procedure] (unzip1 list) -> list
[procedure] (unzip2 list) -> [list list]
[procedure] (unzip3 list) -> [list list list]
[procedure] (unzip4 list) -> [list list list list]
[procedure] (unzip5 list) -> [list list list list list]
unzip1 takes a list of lists, where every list must contain at
least one element, and returns a list containing the initial
element of each such list. That is, it returns (map car lists).
unzip2 takes a list of lists, where every list must contain at
least two elements, and returns two values: a list of the first
elements, and a list of the second elements. unzip3 does the same
for the first three elements of the lists, and so forth.
(unzip2 '((1 one) (2 two) (3 three))) =>
(1 2 3)
(one two three)
[procedure] (count pred clist[1] clist[2]) -> integer
pred is a procedure taking as many arguments as there are lists and
returning a single value. It is applied element-wise to the
elements of the lists, and a count is tallied of the number of
elements that produce a true value. This count is returned. count
is "iterative" in that it is guaranteed to apply pred to the list
elements in a left-to-right order. The counting stops when the
shortest list expires.
(count even? '(3 1 4 1 5 9 2 5 6)) => 3
(count < '(1 2 4 8) '(2 4 6 8 10 12 14 16)) => 3
At least one of the argument lists must be finite:
(count < '(3 1 4 1) (circular-list 1 10)) => 2
Fold, unfold & map
[procedure] (fold kons knil clist[1] clist[2] ...) -> value
The fundamental list iterator.
First, consider the single list-parameter case. If
clist[1] = (e[1] e[2] ... e[n]), then this procedure returns
(kons e[n] ... (kons e[2] (kons e[1] knil)) ... )
That is, it obeys the (tail) recursion
(fold kons knil lis) = (fold kons (kons (car lis) knil) (cdr lis))
(fold kons knil '()) = knil
Examples:
(fold + 0 lis) ; Add up the elements of LIS.
(fold cons '() lis) ; Reverse LIS.
(fold cons tail rev-head) ; See APPEND-REVERSE.
;; How many symbols in LIS?
(fold (lambda (x count) (if (symbol? x) (+ count 1) count))
0
lis)
;; Length of the longest string in LIS:
(fold (lambda (s max-len) (max max-len (string-length s)))
0
lis)
If n list arguments are provided, then the kons function must take
n+1 parameters: one element from each list, and the "seed" or fold
state, which is initially knil. The fold operation terminates when
the shortest list runs out of values:
(fold cons* '() '(a b c) '(1 2 3 4 5)) => (c 3 b 2 a 1)
At least one of the list arguments must be finite.
[procedure] (fold-right kons knil clist[1] clist[2] ...) -> value
The fundamental list recursion operator.
First, consider the single list-parameter case. If
clist[1] = (e[1] e[2] ... e[n]), then this procedure returns
(kons e[1] (kons e[2] ... (kons e[n] knil)))
That is, it obeys the recursion
(fold-right kons knil lis) = (kons (car lis) (fold-right kons knil (cdr lis)))
(fold-right kons knil '()) = knil
Examples:
(fold-right cons '() lis) ; Copy LIS.
;; Filter the even numbers out of LIS.
(fold-right (lambda (x l) (if (even? x) (cons x l) l)) '() lis))
If n list arguments are provided, then the kons function must take
n+1 parameters: one element from each list, and the "seed" or fold
state, which is initially knil. The fold operation terminates when
the shortest list runs out of values:
(fold-right cons* '() '(a b c) '(1 2 3 4 5)) => (a 1 b 2 c 3)
At least one of the list arguments must be finite.
[procedure] (pair-fold kons knil clist[1] clist[2] ...) -> value
Analogous to fold, but kons is applied to successive sublists of
the lists, rather than successive elements -- that is, kons is
applied to the pairs making up the lists, giving this (tail)
recursion:
(pair-fold kons knil lis) = (let ((tail (cdr lis)))
(pair-fold kons (kons lis knil) tail))
(pair-fold kons knil '()) = knil
For finite lists, the kons function may reliably apply set-cdr! to
the pairs it is given without altering the sequence of execution.
Example:
;;; Destructively reverse a list.
(pair-fold (lambda (pair tail) (set-cdr! pair tail) pair) '() lis))
At least one of the list arguments must be finite.
[procedure] (pair-fold-right kons knil clist[1] clist[2] ...) -> value
Holds the same relationship with fold-right that pair-fold holds
with fold. Obeys the recursion
(pair-fold-right kons knil lis) =
(kons lis (pair-fold-right kons knil (cdr lis)))
(pair-fold-right kons knil '()) = knil
Example:
(pair-fold-right cons '() '(a b c)) => ((a b c) (b c) (c))
At least one of the list arguments must be finite.
[procedure] (reduce f ridentity list) -> value
reduce is a variant of fold.
ridentity should be a "right identity" of the procedure f -- that
is, for any value x acceptable to f,
(f x ridentity) = x
reduce has the following definition:
If list = (), return ridentity;
Otherwise, return (fold f (car list) (cdr list)).
...in other words, we compute (fold f ridentity list).
Note that ridentity is used only in the empty-list case. You
typically use reduce when applying f is expensive and you'd like to
avoid the extra application incurred when fold applies f to the
head of list and the identity value, redundantly producing the same
value passed in to f. For example, if f involves searching a file
directory or performing a database query, this can be significant.
In general, however, fold is useful in many contexts where reduce
is not (consider the examples given in the fold definition -- only
one of the five folds uses a function with a right identity. The
other four may not be performed with reduce).
Note: MIT Scheme and Haskell flip F's arg order for their reduce
and fold functions.
;; Take the max of a list of non-negative integers.
(reduce max 0 nums) ; i.e., (apply max 0 nums)
[procedure] (reduce-right f ridentity list) -> value
reduce-right is the fold-right variant of reduce. It obeys the
following definition:
(reduce-right f ridentity '()) = ridentity
(reduce-right f ridentity '(e[1])) = (f e[1] ridentity) = e[1]
(reduce-right f ridentity '(e[1] e[2] ...)) =
(f e[1] (reduce f ridentity (e[2] ...)))
...in other words, we compute (fold-right f ridentity list).
;; Append a bunch of lists together.
;; I.e., (apply append list-of-lists)
(reduce-right append '() list-of-lists)
[procedure] (unfold p f g seed [tail-gen]) -> list
unfold is best described by its basic recursion:
(unfold p f g seed) =
(if (p seed) (tail-gen seed)
(cons (f seed)
(unfold p f g (g seed))))
- p
- Determines when to stop unfolding.
- f
- Maps each seed value to the corresponding list element.
- g
- Maps each seed value to next seed value.
- seed
- The "state" value for the unfold.
- tail-gen
- Creates the tail of the list; defaults to (lambda (x) '())
In other words, we use g to generate a sequence of seed values
seed, g(seed), g^2(seed), g^3(seed), ...
These seed values are mapped to list elements by f, producing the
elements of the result list in a left-to-right order. P says when
to stop.
unfold is the fundamental recursive list constructor, just as
fold-right is the fundamental recursive list consumer. While unfold
may seem a bit abstract to novice functional programmers, it can be
used in a number of ways:
;; List of squares: 1^2 ... 10^2
(unfold (lambda (x) (> x 10))
(lambda (x) (* x x))
(lambda (x) (+ x 1))
1)
(unfold null-list? car cdr lis) ; Copy a proper list.
;; Read current input port into a list of values.
(unfold eof-object? values (lambda (x) (read)) (read))
;; Copy a possibly non-proper list:
(unfold not-pair? car cdr lis
values)
;; Append HEAD onto TAIL:
(unfold null-list? car cdr head
(lambda (x) tail))
Interested functional programmers may enjoy noting that fold-right
and unfold are in some sense inverses. That is, given operations
knull?, kar, kdr, kons, and knil satisfying
(kons (kar x) (kdr x)) = x and (knull? knil) = #t
then
(fold-right kons knil (unfold knull? kar kdr x)) = x
and
(unfold knull? kar kdr (fold-right kons knil x)) = x
This combinator sometimes is called an "anamorphism;" when an
explicit tail-gen procedure is supplied, it is called an
"apomorphism."
[procedure] (unfold-right p f g seed [tail]) -> list
unfold-right constructs a list with the following loop:
(let lp ((seed seed) (lis tail))
(if (p seed) lis
(lp (g seed)
(cons (f seed) lis))))
- p
- Determines when to stop unfolding.
- f
- Maps each seed value to the corresponding list element.
- g
- Maps each seed value to next seed value.
- seed
- The "state" value for the unfold.
- tail
- list terminator; defaults to '().
In other words, we use g to generate a sequence of seed values
seed, g(seed), g^2(seed), g^3(seed), ...
These seed values are mapped to list elements by f, producing the
elements of the result list in a right-to-left order. P says when
to stop.
unfold-right is the fundamental iterative list constructor, just as
fold is the fundamental iterative list consumer. While unfold-right
may seem a bit abstract to novice functional programmers, it can be
used in a number of ways:
;; List of squares: 1^2 ... 10^2
(unfold-right zero?
(lambda (x) (* x x))
(lambda (x) (- x 1))
10)
;; Reverse a proper list.
(unfold-right null-list? car cdr lis)
;; Read current input port into a list of values.
(unfold-right eof-object? values (lambda (x) (read)) (read))
;; (append-reverse rev-head tail)
(unfold-right null-list? car cdr rev-head tail)
Interested functional programmers may enjoy noting that fold and
unfold-right are in some sense inverses. That is, given operations
knull?, kar, kdr, kons, and knil satisfying
(kons (kar x) (kdr x)) = x and (knull? knil) = #t
then
(fold kons knil (unfold-right knull? kar kdr x)) = x
and
(unfold-right knull? kar kdr (fold kons knil x)) = x
This combinator presumably has some pretentious mathematical name;
interested readers are invited to communicate it to the author.
[procedure] (map proc clist[1] clist[2] ...) -> list
This procedure is extended from its R5RS specification to allow the
arguments to be of unequal length; it terminates when the shortest
list runs out.
At least one of the argument lists must be finite:
(map + '(3 1 4 1) (circular-list 1 0)) => (4 1 5 1)
[procedure] (for-each proc clist[1] clist[2] ...) -> unspecified
This procedure is extended from its R5RS specification to allow the
arguments to be of unequal length; it terminates when the shortest
list runs out.
At least one of the argument lists must be finite.
[procedure] (append-map f clist[1] clist[2] ...) -> value
[procedure] (append-map! f clist[1] clist[2] ...) -> value
Equivalent to
(apply append (map f clist[1] clist[2] ...))
and
(apply append! (map f clist[1] clist[2] ...))
Map f over the elements of the lists, just as in the map function.
However, the results of the applications are appended together to
make the final result. append-map uses append to append the results
together; append-map! uses append!.
The dynamic order in which the various applications of f are made
is not specified.
Example:
(append-map! (lambda (x) (list x (- x))) '(1 3 8))
=> (1 -1 3 -3 8 -8)
At least one of the list arguments must be finite.
[procedure] (map! f list[1] clist[2] ...) -> list
Linear-update variant of map -- map! is allowed, but not required,
to alter the cons cells of list[1] to construct the result list.
The dynamic order in which the various applications of f are made
is not specified. In the n-ary case, clist[2], clist[3], ... must
have at least as many elements as list[1].
[procedure] (map-in-order f clist[1] clist[2] ...) -> list
A variant of the map procedure that guarantees to apply f across
the elements of the list[i] arguments in a left-to-right order.
This is useful for mapping procedures that both have side effects
and return useful values.
At least one of the list arguments must be finite.
[procedure] (pair-for-each f clist[1] clist[2] ...) -> unspecific
Like for-each, but f is applied to successive sublists of the
argument lists. That is, f is applied to the cons cells of the
lists, rather than the lists' elements. These applications occur in
left-to-right order.
The f procedure may reliably apply set-cdr! to the pairs it is
given without altering the sequence of execution.
(pair-for-each (lambda (pair) (display pair) (newline)) '(a b c)) ==>
(a b c)
(b c)
(c)
At least one of the list arguments must be finite.
[procedure] (filter-map f clist[1] clist[2] ...) -> list
Like map, but only true values are saved.
(filter-map (lambda (x) (and (number? x) (* x x))) '(a 1 b 3 c 7))
=> (1 9 49)
The dynamic order in which the various applications of f are made
is not specified.
At least one of the list arguments must be finite.
Filtering & partitioning
[procedure] (filter pred list) -> list
Return all the elements of list that satisfy predicate pred. The
list is not disordered -- elements that appear in the result list
occur in the same order as they occur in the argument list. The
returned list may share a common tail with the argument list. The
dynamic order in which the various applications of pred are made is
not specified.
(filter even? '(0 7 8 8 43 -4)) => (0 8 8 -4)
[procedure] (partition pred list) -> [list list]
Partitions the elements of list with predicate pred, and returns
two values: the list of in-elements and the list of out-elements.
The list is not disordered -- elements occur in the result lists in
the same order as they occur in the argument list. The dynamic
order in which the various applications of pred are made is not
specified. One of the returned lists may share a common tail with
the argument list.
(partition symbol? '(one 2 3 four five 6)) =>
(one four five)
(2 3 6)
[procedure] (remove pred list) -> list
Returns list without the elements that satisfy predicate pred:
(lambda (pred list) (filter (lambda (x) (not (pred x))) list))
The list is not disordered -- elements that appear in the result
list occur in the same order as they occur in the argument list.
The returned list may share a common tail with the argument list.
The dynamic order in which the various applications of pred are
made is not specified.
(remove even? '(0 7 8 8 43 -4)) => (7 43)
[procedure] (filter! pred list) -> list
[procedure] (partition! pred list) -> [list list]
[procedure] (remove! pred list) -> list
Linear-update variants of filter, partition and remove. These
procedures are allowed, but not required, to alter the cons cells
in the argument list to construct the result lists.
Searching
[procedure] (find pred clist) -> value
Return the first element of clist that satisfies predicate pred;
false if no element does.
(find even? '(3 1 4 1 5 9)) => 4
Note that find has an ambiguity in its lookup semantics -- if find
returns #f, you cannot tell (in general) if it found a #f element
that satisfied pred, or if it did not find any element at all. In
many situations, this ambiguity cannot arise -- either the list
being searched is known not to contain any #f elements, or the list
is guaranteed to have an element satisfying pred. However, in cases
where this ambiguity can arise, you should use find-tail instead of
find -- find-tail has no such ambiguity:
(cond ((find-tail pred lis) => (lambda (pair) ...)) ; Handle (CAR PAIR)
(else ...)) ; Search failed.
[procedure] (find-tail pred clist) -> pair or false
Return the first pair of clist whose car satisfies pred. If no pair
does, return false.
find-tail can be viewed as a general-predicate variant of the
member function.
Examples:
(find-tail even? '(3 1 37 -8 -5 0 0)) => (-8 -5 0 0)
(find-tail even? '(3 1 37 -5)) => #f
;; MEMBER X LIS:
(find-tail (lambda (elt) (equal? x elt)) lis)
In the circular-list case, this procedure "rotates" the list.
Find-tail is essentially drop-while, where the sense of the
predicate is inverted: Find-tail searches until it finds an element
satisfying the predicate; drop-while searches until it finds an
element that doesn't satisfy the predicate.
[procedure] (take-while pred clist) -> list
[procedure] (take-while! pred clist) -> list
Returns the longest initial prefix of clist whose elements all
satisfy the predicate pred.
Take-while! is the linear-update variant. It is allowed, but not
required, to alter the argument list to produce the result.
(take-while even? '(2 18 3 10 22 9)) => (2 18)
[procedure] (drop-while pred clist) -> list
Drops the longest initial prefix of clist whose elements all
satisfy the predicate pred, and returns the rest of the list.
(drop-while even? '(2 18 3 10 22 9)) => (3 10 22 9)
The circular-list case may be viewed as "rotating" the list.
[procedure] (span pred clist) -> [list clist]
[procedure] (span! pred list ) -> [list list]
[procedure] (break pred clist) -> [list clist]
[procedure] (break! pred list ) -> [list list]
Span splits the list into the longest initial prefix whose elements
all satisfy pred, and the remaining tail. Break inverts the sense
of the predicate: the tail commences with the first element of the
input list that satisfies the predicate.
In other words: span finds the intial span of elements satisfying
pred, and break breaks the list at the first element satisfying
pred.
Span is equivalent to
(values (take-while pred clist)
(drop-while pred clist))
Span! and break! are the linear-update variants. They are allowed,
but not required, to alter the argument list to produce the result.
(span even? '(2 18 3 10 22 9)) =>
(2 18)
(3 10 22 9)
(break even? '(3 1 4 1 5 9)) =>
(3 1)
(4 1 5 9)
[procedure] (any pred clist[1] clist[2] ...) -> value
Applies the predicate across the lists, returning true if the
predicate returns true on any application.
If there are n list arguments clist[1] ... clist[n], then pred must
be a procedure taking n arguments and returning a boolean result.
any applies pred to the first elements of the clist[i] parameters.
If this application returns a true value, any immediately returns
that value. Otherwise, it iterates, applying pred to the second
elements of the clist[i] parameters, then the third, and so forth.
The iteration stops when a true value is produced or one of the
lists runs out of values; in the latter case, any returns #f. The
application of pred to the last element of the lists is a tail
call.
Note the difference between find and any -- find returns the
element that satisfied the predicate; any returns the true value
that the predicate produced.
Like every, any's name does not end with a question mark -- this is
to indicate that it does not return a simple boolean (#t or #f),
but a general value.
(any integer? '(a 3 b 2.7)) => #t
(any integer? '(a 3.1 b 2.7)) => #f
(any < '(3 1 4 1 5)
'(2 7 1 8 2)) => #t
[procedure] (every pred clist[1] clist[2] ...) -> value
Applies the predicate across the lists, returning true if the
predicate returns true on every application.
If there are n list arguments clist[1] ... clist[n], then pred must
be a procedure taking n arguments and returning a boolean result.
every applies pred to the first elements of the clist[i]
parameters. If this application returns false, every immediately
returns false. Otherwise, it iterates, applying pred to the second
elements of the clist[i] parameters, then the third, and so forth.
The iteration stops when a false value is produced or one of the
lists runs out of values. In the latter case, every returns the
true value produced by its final application of pred. The
application of pred to the last element of the lists is a tail
call.
If one of the clist[i] has no elements, every simply returns #t.
Like any, every's name does not end with a question mark -- this is
to indicate that it does not return a simple boolean (#t or #f),
but a general value.
[procedure] (list-index pred clist[1] clist[2] ...) -> integer or false
Return the index of the leftmost element that satisfies pred.
If there are n list arguments clist[1] ... clist[n], then pred must
be a function taking n arguments and returning a boolean result.
list-index applies pred to the first elements of the clist[i]
parameters. If this application returns true, list-index
immediately returns zero. Otherwise, it iterates, applying pred to
the second elements of the clist[i] parameters, then the third, and
so forth. When it finds a tuple of list elements that cause pred to
return true, it stops and returns the zero-based index of that
position in the lists.
The iteration stops when one of the lists runs out of values; in
this case, list-index returns #f.
(list-index even? '(3 1 4 1 5 9)) => 2
(list-index < '(3 1 4 1 5 9 2 5 6) '(2 7 1 8 2)) => 1
(list-index = '(3 1 4 1 5 9 2 5 6) '(2 7 1 8 2)) => #f
[procedure] (member x list [=]) -> list
member is extended from its R5RS definition to allow the client to
pass in an optional equality procedure = used to compare keys.
The comparison procedure is used to compare the elements e[i] of
list to the key x in this way:
(= x e[i]) ; list is (E1 ... En)
That is, the first argument is always x, and the second argument is
one of the list elements. Thus one can reliably find the first
element of list that is greater than five with
(member 5 list <)
Note that fully general list searching may be performed with the
find-tail and find procedures, e.g.
(find-tail even? list) ; Find the first elt with an even key.
Deletion
[procedure] (delete x list [=]) -> list
[procedure] (delete! x list [=]) -> list
delete uses the comparison procedure =, which defaults to equal?,
to find all elements of list that are equal to x, and deletes them
from list. The dynamic order in which the various applications of =
are made is not specified.
The list is not disordered -- elements that appear in the result
list occur in the same order as they occur in the argument list.
The result may share a common tail with the argument list.
Note that fully general element deletion can be performed with the
remove and remove! procedures, e.g.:
;; Delete all the even elements from LIS:
(remove even? lis)
The comparison procedure is used in this way: (= x e[i]). That is,
x is always the first argument, and a list element is always the
second argument. The comparison procedure will be used to compare
each element of list exactly once; the order in which it is applied
to the various e[i] is not specified. Thus, one can reliably remove
all the numbers greater than five from a list with
(delete 5 list <)
delete! is the linear-update variant of delete. It is allowed, but
not required, to alter the cons cells in its argument list to
construct the result.
[procedure] (delete-duplicates list [=]) -> list
[procedure] (delete-duplicates! list [=]) -> list
delete-duplicates removes duplicate elements from the list
argument. If there are multiple equal elements in the argument
list, the result list only contains the first or leftmost of these
elements in the result. The order of these surviving elements is
the same as in the original list -- delete-duplicates does not
disorder the list (hence it is useful for "cleaning up" association
lists).
The = parameter is used to compare the elements of the list; it
defaults to equal?. If x comes before y in list, then the
comparison is performed (= x y). The comparison procedure will be
used to compare each pair of elements in list no more than once;
the order in which it is applied to the various pairs is not
specified.
Implementations of delete-duplicates are allowed to share common
tails between argument and result lists -- for example, if the list
argument contains only unique elements, it may simply return
exactly this list.
Be aware that, in general, delete-duplicates runs in time O(n^2)
for n-element lists. Uniquifying long lists can be accomplished in
O(n lg n) time by sorting the list to bring equal elements
together, then using a linear-time algorithm to remove equal
elements. Alternatively, one can use algorithms based on
element-marking, with linear-time results.
delete-duplicates! is the linear-update variant of
delete-duplicates; it is allowed, but not required, to alter the
cons cells in its argument list to construct the result.
(delete-duplicates '(a b a c a b c z)) => (a b c z)
;; Clean up an alist:
(delete-duplicates '((a . 3) (b . 7) (a . 9) (c . 1))
(lambda (x y) (eq? (car x) (car y))))
=> ((a . 3) (b . 7) (c . 1))
Association lists
An "association list" (or "alist") is a list of pairs. The car of each
pair contains a key value, and the cdr contains the associated data
value. They can be used to construct simple look-up tables in Scheme.
Note that association lists are probably inappropriate for
performance-critical use on large data; in these cases, hash tables or
some other alternative should be employed.
[procedure] (assoc key alist [=]) -> pair or #f
assoc is extended from its R5RS definition to allow the client to
pass in an optional equality procedure = used to compare keys.
The comparison procedure is used to compare the elements e[i] of
list to the key parameter in this way:
(= key (car e[i])) ; list is (E1 ... En)
That is, the first argument is always key, and the second argument
is one of the list elements. Thus one can reliably find the first
entry of alist whose key is greater than five with
(assoc 5 alist <)
Note that fully general alist searching may be performed with the
find-tail and find procedures, e.g.
;; Look up the first association in alist with an even key:
(find (lambda (a) (even? (car a))) alist)
[procedure] (alist-cons key datum alist) -> alist
(lambda (key datum alist) (cons (cons key datum) alist))
Cons a new alist entry mapping key -> datum onto alist.
[procedure] (alist-copy alist) -> alist
Make a fresh copy of alist. This means copying each pair that forms
an association as well as the spine of the list, i.e.
(lambda (a) (map (lambda (elt) (cons (car elt) (cdr elt))) a))
[procedure] (alist-delete key alist [=]) -> alist
[procedure] (alist-delete! key alist [=]) -> alist
alist-delete deletes all associations from alist with the given
key, using key-comparison procedure =, which defaults to equal?.
The dynamic order in which the various applications of = are made
is not specified.
Return values may share common tails with the alist argument. The
alist is not disordered -- elements that appear in the result alist
occur in the same order as they occur in the argument alist.
The comparison procedure is used to compare the element keys k[i]
of alist's entries to the key parameter in this way: (= key k[i]).
Thus, one can reliably remove all entries of alist whose key is
greater than five with (alist-delete 5 alist <)
alist-delete! is the linear-update variant of alist-delete. It is
allowed, but not required, to alter cons cells from the alist
parameter to construct the result.
Set operations on lists
Be aware that these procedures typically run in time O(n * m) for n-
and m-element list arguments. Performance-critical applications
operating upon large sets will probably wish to use other data
structures and algorithms.
[procedure] (lset<= = list[1] ...) -> boolean
Returns true iff every list[i] is a subset of list[i+1], using =
for the element-equality procedure. List A is a subset of list B if
every element in A is equal to some element of B. When performing
an element comparison, the = procedure's first argument is an
element of A; its second, an element of B.
(lset<= eq? '(a) '(a b a) '(a b c c)) => #t
(lset<= eq?) => #t ; Trivial cases
(lset<= eq? '(a)) => #t
[procedure] (lset= = list[1] list[2] ...) -> boolean
Returns true iff every list[i] is set-equal to list[i+1], using =
for the element-equality procedure. "Set-equal" simply means that
list[i] is a subset of list[i+1], and list[i+1] is a subset of list
[i]. The = procedure's first argument is an element of list[i]; its
second is an element of list[i+1].
(lset= eq? '(b e a) '(a e b) '(e e b a)) => #t
(lset= eq?) => #t ; Trivial cases
(lset= eq? '(a)) => #t
[procedure] (lset-adjoin = list elt[1] ...) -> list
Adds the elt[i] elements not already in the list parameter to the
result list. The result shares a common tail with the list
parameter. The new elements are added to the front of the list, but
no guarantees are made about their order. The = parameter is an
equality procedure used to determine if an elt[i] is already a
member of list. Its first argument is an element of list; its
second is one of the elt[i].
The list parameter is always a suffix of the result -- even if the
list parameter contains repeated elements, these are not reduced.
(lset-adjoin eq? '(a b c d c e) 'a 'e 'i 'o 'u) => (u o i a b c d c e)
[procedure] (lset-union = list[1] ...) -> list
Returns the union of the lists, using = for the element-equality
procedure.
The union of lists A and B is constructed as follows:
- If A is the empty list, the answer is B (or a copy of B).
- Otherwise, the result is initialised to be list A (or a copy of
A).
- Proceed through the elements of list B in a left-to-right
order. If b is such an element of B, compare every element r of
the current result list to b: (= r b). If all comparisons fail,
b is consed onto the front of the result.
However, there is no guarantee that = will be applied to every pair
of arguments from A and B. In particular, if A is eq? to B, the
operation may immediately terminate.
In the n-ary case, the two-argument list-union operation is simply
folded across the argument lists.
(lset-union eq? '(a b c d e) '(a e i o u)) =>
(u o i a b c d e)
;; Repeated elements in LIST1 are preserved.
(lset-union eq? '(a a c) '(x a x)) => (x a a c)
;; Trivial cases
(lset-union eq?) => ()
(lset-union eq? '(a b c)) => (a b c)
[procedure] (lset-intersection = list[1] list[2] ...) -> list
Returns the intersection of the lists, using = for the
element-equality procedure.
The intersection of lists A and B is comprised of every element of
A that is = to some element of B: (= a b), for a in A, and b in B.
Note this implies that an element which appears in B and multiple
times in list A will also appear multiple times in the result.
The order in which elements appear in the result is the same as
they appear in list[1] -- that is, lset-intersection essentially
filters list[1], without disarranging element order. The result may
share a common tail with list[1].
In the n-ary case, the two-argument list-intersection operation is
simply folded across the argument lists. However, the dynamic order
in which the applications of = are made is not specified. The
procedure may check an element of list[1] for membership in every
other list before proceeding to consider the next element of list
[1], or it may completely intersect list[1] and list[2] before
proceeding to list[3], or it may go about its work in some third
order.
(lset-intersection eq? '(a b c d e) '(a e i o u)) => (a e)
;; Repeated elements in LIST1 are preserved.
(lset-intersection eq? '(a x y a) '(x a x z)) => '(a x a)
(lset-intersection eq? '(a b c)) => (a b c) ; Trivial case
[procedure] (lset-difference = list[1] list[2] ...) -> list
Returns the difference of the lists, using = for the
element-equality procedure -- all the elements of list[1] that are
not = to any element from one of the other list[i] parameters.
The = procedure's first argument is always an element of list[1];
its second is an element of one of the other list[i]. Elements that
are repeated multiple times in the list[1] parameter will occur
multiple times in the result. The order in which elements appear in
the result is the same as they appear in list[1] -- that is,
lset-difference essentially filters list[1], without disarranging
element order. The result may share a common tail with list[1]. The
dynamic order in which the applications of = are made is not
specified. The procedure may check an element of list[1] for
membership in every other list before proceeding to consider the
next element of list[1], or it may completely compute the
difference of list[1] and list[2] before proceeding to list[3], or
it may go about its work in some third order.
(lset-difference eq? '(a b c d e) '(a e i o u)) => (b c d)
(lset-difference eq? '(a b c)) => (a b c) ; Trivial case
[procedure] (lset-xor = list[1] ...) -> list
Returns the exclusive-or of the sets, using = for the
element-equality procedure. If there are exactly two lists, this is
all the elements that appear in exactly one of the two lists. The
operation is associative, and thus extends to the n-ary case -- the
elements that appear in an odd number of the lists. The result may
share a common tail with any of the list[i] parameters.
More precisely, for two lists A and B, A xor B is a list of
- every element a of A such that there is no element b of B such
that (= a b), and
- every element b of B such that there is no element a of A such
that (= b a).
However, an implementation is allowed to assume that = is symmetric--
that is, that
(= a b) => (= b a).
This means, for example, that if a comparison (= a b) produces true
for some a in A and b in B, both a and b may be removed from
inclusion in the result.
In the n-ary case, the binary-xor operation is simply folded across
the lists.
(lset-xor eq? '(a b c d e) '(a e i o u)) => (d c b i o u)
;; Trivial cases.
(lset-xor eq?) => ()
(lset-xor eq? '(a b c d e)) => (a b c d e)
[procedure] (lset-diff+intersection = list[1] list[2] ...) -> [list list]
Returns two values -- the difference and the intersection of the
lists. Is equivalent to
(values (lset-difference = list[1] list[2] ...)
(lset-intersection = list[1]
(lset-union = list[2] ...)))
but can be implemented more efficiently.
The = procedure's first argument is an element of list[1]; its
second is an element of one of the other list[i].
Either of the answer lists may share a common tail with list[1].
This operation essentially partitions list[1].
[procedure] (lset-union! = list[1] ...) -> list
[procedure] (lset-intersection! = list[1] list[2] ...) -> list
[procedure] (lset-difference! = list[1] list[2] ...) -> list
[procedure] (lset-xor! = list[1] ...) -> list
[procedure] (lset-diff+intersection! = list[1] list[2] ...) -> [list list]
These are linear-update variants. They are allowed, but not
required, to use the cons cells in their first list parameter to
construct their answer. lset-union! is permitted to recycle cons
cells from any of its list arguments.
Previous: Unit regex
Next: Unit srfi-4