Common Lisp the Language, 2nd Edition
Series that come from scanning data structures such as lists and vectors
are closely linked to these structures. The function
alter can be used to modify the underlying data structure with
reference to the series derived from it. (Conversely, it is possible to
modify a series by destructively modifying the data structure it is derived
from. However, given the lazy evaluation nature of series, the effects of
such modifications can be very hard to predict. As a result, this kind of
modification is inadvisable.)
[Function]
alter destinations items
alter changes the series destinations so that it contains the elements in the series items. More importantly, in the manner of setf, the data structure that underlies destinations is changed so that if the series destinations were to be regenerated, the new values would be obtained. The alteration process stops as soon as either input runs out of elements. The value nil is always returned. In the example below each negative element in a list is replaced with its square.
(let* ((data (list 1 -2 3 4 -5 6)) (x (choose-if #'minusp (scan data)))) (alter x (#M* x x)) data) => (1 4 3 4 25 6)
alter can be applied only to series that are alterable. scan, scan-alist, scan-multiple, scan-plist, and scan-lists-of-lists-fringe produce alterable series. However, the alterability of the output of scan-lists-of-lists-fringe is incomplete. If scan-lists-of-lists-fringe is applied to an object that is a leaf, altering the output series does not change the object.
In general, the output of a transducer is alterable as long as the elements of the output come directly from the elements of an input that is alterable. In particular, the outputs of choose, choose-if, split, split-if, cotruncate, until, until-if, and subseries are alterable as long as the corresponding inputs are alterable.
[Function]
to-alter items alter-fn &rest args
Given a series items, to-alter returns an alterable series A containing the same elements. The argument alter-fn is a function. The remaining arguments are all series. Let these series be S1, ..., Sn. If there are n arguments after alter-fn, alter-fn must accept n+1 inputs. If (alter A B) is later encountered, the expression (map-fn t alter-fn B S1 ... Sn) is implicitly evaluated. For each element in B, alter-fn should make appropriate changes in the data structure underlying A.
As an example, consider the following definition of a series function that scans the elements of a list. Alteration is performed by changing cons cells in the list being scanned.
(defun scan-list (list) (declare (optimizable-series-function)) (let ((sublists (scan-sublists list))) (to-alter (#Mcar sublists) #'(lambda (new parent) (setf (car parent) new)) sublists)))