move srfi-1 and srfi-60 C impl to libguile, without public C api
[bpt/guile.git] / module / srfi / srfi-1.scm
CommitLineData
6be07c52
TTN
1;;; srfi-1.scm --- List Library
2
0b7f2eb8 3;; Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2010 Free Software Foundation, Inc.
6be07c52 4;;
73be1d9e
MV
5;; This library is free software; you can redistribute it and/or
6;; modify it under the terms of the GNU Lesser General Public
7;; License as published by the Free Software Foundation; either
83ba2d37 8;; version 3 of the License, or (at your option) any later version.
73be1d9e
MV
9;;
10;; This library is distributed in the hope that it will be useful,
6be07c52
TTN
11;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
73be1d9e
MV
13;; Lesser General Public License for more details.
14;;
15;; You should have received a copy of the GNU Lesser General Public
16;; License along with this library; if not, write to the Free Software
92205699 17;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
e9680547
MG
18
19;;; Author: Martin Grabmueller <mgrabmue@cs.tu-berlin.de>
20;;; Date: 2001-06-06
21
22;;; Commentary:
23
6be07c52
TTN
24;; This is an implementation of SRFI-1 (List Library).
25;;
26;; All procedures defined in SRFI-1, which are not already defined in
27;; the Guile core library, are exported. The procedures in this
28;; implementation work, but they have not been tuned for speed or
29;; memory usage.
30;;
31;; This module is fully documented in the Guile Reference Manual.
e9680547
MG
32
33;;; Code:
34
35(define-module (srfi srfi-1)
f595ccfe 36 :export (
e9680547
MG
37;;; Constructors
38 ;; cons <= in the core
39 ;; list <= in the core
40 xcons
41 ;; cons* <= in the core
42 ;; make-list <= in the core
43 list-tabulate
d61261f0 44 list-copy
e9680547 45 circular-list
f595ccfe 46 ;; iota ; Extended.
e9680547
MG
47
48;;; Predicates
49 proper-list?
50 circular-list?
51 dotted-list?
52 ;; pair? <= in the core
53 ;; null? <= in the core
54 null-list?
55 not-pair?
56 list=
57
58;;; Selectors
59 ;; car <= in the core
60 ;; cdr <= in the core
61 ;; caar <= in the core
62 ;; cadr <= in the core
63 ;; cdar <= in the core
2a326497 64 ;; cddr <= in the core
e9680547
MG
65 ;; caaar <= in the core
66 ;; caadr <= in the core
67 ;; cadar <= in the core
68 ;; caddr <= in the core
69 ;; cdaar <= in the core
70 ;; cdadr <= in the core
71 ;; cddar <= in the core
72 ;; cdddr <= in the core
73 ;; caaaar <= in the core
74 ;; caaadr <= in the core
75 ;; caadar <= in the core
76 ;; caaddr <= in the core
77 ;; cadaar <= in the core
78 ;; cadadr <= in the core
79 ;; caddar <= in the core
80 ;; cadddr <= in the core
81 ;; cdaaar <= in the core
82 ;; cdaadr <= in the core
83 ;; cdadar <= in the core
84 ;; cdaddr <= in the core
85 ;; cddaar <= in the core
86 ;; cddadr <= in the core
87 ;; cdddar <= in the core
88 ;; cddddr <= in the core
89 ;; list-ref <= in the core
90 first
91 second
92 third
93 fourth
94 fifth
95 sixth
96 seventh
97 eighth
98 ninth
99 tenth
100 car+cdr
101 take
102 drop
103 take-right
104 drop-right
105 take!
106 drop-right!
107 split-at
108 split-at!
109 last
110 ;; last-pair <= in the core
111
112;;; Miscelleneous: length, append, concatenate, reverse, zip & count
113 ;; length <= in the core
114 length+
115 ;; append <= in the core
116 ;; append! <= in the core
117 concatenate
118 concatenate!
119 ;; reverse <= in the core
120 ;; reverse! <= in the core
121 append-reverse
122 append-reverse!
123 zip
124 unzip1
125 unzip2
126 unzip3
127 unzip4
128 unzip5
129 count
130
131;;; Fold, unfold & map
132 fold
133 fold-right
134 pair-fold
135 pair-fold-right
136 reduce
137 reduce-right
138 unfold
139 unfold-right
f595ccfe
MD
140 ;; map ; Extended.
141 ;; for-each ; Extended.
e9680547
MG
142 append-map
143 append-map!
144 map!
f595ccfe 145 ;; map-in-order ; Extended.
e9680547
MG
146 pair-for-each
147 filter-map
148
149;;; Filtering & partitioning
c614a00b 150 ;; filter <= in the core
e9680547
MG
151 partition
152 remove
c614a00b 153 ;; filter! <= in the core
e9680547
MG
154 partition!
155 remove!
156
157;;; Searching
158 find
159 find-tail
160 take-while
161 take-while!
162 drop-while
163 span
164 span!
165 break
166 break!
167 any
168 every
f595ccfe
MD
169 ;; list-index ; Extended.
170 ;; member ; Extended.
e9680547
MG
171 ;; memq <= in the core
172 ;; memv <= in the core
173
174;;; Deletion
f595ccfe
MD
175 ;; delete ; Extended.
176 ;; delete! ; Extended.
e9680547
MG
177 delete-duplicates
178 delete-duplicates!
179
180;;; Association lists
f595ccfe 181 ;; assoc ; Extended.
e9680547
MG
182 ;; assq <= in the core
183 ;; assv <= in the core
184 alist-cons
185 alist-copy
186 alist-delete
187 alist-delete!
188
189;;; Set operations on lists
190 lset<=
191 lset=
192 lset-adjoin
193 lset-union
194 lset-intersection
195 lset-difference
196 lset-xor
197 lset-diff+intersection
198 lset-union!
199 lset-intersection!
200 lset-difference!
201 lset-xor!
202 lset-diff+intersection!
203
204;;; Primitive side-effects
205 ;; set-car! <= in the core
206 ;; set-cdr! <= in the core
207 )
d61261f0 208 :re-export (cons list cons* make-list pair? null?
b8b0abf0
MD
209 car cdr caar cadr cdar cddr
210 caaar caadr cadar caddr cdaar cdadr cddar cdddr
211 caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr
212 cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr
213 list-ref last-pair length append append! reverse reverse!
214 filter filter! memq memv assq assv set-car! set-cdr!)
d61261f0 215 :replace (iota map for-each map-in-order list-copy list-index member
f595ccfe
MD
216 delete delete! assoc)
217 )
e9680547
MG
218
219(cond-expand-provide (current-module) '(srfi-1))
220
ee6aac97
MD
221;; Load the compiled primitives from the shared library.
222;;
37710f7e
AW
223(load-extension (string-append "libguile-" (effective-version))
224 "scm_init_srfi_1")
ee6aac97
MD
225
226
e9680547
MG
227;;; Constructors
228
0b7f2eb8
LC
229(define (xcons d a)
230 "Like `cons', but with interchanged arguments. Useful mostly when passed to
231higher-order procedures."
232 (cons a d))
233
5753f02f
GH
234;; internal helper, similar to (scsh utilities) check-arg.
235(define (check-arg-type pred arg caller)
236 (if (pred arg)
237 arg
238 (scm-error 'wrong-type-arg caller
239 "Wrong type argument: ~S" (list arg) '())))
240
241;; the srfi spec doesn't seem to forbid inexact integers.
242(define (non-negative-integer? x) (and (integer? x) (>= x 0)))
243
0b7f2eb8
LC
244(define (list-tabulate n init-proc)
245 "Return an N-element list, where each list element is produced by applying the
246procedure INIT-PROC to the corresponding list index. The order in which
247INIT-PROC is applied to the indices is not specified."
248 (check-arg-type non-negative-integer? n "list-tabulate")
249 (let lp ((n n) (acc '()))
250 (if (<= n 0)
251 acc
252 (lp (- n 1) (cons (init-proc (- n 1)) acc)))))
e9680547 253
2d411b05
KR
254(define (circular-list elt1 . elts)
255 (set! elts (cons elt1 elts))
256 (set-cdr! (last-pair elts) elts)
257 elts)
e9680547 258
2cf7ff2e 259(define* (iota count #:optional (start 0) (step 1))
5753f02f 260 (check-arg-type non-negative-integer? count "iota")
2cf7ff2e
LC
261 (let lp ((n 0) (acc '()))
262 (if (= n count)
e9680547 263 (reverse! acc)
2cf7ff2e 264 (lp (+ n 1) (cons (+ start (* n step)) acc)))))
e9680547
MG
265
266;;; Predicates
267
268(define (proper-list? x)
269 (list? x))
270
271(define (circular-list? x)
272 (if (not-pair? x)
273 #f
274 (let lp ((hare (cdr x)) (tortoise x))
275 (if (not-pair? hare)
276 #f
277 (let ((hare (cdr hare)))
278 (if (not-pair? hare)
279 #f
280 (if (eq? hare tortoise)
281 #t
282 (lp (cdr hare) (cdr tortoise)))))))))
283
284(define (dotted-list? x)
285 (cond
286 ((null? x) #f)
287 ((not-pair? x) #t)
288 (else
289 (let lp ((hare (cdr x)) (tortoise x))
290 (cond
291 ((null? hare) #f)
292 ((not-pair? hare) #t)
293 (else
294 (let ((hare (cdr hare)))
513a3bd7 295 (cond
e9680547
MG
296 ((null? hare) #f)
297 ((not-pair? hare) #t)
298 ((eq? hare tortoise) #f)
299 (else
300 (lp (cdr hare) (cdr tortoise)))))))))))
301
302(define (null-list? x)
303 (cond
513a3bd7 304 ((proper-list? x)
e9680547
MG
305 (null? x))
306 ((circular-list? x)
307 #f)
308 (else
309 (error "not a proper list in null-list?"))))
310
0b7f2eb8
LC
311(define (not-pair? x)
312 "Return #t if X is not a pair, #f otherwise.
313
314This is shorthand notation `(not (pair? X))' and is supposed to be used for
315end-of-list checking in contexts where dotted lists are allowed."
316 (not (pair? x)))
317
e9680547
MG
318(define (list= elt= . rest)
319 (define (lists-equal a b)
320 (let lp ((a a) (b b))
321 (cond ((null? a)
322 (null? b))
323 ((null? b)
324 #f)
325 (else
326 (and (elt= (car a) (car b))
327 (lp (cdr a) (cdr b)))))))
328 (or (null? rest)
1bc8745f
KR
329 (let lp ((lists rest))
330 (or (null? (cdr lists))
331 (and (lists-equal (car lists) (cadr lists))
332 (lp (cdr lists)))))))
e9680547
MG
333
334;;; Selectors
335
336(define first car)
337(define second cadr)
338(define third caddr)
339(define fourth cadddr)
d7418e60
LC
340(define (fifth x) (car (cddddr x)))
341(define (sixth x) (cadr (cddddr x)))
342(define (seventh x) (caddr (cddddr x)))
343(define (eighth x) (cadddr (cddddr x)))
344(define (ninth x) (car (cddddr (cddddr x))))
345(define (tenth x) (cadr (cddddr (cddddr x))))
e9680547 346
0b7f2eb8
LC
347(define (car+cdr x)
348 "Return two values, the `car' and the `cdr' of PAIR."
349 (values (car x) (cdr x)))
350
4dd6bd84
KR
351(define take list-head)
352(define drop list-tail)
353
dcde4386
LC
354(define (take! lst i)
355 "Linear-update variant of `take'."
356 (if (= i 0)
357 '()
358 (let ((tail (drop lst (- i 1))))
359 (set-cdr! tail '())
360 lst)))
361
362(define (drop-right! lst i)
363 "Linear-update variant of `drop-right'."
364 (let ((tail (drop lst i)))
365 (if (null? tail)
366 '()
367 (let loop ((prev lst)
368 (tail (cdr tail)))
369 (if (null? tail)
370 (if (pair? prev)
371 (begin
372 (set-cdr! prev '())
373 lst)
374 lst)
375 (loop (cdr prev)
376 (cdr tail)))))))
377
0b7f2eb8
LC
378(define (last pair)
379 "Return the last element of the non-empty, finite list PAIR."
380 (car (last-pair pair)))
381
e9680547
MG
382;;; Miscelleneous: length, append, concatenate, reverse, zip & count
383
e9680547
MG
384(define (zip clist1 . rest)
385 (let lp ((l (cons clist1 rest)) (acc '()))
386 (if (any null? l)
387 (reverse! acc)
cef248dd 388 (lp (map1 cdr l) (cons (map1 car l) acc)))))
513a3bd7 389
e9680547
MG
390
391(define (unzip1 l)
cef248dd 392 (map1 first l))
e9680547 393(define (unzip2 l)
cef248dd 394 (values (map1 first l) (map1 second l)))
e9680547 395(define (unzip3 l)
cef248dd 396 (values (map1 first l) (map1 second l) (map1 third l)))
e9680547 397(define (unzip4 l)
cef248dd 398 (values (map1 first l) (map1 second l) (map1 third l) (map1 fourth l)))
e9680547 399(define (unzip5 l)
cef248dd
MG
400 (values (map1 first l) (map1 second l) (map1 third l) (map1 fourth l)
401 (map1 fifth l)))
e9680547 402
e9680547
MG
403;;; Fold, unfold & map
404
0b7f2eb8
LC
405(define (fold kons knil list1 . rest)
406 "Apply PROC to the elements of LIST1 ... LISTN to build a result, and return
407that result. See the manual for details."
408 (if (null? rest)
409 (let f ((knil knil) (list1 list1))
410 (if (null? list1)
411 knil
412 (f (kons (car list1) knil) (cdr list1))))
413 (let f ((knil knil) (lists (cons list1 rest)))
414 (if (any null? lists)
415 knil
416 (let ((cars (map1 car lists))
417 (cdrs (map1 cdr lists)))
418 (f (apply kons (append! cars (list knil))) cdrs))))))
419
e9680547
MG
420(define (fold-right kons knil clist1 . rest)
421 (if (null? rest)
422 (let f ((list1 clist1))
423 (if (null? list1)
424 knil
425 (kons (car list1) (f (cdr list1)))))
426 (let f ((lists (cons clist1 rest)))
427 (if (any null? lists)
428 knil
cef248dd 429 (apply kons (append! (map1 car lists) (list (f (map1 cdr lists)))))))))
e9680547
MG
430
431(define (pair-fold kons knil clist1 . rest)
432 (if (null? rest)
433 (let f ((knil knil) (list1 clist1))
434 (if (null? list1)
435 knil
436 (let ((tail (cdr list1)))
437 (f (kons list1 knil) tail))))
438 (let f ((knil knil) (lists (cons clist1 rest)))
439 (if (any null? lists)
440 knil
cef248dd 441 (let ((tails (map1 cdr lists)))
563058ef 442 (f (apply kons (append! lists (list knil))) tails))))))
e9680547
MG
443
444
445(define (pair-fold-right kons knil clist1 . rest)
446 (if (null? rest)
447 (let f ((list1 clist1))
448 (if (null? list1)
449 knil
450 (kons list1 (f (cdr list1)))))
451 (let f ((lists (cons clist1 rest)))
452 (if (any null? lists)
453 knil
cef248dd 454 (apply kons (append! lists (list (f (map1 cdr lists)))))))))
e9680547 455
2cf7ff2e
LC
456(define* (unfold p f g seed #:optional (tail-gen (lambda (x) '())))
457 (let uf ((seed seed))
458 (if (p seed)
459 (tail-gen seed)
460 (cons (f seed)
461 (uf (g seed))))))
462
463(define* (unfold-right p f g seed #:optional (tail '()))
464 (let uf ((seed seed) (lis tail))
465 (if (p seed)
466 lis
467 (uf (g seed) (cons (f seed) lis)))))
e9680547 468
dcde4386
LC
469(define (reduce f ridentity lst)
470 "`reduce' is a variant of `fold', where the first call to F is on two
471elements from LST, rather than one element and a given initial value.
472If LST is empty, RIDENTITY is returned. If LST has just one element
473then that's the return value."
474 (if (null? lst)
475 ridentity
476 (fold f (car lst) (cdr lst))))
477
478(define (reduce-right f ridentity lst)
479 "`reduce-right' is a variant of `fold-right', where the first call to
480F is on two elements from LST, rather than one element and a given
481initial value. If LST is empty, RIDENTITY is returned. If LST
482has just one element then that's the return value."
483 (if (null? lst)
484 ridentity
485 (fold-right f (last lst) (drop-right lst 1))))
486
cef248dd
MG
487
488;; Internal helper procedure. Map `f' over the single list `ls'.
489;;
7692d26b 490(define map1 map)
cef248dd 491
e9680547 492(define (append-map f clist1 . rest)
8b981efd 493 (concatenate (apply map f clist1 rest)))
558d5c03 494
e9680547 495(define (append-map! f clist1 . rest)
8b981efd 496 (concatenate! (apply map f clist1 rest)))
e9680547 497
c6424115
KR
498;; OPTIMIZE-ME: Re-use cons cells of list1
499(define map! map)
e9680547
MG
500
501(define (pair-for-each f clist1 . rest)
502 (if (null? rest)
503 (let lp ((l clist1))
504 (if (null? l)
505 (if #f #f)
506 (begin
507 (f l)
508 (lp (cdr l)))))
509 (let lp ((l (cons clist1 rest)))
510 (if (any1 null? l)
511 (if #f #f)
512 (begin
513 (apply f l)
cef248dd 514 (lp (map1 cdr l)))))))
e9680547 515
dcde4386 516\f
e9680547
MG
517;;; Searching
518
dcde4386
LC
519(define (take-while pred ls)
520 "Return a new list which is the longest initial prefix of LS whose
521elements all satisfy the predicate PRED."
522 (cond ((null? ls) '())
523 ((not (pred (car ls))) '())
524 (else
525 (let ((result (list (car ls))))
526 (let lp ((ls (cdr ls)) (p result))
527 (cond ((null? ls) result)
528 ((not (pred (car ls))) result)
529 (else
530 (set-cdr! p (list (car ls)))
531 (lp (cdr ls) (cdr p)))))))))
532
533(define (take-while! pred lst)
534 "Linear-update variant of `take-while'."
535 (let loop ((prev #f)
536 (rest lst))
537 (cond ((null? rest)
538 lst)
539 ((pred (car rest))
540 (loop rest (cdr rest)))
541 (else
542 (if (pair? prev)
543 (begin
544 (set-cdr! prev '())
545 lst)
546 '())))))
547
548(define (drop-while pred lst)
549 "Drop the longest initial prefix of LST whose elements all satisfy the
550predicate PRED."
551 (let loop ((lst lst))
552 (cond ((null? lst)
553 '())
554 ((pred (car lst))
555 (loop (cdr lst)))
556 (else lst))))
557
558(define (span pred lst)
559 "Return two values, the longest initial prefix of LST whose elements
560all satisfy the predicate PRED, and the remainder of LST."
561 (let lp ((lst lst) (rl '()))
562 (if (and (not (null? lst))
563 (pred (car lst)))
564 (lp (cdr lst) (cons (car lst) rl))
565 (values (reverse! rl) lst))))
566
567(define (span! pred list)
568 "Linear-update variant of `span'."
569 (let loop ((prev #f)
570 (rest list))
571 (cond ((null? rest)
572 (values list '()))
573 ((pred (car rest))
574 (loop rest (cdr rest)))
575 (else
576 (if (pair? prev)
577 (begin
578 (set-cdr! prev '())
579 (values list rest))
580 (values '() list))))))
581
b86d2309
LC
582(define (break pred clist)
583 "Return two values, the longest initial prefix of LST whose elements
584all fail the predicate PRED, and the remainder of LST."
585 (let lp ((clist clist) (rl '()))
586 (if (or (null? clist)
587 (pred (car clist)))
588 (values (reverse! rl) clist)
589 (lp (cdr clist) (cons (car clist) rl)))))
590
591(define (break! pred list)
592 "Linear-update variant of `break'."
593 (let loop ((l list)
594 (prev #f))
595 (cond ((null? l)
596 (values list '()))
597 ((pred (car l))
598 (if (pair? prev)
599 (begin
600 (set-cdr! prev '())
601 (values list l))
602 (values '() list)))
603 (else
604 (loop (cdr l) l)))))
605
e9680547
MG
606(define (any pred ls . lists)
607 (if (null? lists)
608 (any1 pred ls)
609 (let lp ((lists (cons ls lists)))
610 (cond ((any1 null? lists)
611 #f)
cef248dd
MG
612 ((any1 null? (map1 cdr lists))
613 (apply pred (map1 car lists)))
e9680547 614 (else
cef248dd 615 (or (apply pred (map1 car lists)) (lp (map1 cdr lists))))))))
e9680547
MG
616
617(define (any1 pred ls)
618 (let lp ((ls ls))
619 (cond ((null? ls)
620 #f)
621 ((null? (cdr ls))
622 (pred (car ls)))
623 (else
624 (or (pred (car ls)) (lp (cdr ls)))))))
625
626(define (every pred ls . lists)
627 (if (null? lists)
628 (every1 pred ls)
629 (let lp ((lists (cons ls lists)))
630 (cond ((any1 null? lists)
631 #t)
cef248dd
MG
632 ((any1 null? (map1 cdr lists))
633 (apply pred (map1 car lists)))
e9680547 634 (else
cef248dd 635 (and (apply pred (map1 car lists)) (lp (map1 cdr lists))))))))
e9680547
MG
636
637(define (every1 pred ls)
638 (let lp ((ls ls))
639 (cond ((null? ls)
640 #t)
641 ((null? (cdr ls))
642 (pred (car ls)))
643 (else
644 (and (pred (car ls)) (lp (cdr ls)))))))
645
0b7f2eb8
LC
646(define (list-index pred clist1 . rest)
647 "Return the index of the first set of elements, one from each of
648CLIST1 ... CLISTN, that satisfies PRED."
649 (if (null? rest)
650 (let lp ((l clist1) (i 0))
651 (if (null? l)
652 #f
653 (if (pred (car l))
654 i
655 (lp (cdr l) (+ i 1)))))
656 (let lp ((lists (cons clist1 rest)) (i 0))
657 (cond ((any1 null? lists)
658 #f)
659 ((apply pred (map1 car lists)) i)
660 (else
661 (lp (map1 cdr lists) (+ i 1)))))))
662
e9680547
MG
663;;; Association lists
664
0b5adedd 665(define alist-cons acons)
e9680547 666
2cf7ff2e
LC
667(define* (alist-delete key alist #:optional (k= equal?))
668 (let lp ((a alist) (rl '()))
669 (if (null? a)
49ae1e25 670 (reverse! rl)
41ab236c 671 (if (k= key (caar a))
2cf7ff2e
LC
672 (lp (cdr a) rl)
673 (lp (cdr a) (cons (car a) rl))))))
e9680547 674
2cf7ff2e
LC
675(define* (alist-delete! key alist #:optional (k= equal?))
676 (alist-delete key alist k=)) ; XXX:optimize
e9680547
MG
677
678;;; Set operations on lists
679
680(define (lset<= = . rest)
681 (if (null? rest)
682 #t
683 (let lp ((f (car rest)) (r (cdr rest)))
684 (or (null? r)
685 (and (every (lambda (el) (member el (car r) =)) f)
686 (lp (car r) (cdr r)))))))
687
9d494a73 688(define (lset= = . rest)
e9680547
MG
689 (if (null? rest)
690 #t
9d494a73 691 (let lp ((f (car rest)) (r (cdr rest)))
e9680547
MG
692 (or (null? r)
693 (and (every (lambda (el) (member el (car r) =)) f)
600af2ed 694 (every (lambda (el) (member el f (lambda (x y) (= y x)))) (car r))
e9680547
MG
695 (lp (car r) (cdr r)))))))
696
dcde4386
LC
697;; It's not quite clear if duplicates among the `rest' elements are meant to
698;; be cast out. The spec says `=' is called as (= lstelem restelem),
699;; suggesting perhaps not, but the reference implementation shows the "list"
700;; at each stage as including those elements already added. The latter
701;; corresponds to what's described for lset-union, so that's what's done.
702;;
703(define (lset-adjoin = list . rest)
704 "Add to LIST any of the elements of REST not already in the list.
705These elements are `cons'ed onto the start of LIST (so the return shares
706a common tail with LIST), but the order they're added is unspecified.
707
708The given `=' procedure is used for comparing elements, called
709as `(@var{=} listelem elem)', i.e., the second argument is one of the
710given REST parameters."
711 (let lp ((l rest) (acc list))
712 (if (null? l)
713 acc
714 (if (member (car l) acc (lambda (x y) (= y x)))
715 (lp (cdr l) acc)
716 (lp (cdr l) (cons (car l) acc))))))
717
e9680547 718(define (lset-union = . rest)
62a87500
KR
719 (let ((acc '()))
720 (for-each (lambda (lst)
721 (if (null? acc)
722 (set! acc lst)
723 (for-each (lambda (elem)
724 (if (not (member elem acc
725 (lambda (x y) (= y x))))
726 (set! acc (cons elem acc))))
727 lst)))
728 rest)
729 acc))
e9680547
MG
730
731(define (lset-intersection = list1 . rest)
732 (let lp ((l list1) (acc '()))
733 (if (null? l)
734 (reverse! acc)
735 (if (every (lambda (ll) (member (car l) ll =)) rest)
736 (lp (cdr l) (cons (car l) acc))
737 (lp (cdr l) acc)))))
738
739(define (lset-difference = list1 . rest)
740 (if (null? rest)
741 list1
742 (let lp ((l list1) (acc '()))
743 (if (null? l)
744 (reverse! acc)
745 (if (any (lambda (ll) (member (car l) ll =)) rest)
746 (lp (cdr l) acc)
747 (lp (cdr l) (cons (car l) acc)))))))
748
749;(define (fold kons knil list1 . rest)
750
751(define (lset-xor = . rest)
752 (fold (lambda (lst res)
753 (let lp ((l lst) (acc '()))
754 (if (null? l)
755 (let lp0 ((r res) (acc acc))
756 (if (null? r)
757 (reverse! acc)
758 (if (member (car r) lst =)
759 (lp0 (cdr r) acc)
760 (lp0 (cdr r) (cons (car r) acc)))))
761 (if (member (car l) res =)
762 (lp (cdr l) acc)
763 (lp (cdr l) (cons (car l) acc))))))
764 '()
765 rest))
766
767(define (lset-diff+intersection = list1 . rest)
768 (let lp ((l list1) (accd '()) (acci '()))
769 (if (null? l)
770 (values (reverse! accd) (reverse! acci))
771 (let ((appears (every (lambda (ll) (member (car l) ll =)) rest)))
772 (if appears
773 (lp (cdr l) accd (cons (car l) acci))
774 (lp (cdr l) (cons (car l) accd) acci))))))
775
776
777(define (lset-union! = . rest)
778 (apply lset-union = rest)) ; XXX:optimize
779
780(define (lset-intersection! = list1 . rest)
781 (apply lset-intersection = list1 rest)) ; XXX:optimize
782
e9680547
MG
783(define (lset-xor! = . rest)
784 (apply lset-xor = rest)) ; XXX:optimize
785
786(define (lset-diff+intersection! = list1 . rest)
787 (apply lset-diff+intersection = list1 rest)) ; XXX:optimize
6be07c52
TTN
788
789;;; srfi-1.scm ends here