Rewrite ASSOC using SATISFIES-TEST-P
[jscl.git] / src / list.lisp
1 ;;; list.lisp --- 
2
3 ;; JSCL is free software: you can redistribute it and/or
4 ;; modify it under the terms of the GNU General Public License as
5 ;; published by the Free Software Foundation, either version 3 of the
6 ;; License, or (at your option) any later version.
7 ;;
8 ;; JSCL is distributed in the hope that it will be useful, but
9 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
10 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 ;; General Public License for more details.
12 ;;
13 ;; You should have received a copy of the GNU General Public License
14 ;; along with JSCL.  If not, see <http://www.gnu.org/licenses/>.
15
16 ;;;; Various list functions
17
18 (defun cons (x y) (cons x y))
19 (defun consp (x) (consp x))
20
21 (defun listp (x)
22   (or (consp x) (null x)))
23
24 (defun null (x)
25   (eq x nil))
26
27 (defun endp (x)
28   (if (null x)
29       t
30       (if (consp x)
31           nil
32           (error "The value `~S' is not a type list." x))))
33
34 (defun car (x)
35   "Return the CAR part of a cons, or NIL if X is null."
36   (car x))
37
38 (defun cdr (x) (cdr x))
39
40 (defun first   (x) (car    x))
41 (defun second  (x) (cadr   x))
42 (defun third   (x) (caddr  x))
43 (defun fourth  (x) (cadddr x))
44 (defun fifth   (x) (car    (cddddr x)))
45 (defun sixth   (x) (cadr   (cddddr x)))
46 (defun seventh (x) (caddr  (cddddr x)))
47 (defun eighth  (x) (cadddr (cddddr x)))
48 (defun ninth   (x) (car  (cddddr (cddddr x))))
49 (defun tenth   (x) (cadr (cddddr (cddddr x))))
50 (defun rest    (x) (cdr x))
51
52 (defun list (&rest args)
53   args)
54
55 (defun list* (arg &rest others)
56   (cond ((null others) arg)
57         ((null (cdr others)) (cons arg (car others)))
58         (t (do ((x others (cdr x)))
59                ((null (cddr x)) (rplacd x (cadr x))))
60            (cons arg others))))
61
62 (defun nthcdr (n list)
63   (while (and (plusp n) list)
64     (setq n (1- n))
65     (setq list (cdr list)))
66   list)
67
68 (defun nth (n list)
69   (car (nthcdr n list)))
70
71 (defun caar (x) (car (car x)))
72 (defun cadr (x) (car (cdr x)))
73 (defun cdar (x) (cdr (car x)))
74 (defun cddr (x) (cdr (cdr x)))
75
76 (defun caaar (x) (car (caar x)))
77 (defun caadr (x) (car (cadr x)))
78 (defun cadar (x) (car (cdar x)))
79 (defun caddr (x) (car (cddr x)))
80 (defun cdaar (x) (cdr (caar x)))
81 (defun cdadr (x) (cdr (cadr x)))
82 (defun cddar (x) (cdr (cdar x)))
83 (defun cdddr (x) (cdr (cddr x)))
84
85 (defun caaaar (x) (car (caaar x)))
86 (defun caaadr (x) (car (caadr x)))
87 (defun caadar (x) (car (cadar x)))
88 (defun caaddr (x) (car (caddr x)))
89 (defun cadaar (x) (car (cdaar x)))
90 (defun cadadr (x) (car (cdadr x)))
91 (defun caddar (x) (car (cddar x)))
92 (defun cadddr (x) (car (cdddr x)))
93 (defun cdaaar (x) (cdr (caaar x)))
94 (defun cdaadr (x) (cdr (caadr x)))
95 (defun cdadar (x) (cdr (cadar x)))
96 (defun cdaddr (x) (cdr (caddr x)))
97 (defun cddaar (x) (cdr (cdaar x)))
98 (defun cddadr (x) (cdr (cdadr x)))
99 (defun cdddar (x) (cdr (cddar x)))
100 (defun cddddr (x) (cdr (cdddr x)))
101
102 (defun sublis (alist tree &key key (test #'eql testp) (test-not #'eql test-not-p))
103   (when (and testp test-not-p)
104     (error "Both test and test-not are set"))
105   (labels ((s (tree)
106              (let* ((key-val (if key (funcall key tree) tree))
107                     (replace (if test-not-p
108                                  (assoc key-val alist :test-not test-not)
109                                  (assoc key-val alist :test test)))
110                     (x (if replace (cdr replace) tree)))
111                (if (atom x)
112                    x
113                    (cons (s (car x)) (s (cdr x)))))))
114     (s tree)))
115
116 (defun subst (new old tree &key key (test #'eql testp) (test-not #'eql test-not-p))
117   (labels ((s (x)
118              (cond ((satisfies-test-p old x :key key :test test :testp testp
119                                       :test-not test-not :test-not-p test-not-p)
120                     new)
121                    ((atom x) x)
122                    (t (let ((a (s (car x)))
123                             (b (s (cdr x))))
124                         (if (and (eq a (car x))
125                                  (eq b (cdr x)))
126                             x
127                             (cons a b)))))))
128     (s tree)))
129
130 (defun copy-list (x)
131   (mapcar #'identity x))
132
133 (defun copy-tree (tree)
134   (if (consp tree)
135     (cons (copy-tree (car tree))
136           (copy-tree (cdr tree)))
137     tree))
138
139 (defun tree-equal (tree1 tree2 &key (test #'eql testp)
140                          (test-not #'eql test-not-p))
141   (when (and testp test-not-p) (error "Both test and test-not are set"))
142   (let ((func (if test-not-p (complement test-not) test)))
143     (labels ((%tree-equal (tree1 tree2)
144                (if (atom tree1)
145                  (and (atom tree2) (funcall func tree1 tree2))
146                  (and (consp tree2)
147                       (%tree-equal (car tree1) (car tree2))
148                       (%tree-equal (cdr tree1) (cdr tree2))))))
149       (%tree-equal tree1 tree2))))
150
151 (defun tailp (object list)
152   (do ((tail list (cdr tail)))
153     ((atom tail) (eq object tail))
154     (when (eql tail object)
155       (return-from tailp t))))
156
157 (defmacro pop (place)
158   (multiple-value-bind (dummies vals newval setter getter)
159     (get-setf-expansion place)
160     (let ((head (gensym)))
161       `(let* (,@(mapcar #'list dummies vals) 
162               (,head ,getter)
163               (,(car newval) (cdr ,head))
164               ,@(cdr newval)) 
165          ,setter
166          (car ,head)))))
167
168
169 (defun map1 (func list)
170   (with-collect
171     (while list
172       (collect (funcall func (car list)))
173       (setq list (cdr list)))))
174
175 (defun mapcar (func list &rest lists)
176   (let ((lists (cons list lists)))
177     (with-collect
178       (block loop
179         (loop
180            (let ((elems (map1 #'car lists)))
181              (do ((tail lists (cdr tail)))
182                  ((null tail))
183                (when (null (car tail)) (return-from loop))
184                (rplaca tail (cdar tail)))
185              (collect (apply func elems))))))))
186
187 (defun mapc (func &rest lists)
188   (do* ((elems (map1 #'car lists) (map1 #'car lists-rest))
189         (lists-rest (map1 #'cdr lists) (map1 #'cdr lists-rest)))
190        ((dolist (x elems) (when (null x) (return t)))
191         (car lists))
192     (apply func elems)))
193
194 (defun last (x)
195   (while (consp (cdr x))
196     (setq x (cdr x)))
197   x)
198
199 (defun butlast (x)
200   (and (consp (cdr x))
201        (cons (car x) (butlast (cdr x)))))
202
203 (defun member (x list &key key (test #'eql testp) (test-not #'eql test-not-p)) 
204   (while list
205     (when (satisfies-test-p x (car list) :key key :test test :testp testp
206                             :test-not test-not :test-not-p test-not-p)
207       (return list))
208     (setq list (cdr list))))
209
210
211 (defun assoc (x alist &key key (test #'eql testp) (test-not #'eql test-not-p))
212   (while alist
213     (if (satisfies-test-p x (caar alist) :key key :test test :testp testp
214                           :test-not test-not :test-not-p test-not-p)
215       (return)
216       (setq alist (cdr alist))))
217   (car alist))
218
219 (defun rassoc (x alist &key (test #'eql))
220   (while alist
221     (if (funcall test x (cdar alist))
222       (return)
223       (setq alist (cdr alist))))
224   (car alist))
225
226 (defun acons (key datum alist)
227   (cons (cons key datum) alist))
228
229 (defun pairlis (keys data &optional (alist ()))
230   (while keys
231     (setq alist (acons (car keys) (car data) alist))
232     (setq keys (cdr keys))
233     (setq data (cdr data)))
234   alist)
235
236 (defun copy-alist (alist)
237   (let ((new-alist ()))
238     (while alist
239       (push (cons (caar alist) (cdar alist)) new-alist)
240       (setq alist (cdr alist)))
241     (reverse new-alist)))
242
243
244 (define-setf-expander car (x)
245   (let ((cons (gensym))
246         (new-value (gensym)))
247     (values (list cons)
248             (list x)
249             (list new-value)
250             `(progn (rplaca ,cons ,new-value) ,new-value)
251             `(car ,cons))))
252
253 (define-setf-expander cdr (x)
254   (let ((cons (gensym))
255         (new-value (gensym)))
256     (values (list cons)
257             (list x)
258             (list new-value)
259             `(progn (rplacd ,cons ,new-value) ,new-value)
260             `(car ,cons))))
261
262
263 ;; The NCONC function is based on the SBCL's one.
264 (defun nconc (&rest lists)
265   (flet ((fail (object)
266            (error "type-error in nconc")))
267     (do ((top lists (cdr top)))
268         ((null top) nil)
269       (let ((top-of-top (car top)))
270         (typecase top-of-top
271           (cons
272            (let* ((result top-of-top)
273                   (splice result))
274              (do ((elements (cdr top) (cdr elements)))
275                  ((endp elements))
276                (let ((ele (car elements)))
277                  (typecase ele
278                    (cons (rplacd (last splice) ele)
279                          (setf splice ele))
280                    (null (rplacd (last splice) nil))
281                    (atom (if (cdr elements)
282                              (fail ele)
283                              (rplacd (last splice) ele))))))
284              (return result)))
285           (null)
286           (atom
287            (if (cdr top)
288                (fail top-of-top)
289                (return top-of-top))))))))
290
291
292 (defun nreconc (x y)
293   (do ((1st (cdr x) (if (endp 1st) 1st (cdr 1st)))
294        (2nd x 1st)                ; 2nd follows first down the list.
295        (3rd y 2nd))               ;3rd follows 2nd down the list.
296       ((atom 2nd) 3rd)
297     (rplacd 2nd 3rd)))
298
299
300 (defun adjoin (item list &key (test #'eql) (key #'identity))
301   (if (member item list :key key :test test)
302     list
303     (cons item list)))
304
305 (defun intersection (list1 list2 &key (test #'eql) (key #'identity))
306   (let ((new-list ()))
307     (dolist (x list1)
308       (when (member x list2 :test test :key key)
309         (push x new-list)))
310     new-list))