1 ;;; srfi-1.scm --- List Library
3 ;; Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
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
8 ;; version 2.1 of the License, or (at your option) any later version.
10 ;; This library is distributed in the hope that it will be useful,
11 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 ;; Lesser General Public License for more details.
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
17 ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 ;;; Author: Martin Grabmueller <mgrabmue@cs.tu-berlin.de>
24 ;; This is an implementation of SRFI-1 (List Library).
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
31 ;; This module is fully documented in the Guile Reference Manual.
35 (define-module (srfi srfi-1)
36 :use-module (ice-9 session)
37 :use-module (ice-9 receive)
40 ;; cons <= in the core
41 ;; list <= in the core
43 ;; cons* <= in the core
44 ;; make-list <= in the core
46 ;; list-copy <= in the core
54 ;; pair? <= in the core
55 ;; null? <= in the core
63 ;; caar <= in the core
64 ;; cadr <= in the core
65 ;; cdar <= in the core
66 ;; cddr <= in the core
67 ;; caaar <= in the core
68 ;; caadr <= in the core
69 ;; cadar <= in the core
70 ;; caddr <= in the core
71 ;; cdaar <= in the core
72 ;; cdadr <= in the core
73 ;; cddar <= in the core
74 ;; cdddr <= in the core
75 ;; caaaar <= in the core
76 ;; caaadr <= in the core
77 ;; caadar <= in the core
78 ;; caaddr <= in the core
79 ;; cadaar <= in the core
80 ;; cadadr <= in the core
81 ;; caddar <= in the core
82 ;; cadddr <= in the core
83 ;; cdaaar <= in the core
84 ;; cdaadr <= in the core
85 ;; cdadar <= in the core
86 ;; cdaddr <= in the core
87 ;; cddaar <= in the core
88 ;; cddadr <= in the core
89 ;; cdddar <= in the core
90 ;; cddddr <= in the core
91 ;; list-ref <= in the core
112 ;; last-pair <= in the core
114 ;;; Miscelleneous: length, append, concatenate, reverse, zip & count
115 ;; length <= in the core
117 ;; append <= in the core
118 ;; append! <= in the core
121 ;; reverse <= in the core
122 ;; reverse! <= in the core
133 ;;; Fold, unfold & map
143 ;; for-each ; Extended.
147 ;; map-in-order ; Extended.
151 ;;; Filtering & partitioning
152 ;; filter <= in the core
155 ;; filter! <= in the core
171 ;; list-index ; Extended.
172 ;; member ; Extended.
173 ;; memq <= in the core
174 ;; memv <= in the core
177 ;; delete ; Extended.
178 ;; delete! ; Extended.
182 ;;; Association lists
184 ;; assq <= in the core
185 ;; assv <= in the core
191 ;;; Set operations on lists
199 lset-diff+intersection
204 lset-diff+intersection!
206 ;;; Primitive side-effects
207 ;; set-car! <= in the core
208 ;; set-cdr! <= in the core
210 :re-export (cons list cons* make-list list-copy pair? null?
211 car cdr caar cadr cdar cddr
212 caaar caadr cadar caddr cdaar cdadr cddar cdddr
213 caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr
214 cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr
215 list-ref last-pair length append append! reverse reverse!
216 filter filter! memq memv assq assv set-car! set-cdr!)
217 :replace (iota map for-each map-in-order list-index member
218 delete delete! assoc)
221 (cond-expand-provide (current-module) '(srfi-1))
223 ;; Load the compiled primitives from the shared library.
225 (load-extension "libguile-srfi-srfi-1" "scm_init_srfi_1")
233 ;; internal helper, similar to (scsh utilities) check-arg.
234 (define (check-arg-type pred arg caller)
237 (scm-error 'wrong-type-arg caller
238 "Wrong type argument: ~S" (list arg) '())))
240 ;; the srfi spec doesn't seem to forbid inexact integers.
241 (define (non-negative-integer? x) (and (integer? x) (>= x 0)))
243 (define (list-tabulate n init-proc)
244 (check-arg-type non-negative-integer? n "list-tabulate")
245 (let lp ((n n) (acc '()))
248 (lp (- n 1) (cons (init-proc (- n 1)) acc)))))
250 (define (circular-list elt1 . rest)
251 (let ((start (cons elt1 '())))
252 (let lp ((r rest) (p start))
258 (set-cdr! p (cons (car r) '()))
259 (lp (cdr r) (cdr p)))))))
261 (define (iota count . rest)
262 (check-arg-type non-negative-integer? count "iota")
263 (let ((start (if (pair? rest) (car rest) 0))
264 (step (if (and (pair? rest) (pair? (cdr rest))) (cadr rest) 1)))
265 (let lp ((n 0) (acc '()))
268 (lp (+ n 1) (cons (+ start (* n step)) acc))))))
272 (define (proper-list? x)
275 (define (circular-list? x)
278 (let lp ((hare (cdr x)) (tortoise x))
281 (let ((hare (cdr hare)))
284 (if (eq? hare tortoise)
286 (lp (cdr hare) (cdr tortoise)))))))))
288 (define (dotted-list? x)
293 (let lp ((hare (cdr x)) (tortoise x))
296 ((not-pair? hare) #t)
298 (let ((hare (cdr hare)))
301 ((not-pair? hare) #t)
302 ((eq? hare tortoise) #f)
304 (lp (cdr hare) (cdr tortoise)))))))))))
306 (define (null-list? x)
313 (error "not a proper list in null-list?"))))
315 (define (not-pair? x)
318 (define (list= elt= . rest)
319 (define (lists-equal a b)
320 (let lp ((a a) (b b))
326 (and (elt= (car a) (car b))
327 (lp (cdr a) (cdr b)))))))
329 (let ((first (car rest)))
330 (let lp ((lists rest))
332 (and (lists-equal first (car lists))
333 (lp (cdr lists))))))))
340 (define fourth cadddr)
341 (define (fifth x) (car (cddddr x)))
342 (define (sixth x) (cadr (cddddr x)))
343 (define (seventh x) (caddr (cddddr x)))
344 (define (eighth x) (cadddr (cddddr x)))
345 (define (ninth x) (car (cddddr (cddddr x))))
346 (define (tenth x) (cadr (cddddr (cddddr x))))
348 (define (car+cdr x) (values (car x) (cdr x)))
350 (define take list-head)
351 (define drop list-tail)
353 (define (take-right flist i)
354 (let lp ((n i) (l flist))
356 (let lp0 ((s flist) (l l))
359 (lp0 (cdr s) (cdr l))))
360 (lp (- n 1) (cdr l)))))
362 (define (drop-right flist i)
363 (let lp ((n i) (l flist))
365 (let lp0 ((s flist) (l l) (acc '()))
368 (lp0 (cdr s) (cdr l) (cons (car s) acc))))
369 (lp (- n 1) (cdr l)))))
374 (let lp ((n (- i 1)) (l x))
379 (lp (- n 1) (cdr l))))))
381 (define (drop-right! flist i)
384 (let lp ((n (+ i 1)) (l flist))
386 (let lp0 ((s flist) (l l))
391 (lp0 (cdr s) (cdr l))))
394 (lp (- n 1) (cdr l)))))))
396 (define (split-at x i)
397 (let lp ((l x) (n i) (acc '()))
399 (values (reverse! acc) l)
400 (lp (cdr l) (- n 1) (cons (car l) acc)))))
402 (define (split-at! x i)
405 (let lp ((l x) (n (- i 1)))
410 (lp (cdr l) (- n 1))))))
413 (car (last-pair pair)))
415 ;;; Miscelleneous: length, append, concatenate, reverse, zip & count
417 (define (length+ clist)
420 (let lp ((hare (cdr clist)) (tortoise clist) (l 1))
423 (let ((hare (cdr hare)))
426 (if (eq? hare tortoise)
428 (lp (cdr hare) (cdr tortoise) (+ l 2)))))))))
430 (define (concatenate l-o-l)
431 (let lp ((l l-o-l) (acc '()))
434 (let lp0 ((ll (car l)) (acc acc))
437 (lp0 (cdr ll) (cons (car ll) acc)))))))
439 (define (concatenate! l-o-l)
440 (let lp0 ((l-o-l l-o-l))
447 (let ((result (car l-o-l)) (tail (last-pair (car l-o-l))))
448 (let lp ((l (cdr l-o-l)) (ntail tail))
452 (set-cdr! ntail (car l))
453 (lp (cdr l) (last-pair ntail))))))))))
456 (define (append-reverse rev-head tail)
457 (let lp ((l rev-head) (acc tail))
460 (lp (cdr l) (cons (car l) acc)))))
462 (define (append-reverse! rev-head tail)
463 (append-reverse rev-head tail)) ; XXX:optimize
465 (define (zip clist1 . rest)
466 (let lp ((l (cons clist1 rest)) (acc '()))
469 (lp (map1 cdr l) (cons (map1 car l) acc)))))
475 (values (map1 first l) (map1 second l)))
477 (values (map1 first l) (map1 second l) (map1 third l)))
479 (values (map1 first l) (map1 second l) (map1 third l) (map1 fourth l)))
481 (values (map1 first l) (map1 second l) (map1 third l) (map1 fourth l)
484 (define (count pred clist1 . rest)
487 (let lp ((lists (cons clist1 rest)))
488 (cond ((any1 null? lists)
491 (if (apply pred (map1 car lists))
492 (+ 1 (lp (map1 cdr lists)))
493 (lp (map1 cdr lists))))))))
495 (define (count1 pred clist)
496 (let lp ((result 0) (rest clist))
499 (if (pred (car rest))
500 (lp (+ 1 result) (cdr rest))
501 (lp result (cdr rest))))))
503 ;;; Fold, unfold & map
505 (define (fold kons knil list1 . rest)
507 (let f ((knil knil) (list1 list1))
510 (f (kons (car list1) knil) (cdr list1))))
511 (let f ((knil knil) (lists (cons list1 rest)))
512 (if (any null? lists)
514 (let ((cars (map1 car lists))
515 (cdrs (map1 cdr lists)))
516 (f (apply kons (append! cars (list knil))) cdrs))))))
518 (define (fold-right kons knil clist1 . rest)
520 (let f ((list1 clist1))
523 (kons (car list1) (f (cdr list1)))))
524 (let f ((lists (cons clist1 rest)))
525 (if (any null? lists)
527 (apply kons (append! (map1 car lists) (list (f (map1 cdr lists)))))))))
529 (define (pair-fold kons knil clist1 . rest)
531 (let f ((knil knil) (list1 clist1))
534 (let ((tail (cdr list1)))
535 (f (kons list1 knil) tail))))
536 (let f ((knil knil) (lists (cons clist1 rest)))
537 (if (any null? lists)
539 (let ((tails (map1 cdr lists)))
540 (f (apply kons (append! lists (list knil))) tails))))))
543 (define (pair-fold-right kons knil clist1 . rest)
545 (let f ((list1 clist1))
548 (kons list1 (f (cdr list1)))))
549 (let f ((lists (cons clist1 rest)))
550 (if (any null? lists)
552 (apply kons (append! lists (list (f (map1 cdr lists)))))))))
554 (define (unfold p f g seed . rest)
555 (let ((tail-gen (if (pair? rest)
556 (if (pair? (cdr rest))
557 (scm-error 'wrong-number-of-args
558 "unfold" "too many arguments" '() '())
561 (let uf ((seed seed))
567 (define (unfold-right p f g seed . rest)
568 (let ((tail (if (pair? rest)
569 (if (pair? (cdr rest))
570 (scm-error 'wrong-number-of-args
571 "unfold-right" "too many arguments" '()
575 (let uf ((seed seed) (lis tail))
578 (uf (g seed) (cons (f seed) lis))))))
580 (define (reduce f ridentity lst)
581 (fold f ridentity lst))
583 (define (reduce-right f ridentity lst)
584 (fold-right f ridentity lst))
587 ;; Internal helper procedure. Map `f' over the single list `ls'.
591 (define (append-map f clist1 . rest)
596 (append (f (car l)) (lp (cdr l)))))
597 (let lp ((l (cons clist1 rest)))
600 (append (apply f (map1 car l)) (lp (map1 cdr l)))))))
603 (define (append-map! f clist1 . rest)
608 (append! (f (car l)) (lp (cdr l)))))
609 (let lp ((l (cons clist1 rest)))
612 (append! (apply f (map1 car l)) (lp (map1 cdr l)))))))
614 (define (map! f list1 . rest)
620 (set-car! l (f (car l)))
621 (set-cdr! l (lp (cdr l)))
623 (let lp ((l (cons list1 rest)) (res list1))
627 (set-car! res (apply f (map1 car l)))
628 (set-cdr! res (lp (map1 cdr l) (cdr res)))
631 (define (pair-for-each f clist1 . rest)
639 (let lp ((l (cons clist1 rest)))
644 (lp (map1 cdr l)))))))
646 (define (filter-map f clist1 . rest)
651 (let ((res (f (car l))))
653 (cons res (lp (cdr l)))
655 (let lp ((l (cons clist1 rest)))
658 (let ((res (apply f (map1 car l))))
660 (cons res (lp (map1 cdr l)))
661 (lp (map1 cdr l))))))))
663 ;;; Filtering & partitioning
665 (define (partition pred list)
668 (if (pred (car list))
669 (receive (in out) (partition pred (cdr list))
670 (values (cons (car list) in) out))
671 (receive (in out) (partition pred (cdr list))
672 (values in (cons (car list) out))))))
674 (define (remove pred list)
675 (filter (lambda (x) (not (pred x))) list))
677 (define (partition! pred list)
678 (partition pred list)) ; XXX:optimize
680 (define (remove! pred list)
681 (remove pred list)) ; XXX:optimize
685 (define (find pred clist)
688 (if (pred (car clist))
690 (find pred (cdr clist)))))
692 (define (find-tail pred clist)
695 (if (pred (car clist))
697 (find-tail pred (cdr clist)))))
699 (define (take-while pred ls)
700 (cond ((null? ls) '())
701 ((not (pred (car ls))) '())
703 (let ((result (list (car ls))))
704 (let lp ((ls (cdr ls)) (p result))
705 (cond ((null? ls) result)
706 ((not (pred (car ls))) result)
708 (set-cdr! p (list (car ls)))
709 (lp (cdr ls) (cdr p)))))))))
711 (define (take-while! pred clist)
712 (take-while pred clist)) ; XXX:optimize
714 (define (drop-while pred clist)
717 (if (pred (car clist))
718 (drop-while pred (cdr clist))
721 (define (span pred clist)
724 (if (pred (car clist))
725 (receive (first last) (span pred (cdr clist))
726 (values (cons (car clist) first) last))
727 (values '() clist))))
729 (define (span! pred list)
730 (span pred list)) ; XXX:optimize
732 (define (break pred clist)
735 (if (pred (car clist))
737 (receive (first last) (break pred (cdr clist))
738 (values (cons (car clist) first) last)))))
740 (define (break! pred list)
741 (break pred list)) ; XXX:optimize
743 (define (any pred ls . lists)
746 (let lp ((lists (cons ls lists)))
747 (cond ((any1 null? lists)
749 ((any1 null? (map1 cdr lists))
750 (apply pred (map1 car lists)))
752 (or (apply pred (map1 car lists)) (lp (map1 cdr lists))))))))
754 (define (any1 pred ls)
761 (or (pred (car ls)) (lp (cdr ls)))))))
763 (define (every pred ls . lists)
766 (let lp ((lists (cons ls lists)))
767 (cond ((any1 null? lists)
769 ((any1 null? (map1 cdr lists))
770 (apply pred (map1 car lists)))
772 (and (apply pred (map1 car lists)) (lp (map1 cdr lists))))))))
774 (define (every1 pred ls)
781 (and (pred (car ls)) (lp (cdr ls)))))))
783 (define (list-index pred clist1 . rest)
785 (let lp ((l clist1) (i 0))
790 (lp (cdr l) (+ i 1)))))
791 (let lp ((lists (cons clist1 rest)) (i 0))
792 (cond ((any1 null? lists)
794 ((apply pred (map1 car lists)) i)
796 (lp (map1 cdr lists) (+ i 1)))))))
798 ;;; Association lists
800 (define (alist-cons key datum alist)
801 (acons key datum alist))
803 (define (alist-copy alist)
807 (acons (caar a) (cdar a) (lp (cdr a))))))
809 (define (alist-delete key alist . rest)
810 (let ((k= (if (pair? rest) (car rest) equal?)))
814 (if (k= (caar a) key)
816 (cons (car a) (lp (cdr a))))))))
818 (define (alist-delete! key alist . rest)
819 (let ((k= (if (pair? rest) (car rest) equal?)))
820 (alist-delete key alist k=))) ; XXX:optimize
822 ;;; Set operations on lists
824 (define (lset<= = . rest)
827 (let lp ((f (car rest)) (r (cdr rest)))
829 (and (every (lambda (el) (member el (car r) =)) f)
830 (lp (car r) (cdr r)))))))
832 (define (lset= = list1 . rest)
835 (let lp ((f list1) (r rest))
837 (and (every (lambda (el) (member el (car r) =)) f)
838 (every (lambda (el) (member el f =)) (car r))
839 (lp (car r) (cdr r)))))))
841 (define (lset-adjoin = list . rest)
842 (let lp ((l rest) (acc list))
845 (if (member (car l) acc)
847 (lp (cdr l) (cons (car l) acc))))))
849 (define (lset-union = . rest)
850 (let lp0 ((l rest) (acc '()))
853 (let lp1 ((ll (car l)) (acc acc))
856 (if (member (car ll) acc =)
858 (lp1 (cdr ll) (cons (car ll) acc))))))))
860 (define (lset-intersection = list1 . rest)
861 (let lp ((l list1) (acc '()))
864 (if (every (lambda (ll) (member (car l) ll =)) rest)
865 (lp (cdr l) (cons (car l) acc))
868 (define (lset-difference = list1 . rest)
871 (let lp ((l list1) (acc '()))
874 (if (any (lambda (ll) (member (car l) ll =)) rest)
876 (lp (cdr l) (cons (car l) acc)))))))
878 ;(define (fold kons knil list1 . rest)
880 (define (lset-xor = . rest)
881 (fold (lambda (lst res)
882 (let lp ((l lst) (acc '()))
884 (let lp0 ((r res) (acc acc))
887 (if (member (car r) lst =)
889 (lp0 (cdr r) (cons (car r) acc)))))
890 (if (member (car l) res =)
892 (lp (cdr l) (cons (car l) acc))))))
896 (define (lset-diff+intersection = list1 . rest)
897 (let lp ((l list1) (accd '()) (acci '()))
899 (values (reverse! accd) (reverse! acci))
900 (let ((appears (every (lambda (ll) (member (car l) ll =)) rest)))
902 (lp (cdr l) accd (cons (car l) acci))
903 (lp (cdr l) (cons (car l) accd) acci))))))
906 (define (lset-union! = . rest)
907 (apply lset-union = rest)) ; XXX:optimize
909 (define (lset-intersection! = list1 . rest)
910 (apply lset-intersection = list1 rest)) ; XXX:optimize
912 (define (lset-difference! = list1 . rest)
913 (apply lset-difference = list1 rest)) ; XXX:optimize
915 (define (lset-xor! = . rest)
916 (apply lset-xor = rest)) ; XXX:optimize
918 (define (lset-diff+intersection! = list1 . rest)
919 (apply lset-diff+intersection = list1 rest)) ; XXX:optimize
921 ;;; srfi-1.scm ends here