User Tools


Differences

This shows you the differences between two versions of the page.

Link to this comparison view

cl:functions:substitute [2019/09/14 05:00]
cl:functions:substitute [2019/09/20 08:00] (current)
Line 1: Line 1:
 +====== Function SUBSTITUTE, SUBSTITUTE-IF,​ SUBSTITUTE-IF-NOT,​ NSUBSTITUTE,​ NSUBSTITUTE-IF,​ NSUBSTITUTE-IF-NOT ======
 +
 +====Syntax====
 +  * **substitute** //newitem// //olditem// //​sequence//​ ''&​key''​ //​from-end//​ //test// //​test-not//​ //start// //end// //count// //key// → //​result-sequence//​
 +  * **substitute-if** //newitem// //​predicate//​ //​sequence//​ ''&​key''​ //​from-end//​ //start// //end// //count// //key// → //​result-sequence//​
 +  * **substitute-if-not** //newitem// //​predicate//​ //​sequence//​ ''&​key''​ //​from-end//​ //start// //end// //count// //key// → //​result-sequence//​
 +  * **nsubstitute** //newitem// //olditem// //​sequence//​ ''&​key''​ //​from-end//​ //test// //​test-not//​ //start// //end// //count// //key// → //​result-sequence//​
 +  * **nsubstitute-if** //newitem// //​predicate//​ //​sequence//​ ''&​key''​ //​from-end//​ //start// //end// //count// //key// → //​result-sequence//​
 +  * **nsubstitute-if-not** //newitem// //​predicate//​ //​sequence//​ ''&​key''​ //​from-end//​ //start// //end// //count// //key// → //​result-sequence//​
 +
 +====Arguments and Values====
 +  * //newitem// - an //​[[CL:​Glossary:​object]]//​.
 +  * //olditem// - an //​[[CL:​Glossary:​object]]//​.
 +  * //​sequence//​ - a //​[[CL:​Glossary:​proper sequence]]//​.
 +  * //​predicate//​ - a //​[[CL:​Glossary:​designator]]//​ for a //​[[CL:​Glossary:​function]]//​ of one //​[[CL:​Glossary:​argument]]//​ that returns a //​[[CL:​Glossary:​generalized boolean]]//​.
 +  * //​from-end//​ - a //​[[CL:​Glossary:​generalized boolean]]//​. The default is //​[[CL:​Glossary:​false]]//​.
 +  * //test// - a //​[[CL:​Glossary:​designator]]//​ for a //​[[CL:​Glossary:​function]]//​ of two //​[[CL:​Glossary:​argument|arguments]]//​ that returns a //​[[CL:​Glossary:​generalized boolean]]//​.
 +  * //​test-not//​ - a //​[[CL:​Glossary:​designator]]//​ for a //​[[CL:​Glossary:​function]]//​ of two //​[[CL:​Glossary:​argument|arguments]]//​ that returns a //​[[CL:​Glossary:​generalized boolean]]//​.
 +  * //start//, //end// - //​[[CL:​Glossary:​bounding index designator|bounding index designators]]//​ of //​sequence//​. The defaults for //start// and //end// are ''​0''​ and **[[CL:​Constant Variables:​nil]]**,​ respectively.
 +  * //count// - an //​[[CL:​Glossary:​integer]]//​ or **[[CL:​Constant Variables:​nil]]**. The default is **[[CL:​Constant Variables:​nil]]**.
 +  * //key// - a //​[[CL:​Glossary:​designator]]//​ for a //​[[CL:​Glossary:​function]]//​ of one argument, or **[[CL:​Constant Variables:​nil]]**.
 +  * //​result-sequence//​ - a //​[[CL:​Glossary:​sequence]]//​.
 +
 +====Description====
 +**substitute**,​ **substitute-if**,​ and **substitute-if-not** return a copy of //​sequence//​ in which each //​[[CL:​Glossary:​element]]//​ that //​[[CL:​Glossary:​satisfy the test|satisfies the test]]// has been replaced with //​newitem//​.
 +
 +**nsubstitute**,​ **nsubstitute-if**,​ and **nsubstitute-if-not** are like **substitute**,​ **substitute-if**,​ and **substitute-if-not** respectively,​ but they may modify //​sequence//​.
 +
 +If //​sequence//​ is a //​[[CL:​Glossary:​vector]]//,​ the result is a //​[[CL:​Glossary:​vector]]//​ that has the same //​[[CL:​Glossary:​actual array element type]]// as //​sequence//​.
 +
 +If //​sequence//​ is a //​[[CL:​Glossary:​list]]//,​ the result is a //​[[CL:​Glossary:​list]]//​.
 +
 +//count//, if supplied, limits the number of elements altered; if more than //count// //​[[CL:​Glossary:​element|elements]]//​ //​[[CL:​Glossary:​satisfy the test]]//, then of these //​[[CL:​Glossary:​element|elements]]//​ only the leftmost or rightmost, depending on //​from-end//,​ are replaced, as many as specified by //count//.
 +
 +If //count// is supplied and negative, the behavior is as if zero had been supplied instead.
 +
 +If //count// is **[[CL:​Constant Variables:​nil]]**,​ all matching items are affected.
 +
 +Supplying a //​from-end//​ of //​[[CL:​Glossary:​true]]//​ matters only when the //count// is provided (and //​[[CL:​Glossary:​non-nil]]//​);​ in that case, only the rightmost //count// //​[[CL:​Glossary:​element|elements]]//​ //​[[CL:​Glossary:​satisfy the test|satisfying the test]]// are removed (instead of the leftmost).
 +
 +//​predicate//,​ //test//, and //​test-not//​ might be called more than once for each //​[[CL:​Glossary:​sequence]]//​ //​[[CL:​Glossary:​element]]//,​ and their side effects can happen in any order.
 +
 +The result of all these functions is a //​[[CL:​Glossary:​sequence]]//​ of the same //​[[CL:​Glossary:​type]]//​ as //​sequence//​ that has the same elements except that those in the subsequence //​[[CL:​Glossary:​bounded]]//​ by //start// and //end// and //​[[CL:​Glossary:​satisfy the test|satisfying the test]]// have been replaced by //​newitem//​.
 +
 +**substitute**,​ **substitute-if**,​ and **substitute-if-not** return a //​sequence//​ which can share with //​sequence//​ or may be //​[[CL:​Glossary:​identical]]//​ to the input //​sequence//​ if no elements need to be changed.
 +
 +**nsubstitute** and **nsubstitute-if** are required to **[[CL:​Macros:​setf]]** any **[[CL:​Functions:​car]]** (if //​sequence//​ is a //​[[CL:​Glossary:​list]]//​) or **[[CL:​Functions:​aref]]** (if //​sequence//​ is a //​[[CL:​Glossary:​vector]]//​) of //​sequence//​ that is required to be replaced with //​newitem//​. If //​sequence//​ is a //​[[CL:​Glossary:​list]]//,​ none of the //​[[CL:​Glossary:​cdrs]]//​ of the top-level //​[[CL:​Glossary:​list]]//​ can be modified.
 +
 +====Examples====
 +<​blockquote> ​
 +(substitute #\. #\Space "0 2 4 6") <​r>"​0.2.4.6"​ </r>
 +(substitute 9 4 '(1 2 4 1 3 4 5)) <r>(1 2 9 1 3 9 5) </r>
 +(substitute 9 4 '(1 2 4 1 3 4 5) :count 1) <r>(1 2 9 1 3 4 5) </r>
 +(substitute 9 4 '(1 2 4 1 3 4 5) :count 1 :from-end [[CL:​Constant Variables:​t]]) <r>(1 2 4 1 3 9 5) </r>
 +(substitute 9 3 '(1 2 4 1 3 4 5) :test #'>​) <r>(9 9 4 9 3 4 5)</​r>​
 +
 +(substitute-if 0 #'​[[CL:​Functions:​evenp]] '((1) (2) (3) (4)) :start 2 :key #'​[[CL:​Functions:​car]]) <​r>​((1) (2) (3) 0) </r>
 +(substitute-if 9 #'​[[CL:​Functions:​oddp]] '(1 2 4 1 3 4 5)) <r>(9 2 4 9 9 4 9) </r>
 +(substitute-if 9 #'​[[CL:​Functions:​evenp]] '(1 2 4 1 3 4 5) :count 1 :from-end [[CL:​Constant Variables:​t]]) <r>(1 2 4 1 3 9 5)</​r>​
 +
 +([[CL:​Macros:​defparameter]] *some-things* ([[CL:​Functions:​list]] 'a 'car 'b 'cdr 'c)) <​r>​*SOME-THINGS*</​r>​
 +(nsubstitute-if "​function was here" #'​fboundp *some-things* ​
 +                :count 1 :from-end [[CL:​Constant Variables:​t]]) <r>(A CAR B "​function was here" C)</​r>​
 +*some-things* <r>(A CAR B "​function was here" C) </r>
 +([[CL:​Macros:​defparameter]] *alpha-tester* ([[CL:​Functions:​copy-seq]] "ab ")) <​r>"​ab " </r>
 +(nsubstitute-if-not #\z #'​[[CL:​Functions:​alpha-char-p]] *alpha-tester*) <​r>"​abz"​ </r>
 +*alpha-tester* <​r>"​abz"​ </r>
 +</​blockquote>​
 +
 +====Side Effects====
 +**nsubstitute**,​ **nsubstitute-if**,​ and **nsubstitute-if-not** modify //​sequence//​.
 +
 +====Affected By====
 +None.
 +
 +====Exceptional Situations====
 +Should be prepared to signal an error of type type-error if //​sequence//​ is not a //​[[CL:​Glossary:​proper sequence]]//​.
 +
 +====See Also====
 +  * **[[CL:​Functions:​subst|Function SUBST]]**
 +  * **[[CL:​Functions:​nsubst|Function NSUBST]]**,
 +
 +{\secref\ConstantModification},​
 +
 +{\secref\TraversalRules}
 +
 +====Notes====
 +If //​sequence//​ is a //​[[CL:​Glossary:​vector]]//,​ the result might or might not be simple, and might or might not be //​[[CL:​Glossary:​identical]]//​ to //​sequence//​.
 +
 +The **'':​test-not''​** //​[[CL:​Glossary:​argument]]//​ is deprecated.
 +
 +The functions **substitute-if-not** and **nsubstitute-if-not** are deprecated.
 +
 +**nsubstitute** and **nsubstitute-if** can be used in for-effect-only positions in code.
 +
 +Because the side-effecting variants (//e.g.// **nsubstitute**) potentially change the path that is being traversed, their effects in the presence of shared or circular structure may vary in surprising ways when compared to their non-side-effecting alternatives. To see this, consider the following side-effect behavior, which might be exhibited by some implementations:​
 +
 +<​blockquote>​ (defun test-it (fn) (let ((x (cons 'b nil))) (rplacd x x) (funcall fn 'a 'b x :count 1))) (test-it #'​substitute) → (A . #1=(B . #1#)) (test-it #'​nsubstitute) → (A . #1#) </​blockquote>​
 +
 +\issue{MAPPING-DESTRUCTIVE-INTERACTION:​EXPLICITLY-VAGUE} \issue{TEST-NOT-IF-NOT:​FLUSH-ALL} \issue{TEST-NOT-IF-NOT:​FLUSH-ALL} \issue{SUBSEQ-OUT-OF-BOUNDS} \issue{RANGE-OF-START-AND-END-PARAMETERS:​INTEGER-AND-INTEGER-NIL} \issue{RANGE-OF-COUNT-KEYWORD:​NIL-OR-INTEGER} \issue{RANGE-OF-COUNT-KEYWORD:​NIL-OR-INTEGER} \issue{REMF-DESTRUCTION-UNSPECIFIED:​X3J13-MAR-89} \issue{CONSTANT-MODIFICATION:​DISALLOW}