(cons (s (car x)) (s (cdr x)))))))
(s tree)))
+(defun subst (new old tree &key key (test #'eql testp) (test-not #'eql test-not-p))
+ (when (and testp test-not-p)
+ (error "Both test and test-not are set"))
+ (labels ((s (x)
+ (let ((key-val (if key (funcall key x) x)))
+ (cond
+ ((funcall (if test-not-p test-not test) key-val old) new)
+ ((atom x) x)
+ (t (cons (s (car x)) (s (cdr x))))))))
+ (s tree)))
+
(defun copy-list (x)
(mapcar #'identity x))
(when (eql tail object)
(return-from tailp t))))
-(defun subst (new old tree &key (key #'identity) (test #'eql))
- (cond
- ((funcall test (funcall key tree) (funcall key old))
- new)
- ((consp tree)
- (cons (subst new old (car tree) :key key :test test)
- (subst new old (cdr tree) :key key :test test)))
- (t tree)))
-
(defmacro pop (place)
(multiple-value-bind (dummies vals newval setter getter)
(get-setf-expansion place)
(test (equal (sublis '(("two" . 2)) tree2 :test 'equal)
'("one" ("one" 2) (("one" "Two" "three"))))))
+;; SUBST
+(let ((tree1 '(1 (1 2) (1 2 3) (1 2 3 4))))
+ (test (equal (subst "two" 2 tree1) '(1 (1 "two") (1 "two" 3) (1 "two" 3 4))))
+ (test (equal (subst "five" 5 tree1) '(1 (1 2) (1 2 3) (1 2 3 4))))
+ (test (not (eq tree1 (subst "five" 5 tree1)))) ; Implementation dependent
+ (test (equal tree1 '(1 (1 2) (1 2 3) (1 2 3 4)))))
+(test (equal (subst 'tempest 'hurricane
+ '(shakespeare wrote (the hurricane)))
+ '(SHAKESPEARE WROTE (THE TEMPEST))))
+(test (equal (subst 'foo 'nil '(shakespeare wrote (twelfth night)))
+ '(SHAKESPEARE WROTE (TWELFTH NIGHT . FOO) . FOO)))
+(test (equal (subst '(a . cons) '(old . pair)
+ '((old . spice) ((old . shoes) old . pair) (old . pair))
+ :test #'equal)
+ '((OLD . SPICE) ((OLD . SHOES) A . CONS) (A . CONS))))
+
; COPY-TREE
(test (let* ((foo (list '(1 2) '(3 4)))
(bar (copy-tree foo)))
(test (not (intersection '(1 2 3) '(4 5 6))))
(test (equal (intersection '((1) (2)) '((2) (3)) :test #'equal) '((2))))
-; SUBST
-
; POP
(test (let* ((foo '(1 2 3))
(bar (pop foo)))