fix tree-il->scheme test
[bpt/guile.git] / module / srfi / srfi-1.scm
CommitLineData
6be07c52
TTN
1;;; srfi-1.scm --- List Library
2
9e775af3 3;; Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2010, 2011 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 18
9e775af3
AW
19;;; Some parts from the reference implementation, which is
20;;; Copyright (c) 1998, 1999 by Olin Shivers. You may do as you please with
21;;; this code as long as you do not remove this copyright notice or
22;;; hold me liable for its use.
23
e9680547
MG
24;;; Author: Martin Grabmueller <mgrabmue@cs.tu-berlin.de>
25;;; Date: 2001-06-06
26
27;;; Commentary:
28
6be07c52
TTN
29;; This is an implementation of SRFI-1 (List Library).
30;;
31;; All procedures defined in SRFI-1, which are not already defined in
32;; the Guile core library, are exported. The procedures in this
33;; implementation work, but they have not been tuned for speed or
34;; memory usage.
35;;
36;; This module is fully documented in the Guile Reference Manual.
e9680547
MG
37
38;;; Code:
39
40(define-module (srfi srfi-1)
f595ccfe 41 :export (
e9680547
MG
42;;; Constructors
43 ;; cons <= in the core
44 ;; list <= in the core
45 xcons
46 ;; cons* <= in the core
47 ;; make-list <= in the core
48 list-tabulate
d61261f0 49 list-copy
e9680547 50 circular-list
f595ccfe 51 ;; iota ; Extended.
e9680547
MG
52
53;;; Predicates
54 proper-list?
55 circular-list?
56 dotted-list?
57 ;; pair? <= in the core
58 ;; null? <= in the core
59 null-list?
60 not-pair?
61 list=
62
63;;; Selectors
64 ;; car <= in the core
65 ;; cdr <= in the core
66 ;; caar <= in the core
67 ;; cadr <= in the core
68 ;; cdar <= in the core
2a326497 69 ;; cddr <= in the core
e9680547
MG
70 ;; caaar <= in the core
71 ;; caadr <= in the core
72 ;; cadar <= in the core
73 ;; caddr <= in the core
74 ;; cdaar <= in the core
75 ;; cdadr <= in the core
76 ;; cddar <= in the core
77 ;; cdddr <= in the core
78 ;; caaaar <= in the core
79 ;; caaadr <= in the core
80 ;; caadar <= in the core
81 ;; caaddr <= in the core
82 ;; cadaar <= in the core
83 ;; cadadr <= in the core
84 ;; caddar <= in the core
85 ;; cadddr <= in the core
86 ;; cdaaar <= in the core
87 ;; cdaadr <= in the core
88 ;; cdadar <= in the core
89 ;; cdaddr <= in the core
90 ;; cddaar <= in the core
91 ;; cddadr <= in the core
92 ;; cdddar <= in the core
93 ;; cddddr <= in the core
94 ;; list-ref <= in the core
95 first
96 second
97 third
98 fourth
99 fifth
100 sixth
101 seventh
102 eighth
103 ninth
104 tenth
105 car+cdr
106 take
107 drop
108 take-right
109 drop-right
110 take!
111 drop-right!
112 split-at
113 split-at!
114 last
115 ;; last-pair <= in the core
116
117;;; Miscelleneous: length, append, concatenate, reverse, zip & count
118 ;; length <= in the core
119 length+
120 ;; append <= in the core
121 ;; append! <= in the core
122 concatenate
123 concatenate!
124 ;; reverse <= in the core
125 ;; reverse! <= in the core
126 append-reverse
127 append-reverse!
128 zip
129 unzip1
130 unzip2
131 unzip3
132 unzip4
133 unzip5
134 count
135
136;;; Fold, unfold & map
137 fold
138 fold-right
139 pair-fold
140 pair-fold-right
141 reduce
142 reduce-right
143 unfold
144 unfold-right
f595ccfe
MD
145 ;; map ; Extended.
146 ;; for-each ; Extended.
e9680547
MG
147 append-map
148 append-map!
149 map!
f595ccfe 150 ;; map-in-order ; Extended.
e9680547
MG
151 pair-for-each
152 filter-map
153
154;;; Filtering & partitioning
c614a00b 155 ;; filter <= in the core
e9680547
MG
156 partition
157 remove
c614a00b 158 ;; filter! <= in the core
e9680547
MG
159 partition!
160 remove!
161
162;;; Searching
163 find
164 find-tail
165 take-while
166 take-while!
167 drop-while
168 span
169 span!
170 break
171 break!
172 any
173 every
f595ccfe
MD
174 ;; list-index ; Extended.
175 ;; member ; Extended.
e9680547
MG
176 ;; memq <= in the core
177 ;; memv <= in the core
178
179;;; Deletion
f595ccfe
MD
180 ;; delete ; Extended.
181 ;; delete! ; Extended.
e9680547
MG
182 delete-duplicates
183 delete-duplicates!
184
185;;; Association lists
f595ccfe 186 ;; assoc ; Extended.
e9680547
MG
187 ;; assq <= in the core
188 ;; assv <= in the core
189 alist-cons
190 alist-copy
191 alist-delete
192 alist-delete!
193
194;;; Set operations on lists
195 lset<=
196 lset=
197 lset-adjoin
198 lset-union
199 lset-intersection
200 lset-difference
201 lset-xor
202 lset-diff+intersection
203 lset-union!
204 lset-intersection!
205 lset-difference!
206 lset-xor!
207 lset-diff+intersection!
208
209;;; Primitive side-effects
210 ;; set-car! <= in the core
211 ;; set-cdr! <= in the core
212 )
d61261f0 213 :re-export (cons list cons* make-list pair? null?
b8b0abf0
MD
214 car cdr caar cadr cdar cddr
215 caaar caadr cadar caddr cdaar cdadr cddar cdddr
216 caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr
217 cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr
218 list-ref last-pair length append append! reverse reverse!
219 filter filter! memq memv assq assv set-car! set-cdr!)
d61261f0 220 :replace (iota map for-each map-in-order list-copy list-index member
f595ccfe
MD
221 delete delete! assoc)
222 )
e9680547
MG
223
224(cond-expand-provide (current-module) '(srfi-1))
225
ee6aac97
MD
226;; Load the compiled primitives from the shared library.
227;;
37710f7e
AW
228(load-extension (string-append "libguile-" (effective-version))
229 "scm_init_srfi_1")
ee6aac97
MD
230
231
e9680547
MG
232;;; Constructors
233
0b7f2eb8
LC
234(define (xcons d a)
235 "Like `cons', but with interchanged arguments. Useful mostly when passed to
236higher-order procedures."
237 (cons a d))
238
5753f02f
GH
239;; internal helper, similar to (scsh utilities) check-arg.
240(define (check-arg-type pred arg caller)
241 (if (pred arg)
242 arg
243 (scm-error 'wrong-type-arg caller
244 "Wrong type argument: ~S" (list arg) '())))
245
7f593bc7
LC
246(define (out-of-range proc arg)
247 (scm-error 'out-of-range proc
248 "Value out of range: ~A" (list arg) (list arg)))
249
5753f02f
GH
250;; the srfi spec doesn't seem to forbid inexact integers.
251(define (non-negative-integer? x) (and (integer? x) (>= x 0)))
252
0b7f2eb8
LC
253(define (list-tabulate n init-proc)
254 "Return an N-element list, where each list element is produced by applying the
255procedure INIT-PROC to the corresponding list index. The order in which
256INIT-PROC is applied to the indices is not specified."
257 (check-arg-type non-negative-integer? n "list-tabulate")
258 (let lp ((n n) (acc '()))
259 (if (<= n 0)
260 acc
261 (lp (- n 1) (cons (init-proc (- n 1)) acc)))))
e9680547 262
2d411b05
KR
263(define (circular-list elt1 . elts)
264 (set! elts (cons elt1 elts))
265 (set-cdr! (last-pair elts) elts)
266 elts)
e9680547 267
2cf7ff2e 268(define* (iota count #:optional (start 0) (step 1))
5753f02f 269 (check-arg-type non-negative-integer? count "iota")
2cf7ff2e
LC
270 (let lp ((n 0) (acc '()))
271 (if (= n count)
e9680547 272 (reverse! acc)
2cf7ff2e 273 (lp (+ n 1) (cons (+ start (* n step)) acc)))))
e9680547
MG
274
275;;; Predicates
276
277(define (proper-list? x)
278 (list? x))
279
280(define (circular-list? x)
281 (if (not-pair? x)
282 #f
283 (let lp ((hare (cdr x)) (tortoise x))
284 (if (not-pair? hare)
285 #f
286 (let ((hare (cdr hare)))
287 (if (not-pair? hare)
288 #f
289 (if (eq? hare tortoise)
290 #t
291 (lp (cdr hare) (cdr tortoise)))))))))
292
293(define (dotted-list? x)
294 (cond
295 ((null? x) #f)
296 ((not-pair? x) #t)
297 (else
298 (let lp ((hare (cdr x)) (tortoise x))
299 (cond
300 ((null? hare) #f)
301 ((not-pair? hare) #t)
302 (else
303 (let ((hare (cdr hare)))
513a3bd7 304 (cond
e9680547
MG
305 ((null? hare) #f)
306 ((not-pair? hare) #t)
307 ((eq? hare tortoise) #f)
308 (else
309 (lp (cdr hare) (cdr tortoise)))))))))))
310
311(define (null-list? x)
312 (cond
513a3bd7 313 ((proper-list? x)
e9680547
MG
314 (null? x))
315 ((circular-list? x)
316 #f)
317 (else
318 (error "not a proper list in null-list?"))))
319
0b7f2eb8
LC
320(define (not-pair? x)
321 "Return #t if X is not a pair, #f otherwise.
322
323This is shorthand notation `(not (pair? X))' and is supposed to be used for
324end-of-list checking in contexts where dotted lists are allowed."
325 (not (pair? x)))
326
e9680547
MG
327(define (list= elt= . rest)
328 (define (lists-equal a b)
329 (let lp ((a a) (b b))
330 (cond ((null? a)
331 (null? b))
332 ((null? b)
333 #f)
334 (else
335 (and (elt= (car a) (car b))
336 (lp (cdr a) (cdr b)))))))
337 (or (null? rest)
1bc8745f
KR
338 (let lp ((lists rest))
339 (or (null? (cdr lists))
340 (and (lists-equal (car lists) (cadr lists))
341 (lp (cdr lists)))))))
e9680547
MG
342
343;;; Selectors
344
345(define first car)
346(define second cadr)
347(define third caddr)
348(define fourth cadddr)
d7418e60
LC
349(define (fifth x) (car (cddddr x)))
350(define (sixth x) (cadr (cddddr x)))
351(define (seventh x) (caddr (cddddr x)))
352(define (eighth x) (cadddr (cddddr x)))
353(define (ninth x) (car (cddddr (cddddr x))))
354(define (tenth x) (cadr (cddddr (cddddr x))))
e9680547 355
0b7f2eb8
LC
356(define (car+cdr x)
357 "Return two values, the `car' and the `cdr' of PAIR."
358 (values (car x) (cdr x)))
359
4dd6bd84
KR
360(define take list-head)
361(define drop list-tail)
362
dcde4386
LC
363(define (take! lst i)
364 "Linear-update variant of `take'."
365 (if (= i 0)
366 '()
367 (let ((tail (drop lst (- i 1))))
368 (set-cdr! tail '())
369 lst)))
370
371(define (drop-right! lst i)
372 "Linear-update variant of `drop-right'."
373 (let ((tail (drop lst i)))
374 (if (null? tail)
375 '()
376 (let loop ((prev lst)
377 (tail (cdr tail)))
378 (if (null? tail)
379 (if (pair? prev)
380 (begin
381 (set-cdr! prev '())
382 lst)
383 lst)
384 (loop (cdr prev)
385 (cdr tail)))))))
386
7f593bc7
LC
387(define (split-at lst i)
388 "Return two values, a list of the elements before index I in LST, and
389a list of those after."
390 (if (< i 0)
391 (out-of-range 'split-at i)
392 (let lp ((l lst) (n i) (acc '()))
393 (if (<= n 0)
394 (values (reverse! acc) l)
395 (lp (cdr l) (- n 1) (cons (car l) acc))))))
396
397(define (split-at! lst i)
398 "Linear-update variant of `split-at'."
399 (cond ((< i 0)
400 (out-of-range 'split-at! i))
401 ((= i 0)
402 (values '() lst))
403 (else
404 (let lp ((l lst) (n (- i 1)))
405 (if (<= n 0)
406 (let ((tmp (cdr l)))
407 (set-cdr! l '())
408 (values lst tmp))
409 (lp (cdr l) (- n 1)))))))
410
0b7f2eb8
LC
411(define (last pair)
412 "Return the last element of the non-empty, finite list PAIR."
413 (car (last-pair pair)))
414
e9680547
MG
415;;; Miscelleneous: length, append, concatenate, reverse, zip & count
416
e9680547
MG
417(define (zip clist1 . rest)
418 (let lp ((l (cons clist1 rest)) (acc '()))
419 (if (any null? l)
420 (reverse! acc)
a2230b65 421 (lp (map cdr l) (cons (map car l) acc)))))
513a3bd7 422
e9680547
MG
423
424(define (unzip1 l)
a2230b65 425 (map first l))
e9680547 426(define (unzip2 l)
a2230b65 427 (values (map first l) (map second l)))
e9680547 428(define (unzip3 l)
a2230b65 429 (values (map first l) (map second l) (map third l)))
e9680547 430(define (unzip4 l)
a2230b65 431 (values (map first l) (map second l) (map third l) (map fourth l)))
e9680547 432(define (unzip5 l)
a2230b65
AW
433 (values (map first l) (map second l) (map third l) (map fourth l)
434 (map fifth l)))
e9680547 435
e9680547
MG
436;;; Fold, unfold & map
437
0b7f2eb8
LC
438(define (fold kons knil list1 . rest)
439 "Apply PROC to the elements of LIST1 ... LISTN to build a result, and return
440that result. See the manual for details."
441 (if (null? rest)
442 (let f ((knil knil) (list1 list1))
443 (if (null? list1)
444 knil
445 (f (kons (car list1) knil) (cdr list1))))
446 (let f ((knil knil) (lists (cons list1 rest)))
447 (if (any null? lists)
448 knil
a2230b65
AW
449 (let ((cars (map car lists))
450 (cdrs (map cdr lists)))
0b7f2eb8
LC
451 (f (apply kons (append! cars (list knil))) cdrs))))))
452
e9680547
MG
453(define (fold-right kons knil clist1 . rest)
454 (if (null? rest)
a6505cb4
LC
455 (let loop ((lst (reverse clist1))
456 (result knil))
457 (if (null? lst)
458 result
459 (loop (cdr lst)
460 (kons (car lst) result))))
a2230b65 461 (let loop ((lists (map reverse (cons clist1 rest)))
a6505cb4
LC
462 (result knil))
463 (if (any1 null? lists)
464 result
a2230b65
AW
465 (loop (map cdr lists)
466 (apply kons (append! (map car lists) (list result))))))))
e9680547
MG
467
468(define (pair-fold kons knil clist1 . rest)
469 (if (null? rest)
470 (let f ((knil knil) (list1 clist1))
471 (if (null? list1)
472 knil
473 (let ((tail (cdr list1)))
474 (f (kons list1 knil) tail))))
475 (let f ((knil knil) (lists (cons clist1 rest)))
476 (if (any null? lists)
477 knil
a2230b65 478 (let ((tails (map cdr lists)))
563058ef 479 (f (apply kons (append! lists (list knil))) tails))))))
e9680547
MG
480
481
482(define (pair-fold-right kons knil clist1 . rest)
483 (if (null? rest)
484 (let f ((list1 clist1))
485 (if (null? list1)
486 knil
487 (kons list1 (f (cdr list1)))))
488 (let f ((lists (cons clist1 rest)))
489 (if (any null? lists)
490 knil
a2230b65 491 (apply kons (append! lists (list (f (map cdr lists)))))))))
e9680547 492
2cf7ff2e 493(define* (unfold p f g seed #:optional (tail-gen (lambda (x) '())))
07076c1e
LC
494 (define (reverse+tail lst seed)
495 (let loop ((lst lst)
496 (result (tail-gen seed)))
497 (if (null? lst)
498 result
499 (loop (cdr lst)
500 (cons (car lst) result)))))
501
502 (let loop ((seed seed)
503 (result '()))
2cf7ff2e 504 (if (p seed)
07076c1e
LC
505 (reverse+tail result seed)
506 (loop (g seed)
507 (cons (f seed) result)))))
2cf7ff2e
LC
508
509(define* (unfold-right p f g seed #:optional (tail '()))
510 (let uf ((seed seed) (lis tail))
511 (if (p seed)
512 lis
513 (uf (g seed) (cons (f seed) lis)))))
e9680547 514
dcde4386
LC
515(define (reduce f ridentity lst)
516 "`reduce' is a variant of `fold', where the first call to F is on two
517elements from LST, rather than one element and a given initial value.
518If LST is empty, RIDENTITY is returned. If LST has just one element
519then that's the return value."
520 (if (null? lst)
521 ridentity
522 (fold f (car lst) (cdr lst))))
523
524(define (reduce-right f ridentity lst)
525 "`reduce-right' is a variant of `fold-right', where the first call to
526F is on two elements from LST, rather than one element and a given
527initial value. If LST is empty, RIDENTITY is returned. If LST
528has just one element then that's the return value."
529 (if (null? lst)
530 ridentity
531 (fold-right f (last lst) (drop-right lst 1))))
532
a2230b65
AW
533(define map
534 (case-lambda
535 ((f l)
536 (let map1 ((hare l) (tortoise l) (move? #f) (out '()))
537 (if (pair? hare)
538 (if move?
539 (if (eq? tortoise hare)
540 (scm-error 'wrong-type-arg "map" "Circular list: ~S"
541 (list l) #f)
542 (map1 (cdr hare) (cdr tortoise) #f
543 (cons (f (car hare)) out)))
544 (map1 (cdr hare) tortoise #t
545 (cons (f (car hare)) out)))
546 (if (null? hare)
547 (reverse! out)
548 (scm-error 'wrong-type-arg "map" "Not a list: ~S"
549 (list l) #f)))))
550
551 ((f l1 . rest)
552 (let ((len (fold (lambda (ls len)
553 (let ((ls-len (length+ ls)))
554 (if len
555 (if ls-len (min ls-len len) len)
556 ls-len)))
557 (length+ l1)
558 rest)))
559 (if (not len)
560 (scm-error 'wrong-type-arg "map"
561 "Args do not contain a proper (finite) list: ~S"
562 (list (cons l1 rest)) #f))
563 (let mapn ((l1 l1) (rest rest) (len len) (out '()))
564 (if (zero? len)
565 (reverse! out)
566 (mapn (cdr l1) (map cdr rest) (1- len)
567 (cons (apply f (car l1) (map car rest)) out))))))))
568
b706a011
AW
569(define map-in-order map)
570
a2230b65
AW
571(define for-each
572 (case-lambda
573 ((f l)
574 (let for-each1 ((hare l) (tortoise l) (move? #f))
575 (if (pair? hare)
576 (if move?
577 (if (eq? tortoise hare)
578 (scm-error 'wrong-type-arg "for-each" "Circular list: ~S"
579 (list l) #f)
580 (begin
581 (f (car hare))
582 (for-each1 (cdr hare) (cdr tortoise) #f)))
583 (begin
584 (f (car hare))
585 (for-each1 (cdr hare) tortoise #t)))
586
587 (if (not (null? hare))
588 (scm-error 'wrong-type-arg "for-each" "Not a list: ~S"
589 (list l) #f)))))
590
591 ((f l1 . rest)
592 (let ((len (fold (lambda (ls len)
593 (let ((ls-len (length+ ls)))
594 (if len
595 (if ls-len (min ls-len len) len)
596 ls-len)))
597 (length+ l1)
598 rest)))
599 (if (not len)
600 (scm-error 'wrong-type-arg "for-each"
601 "Args do not contain a proper (finite) list: ~S"
602 (list (cons l1 rest)) #f))
603 (let for-eachn ((l1 l1) (rest rest) (len len))
604 (if (> len 0)
605 (begin
606 (apply f (car l1) (map car rest))
607 (for-eachn (cdr l1) (map cdr rest) (1- len)))))))))
cef248dd 608
e9680547 609(define (append-map f clist1 . rest)
8b981efd 610 (concatenate (apply map f clist1 rest)))
558d5c03 611
e9680547 612(define (append-map! f clist1 . rest)
8b981efd 613 (concatenate! (apply map f clist1 rest)))
e9680547 614
c6424115
KR
615;; OPTIMIZE-ME: Re-use cons cells of list1
616(define map! map)
e9680547 617
58ee1bea
LC
618(define (filter-map proc list1 . rest)
619 "Apply PROC to to the elements of LIST1... and return a list of the
620results as per SRFI-1 `map', except that any #f results are omitted from
621the list returned."
622 (if (null? rest)
623 (let lp ((l list1)
624 (rl '()))
625 (if (null? l)
626 (reverse! rl)
627 (let ((res (proc (car l))))
628 (if res
629 (lp (cdr l) (cons res rl))
630 (lp (cdr l) rl)))))
631 (let lp ((l (cons list1 rest))
632 (rl '()))
633 (if (any1 null? l)
634 (reverse! rl)
a2230b65 635 (let ((res (apply proc (map car l))))
58ee1bea 636 (if res
a2230b65
AW
637 (lp (map cdr l) (cons res rl))
638 (lp (map cdr l) rl)))))))
58ee1bea 639
e9680547
MG
640(define (pair-for-each f clist1 . rest)
641 (if (null? rest)
642 (let lp ((l clist1))
643 (if (null? l)
644 (if #f #f)
645 (begin
646 (f l)
647 (lp (cdr l)))))
648 (let lp ((l (cons clist1 rest)))
649 (if (any1 null? l)
650 (if #f #f)
651 (begin
652 (apply f l)
a2230b65 653 (lp (map cdr l)))))))
e9680547 654
dcde4386 655\f
e9680547
MG
656;;; Searching
657
dcde4386
LC
658(define (take-while pred ls)
659 "Return a new list which is the longest initial prefix of LS whose
660elements all satisfy the predicate PRED."
661 (cond ((null? ls) '())
662 ((not (pred (car ls))) '())
663 (else
664 (let ((result (list (car ls))))
665 (let lp ((ls (cdr ls)) (p result))
666 (cond ((null? ls) result)
667 ((not (pred (car ls))) result)
668 (else
669 (set-cdr! p (list (car ls)))
670 (lp (cdr ls) (cdr p)))))))))
671
672(define (take-while! pred lst)
673 "Linear-update variant of `take-while'."
674 (let loop ((prev #f)
675 (rest lst))
676 (cond ((null? rest)
677 lst)
678 ((pred (car rest))
679 (loop rest (cdr rest)))
680 (else
681 (if (pair? prev)
682 (begin
683 (set-cdr! prev '())
684 lst)
685 '())))))
686
687(define (drop-while pred lst)
688 "Drop the longest initial prefix of LST whose elements all satisfy the
689predicate PRED."
690 (let loop ((lst lst))
691 (cond ((null? lst)
692 '())
693 ((pred (car lst))
694 (loop (cdr lst)))
695 (else lst))))
696
697(define (span pred lst)
698 "Return two values, the longest initial prefix of LST whose elements
699all satisfy the predicate PRED, and the remainder of LST."
700 (let lp ((lst lst) (rl '()))
701 (if (and (not (null? lst))
702 (pred (car lst)))
703 (lp (cdr lst) (cons (car lst) rl))
704 (values (reverse! rl) lst))))
705
706(define (span! pred list)
707 "Linear-update variant of `span'."
708 (let loop ((prev #f)
709 (rest list))
710 (cond ((null? rest)
711 (values list '()))
712 ((pred (car rest))
713 (loop rest (cdr rest)))
714 (else
715 (if (pair? prev)
716 (begin
717 (set-cdr! prev '())
718 (values list rest))
719 (values '() list))))))
720
b86d2309
LC
721(define (break pred clist)
722 "Return two values, the longest initial prefix of LST whose elements
723all fail the predicate PRED, and the remainder of LST."
724 (let lp ((clist clist) (rl '()))
725 (if (or (null? clist)
726 (pred (car clist)))
727 (values (reverse! rl) clist)
728 (lp (cdr clist) (cons (car clist) rl)))))
729
730(define (break! pred list)
731 "Linear-update variant of `break'."
732 (let loop ((l list)
733 (prev #f))
734 (cond ((null? l)
735 (values list '()))
736 ((pred (car l))
737 (if (pair? prev)
738 (begin
739 (set-cdr! prev '())
740 (values list l))
741 (values '() list)))
742 (else
743 (loop (cdr l) l)))))
744
e9680547
MG
745(define (any pred ls . lists)
746 (if (null? lists)
747 (any1 pred ls)
748 (let lp ((lists (cons ls lists)))
749 (cond ((any1 null? lists)
750 #f)
a2230b65
AW
751 ((any1 null? (map cdr lists))
752 (apply pred (map car lists)))
e9680547 753 (else
a2230b65 754 (or (apply pred (map car lists)) (lp (map cdr lists))))))))
e9680547
MG
755
756(define (any1 pred ls)
757 (let lp ((ls ls))
758 (cond ((null? ls)
759 #f)
760 ((null? (cdr ls))
761 (pred (car ls)))
762 (else
763 (or (pred (car ls)) (lp (cdr ls)))))))
764
765(define (every pred ls . lists)
766 (if (null? lists)
767 (every1 pred ls)
768 (let lp ((lists (cons ls lists)))
769 (cond ((any1 null? lists)
770 #t)
a2230b65
AW
771 ((any1 null? (map cdr lists))
772 (apply pred (map car lists)))
e9680547 773 (else
a2230b65 774 (and (apply pred (map car lists)) (lp (map cdr lists))))))))
e9680547
MG
775
776(define (every1 pred ls)
777 (let lp ((ls ls))
778 (cond ((null? ls)
779 #t)
780 ((null? (cdr ls))
781 (pred (car ls)))
782 (else
783 (and (pred (car ls)) (lp (cdr ls)))))))
784
0b7f2eb8
LC
785(define (list-index pred clist1 . rest)
786 "Return the index of the first set of elements, one from each of
787CLIST1 ... CLISTN, that satisfies PRED."
788 (if (null? rest)
789 (let lp ((l clist1) (i 0))
790 (if (null? l)
791 #f
792 (if (pred (car l))
793 i
794 (lp (cdr l) (+ i 1)))))
795 (let lp ((lists (cons clist1 rest)) (i 0))
796 (cond ((any1 null? lists)
797 #f)
a2230b65 798 ((apply pred (map car lists)) i)
0b7f2eb8 799 (else
a2230b65 800 (lp (map cdr lists) (+ i 1)))))))
0b7f2eb8 801
e9680547
MG
802;;; Association lists
803
0b5adedd 804(define alist-cons acons)
e9680547 805
194865d2
LC
806(define (alist-copy alist)
807 "Return a copy of ALIST, copying both the pairs comprising the list
808and those making the associations."
809 (let lp ((a alist)
810 (rl '()))
811 (if (null? a)
812 (reverse! rl)
813 (lp (cdr a) (alist-cons (caar a) (cdar a) rl)))))
814
2cf7ff2e
LC
815(define* (alist-delete key alist #:optional (k= equal?))
816 (let lp ((a alist) (rl '()))
817 (if (null? a)
49ae1e25 818 (reverse! rl)
41ab236c 819 (if (k= key (caar a))
2cf7ff2e
LC
820 (lp (cdr a) rl)
821 (lp (cdr a) (cons (car a) rl))))))
e9680547 822
2cf7ff2e
LC
823(define* (alist-delete! key alist #:optional (k= equal?))
824 (alist-delete key alist k=)) ; XXX:optimize
e9680547 825
9e775af3
AW
826;;; Delete / assoc / member
827
828(define* (member x ls #:optional (= equal?))
829 (cond
830 ((eq? = eq?) (memq x ls))
831 ((eq? = eqv?) (memv x ls))
832 (else (find-tail (lambda (y) (= x y)) ls))))
833
e9680547
MG
834;;; Set operations on lists
835
836(define (lset<= = . rest)
837 (if (null? rest)
9e775af3
AW
838 #t
839 (let lp ((f (car rest)) (r (cdr rest)))
840 (or (null? r)
841 (and (every (lambda (el) (member el (car r) =)) f)
842 (lp (car r) (cdr r)))))))
e9680547 843
9d494a73 844(define (lset= = . rest)
e9680547
MG
845 (if (null? rest)
846 #t
9d494a73 847 (let lp ((f (car rest)) (r (cdr rest)))
e9680547
MG
848 (or (null? r)
849 (and (every (lambda (el) (member el (car r) =)) f)
600af2ed 850 (every (lambda (el) (member el f (lambda (x y) (= y x)))) (car r))
e9680547
MG
851 (lp (car r) (cdr r)))))))
852
dcde4386
LC
853;; It's not quite clear if duplicates among the `rest' elements are meant to
854;; be cast out. The spec says `=' is called as (= lstelem restelem),
855;; suggesting perhaps not, but the reference implementation shows the "list"
856;; at each stage as including those elements already added. The latter
857;; corresponds to what's described for lset-union, so that's what's done.
858;;
859(define (lset-adjoin = list . rest)
860 "Add to LIST any of the elements of REST not already in the list.
861These elements are `cons'ed onto the start of LIST (so the return shares
862a common tail with LIST), but the order they're added is unspecified.
863
864The given `=' procedure is used for comparing elements, called
865as `(@var{=} listelem elem)', i.e., the second argument is one of the
866given REST parameters."
9e775af3
AW
867 ;; If `=' is `eq?' or `eqv?', users won't be able to tell which arg is
868 ;; first, so we can pass the raw procedure through to `member',
869 ;; allowing `memq' / `memv' to be selected.
870 (define pred
871 (if (or (eq? = eq?) (eq? = eqv?))
872 =
873 (lambda (x y) (= y x))))
874
875 (let lp ((ans list) (rest rest))
876 (if (null? rest)
877 ans
878 (lp (if (member (car rest) ans pred)
879 ans
880 (cons (car rest) ans))
881 (cdr rest)))))
dcde4386 882
e9680547 883(define (lset-union = . rest)
9e775af3
AW
884 ;; Likewise, allow memq / memv to be used if possible.
885 (define pred
886 (if (or (eq? = eq?) (eq? = eqv?))
887 =
888 (lambda (x y) (= y x))))
889
890 (fold (lambda (lis ans) ; Compute ANS + LIS.
891 (cond ((null? lis) ans) ; Don't copy any lists
892 ((null? ans) lis) ; if we don't have to.
893 ((eq? lis ans) ans)
894 (else
895 (fold (lambda (elt ans)
896 (if (member elt ans pred)
897 ans
898 (cons elt ans)))
899 ans lis))))
900 '()
901 rest))
e9680547
MG
902
903(define (lset-intersection = list1 . rest)
904 (let lp ((l list1) (acc '()))
905 (if (null? l)
906 (reverse! acc)
907 (if (every (lambda (ll) (member (car l) ll =)) rest)
908 (lp (cdr l) (cons (car l) acc))
909 (lp (cdr l) acc)))))
910
911(define (lset-difference = list1 . rest)
912 (if (null? rest)
913 list1
914 (let lp ((l list1) (acc '()))
915 (if (null? l)
916 (reverse! acc)
917 (if (any (lambda (ll) (member (car l) ll =)) rest)
918 (lp (cdr l) acc)
919 (lp (cdr l) (cons (car l) acc)))))))
920
921;(define (fold kons knil list1 . rest)
922
923(define (lset-xor = . rest)
924 (fold (lambda (lst res)
925 (let lp ((l lst) (acc '()))
926 (if (null? l)
927 (let lp0 ((r res) (acc acc))
928 (if (null? r)
929 (reverse! acc)
930 (if (member (car r) lst =)
931 (lp0 (cdr r) acc)
932 (lp0 (cdr r) (cons (car r) acc)))))
933 (if (member (car l) res =)
934 (lp (cdr l) acc)
935 (lp (cdr l) (cons (car l) acc))))))
936 '()
937 rest))
938
939(define (lset-diff+intersection = list1 . rest)
940 (let lp ((l list1) (accd '()) (acci '()))
941 (if (null? l)
942 (values (reverse! accd) (reverse! acci))
943 (let ((appears (every (lambda (ll) (member (car l) ll =)) rest)))
944 (if appears
945 (lp (cdr l) accd (cons (car l) acci))
946 (lp (cdr l) (cons (car l) accd) acci))))))
947
948
949(define (lset-union! = . rest)
950 (apply lset-union = rest)) ; XXX:optimize
951
952(define (lset-intersection! = list1 . rest)
953 (apply lset-intersection = list1 rest)) ; XXX:optimize
954
e9680547
MG
955(define (lset-xor! = . rest)
956 (apply lset-xor = rest)) ; XXX:optimize
957
958(define (lset-diff+intersection! = list1 . rest)
959 (apply lset-diff+intersection = list1 rest)) ; XXX:optimize
6be07c52
TTN
960
961;;; srfi-1.scm ends here