(scm_double_cell): move SET_GCMARK set out of if body.
[bpt/guile.git] / ice-9 / common-list.scm
index a097184..29fa0e5 100644 (file)
@@ -1,24 +1,85 @@
 ;;;; common-list.scm --- COMMON LISP list functions for Scheme
 ;;;;
-;;;;   Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
-;;;; 
+;;;;   Copyright (C) 1995, 1996, 1997, 2001 Free Software Foundation, Inc.
+;;;;
 ;;;; This program is free software; you can redistribute it and/or modify
 ;;;; it under the terms of the GNU General Public License as published by
 ;;;; the Free Software Foundation; either version 2, or (at your option)
 ;;;; any later version.
-;;;; 
+;;;;
 ;;;; This program is distributed in the hope that it will be useful,
 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;;;; GNU General Public License for more details.
-;;;; 
+;;;;
 ;;;; You should have received a copy of the GNU General Public License
 ;;;; along with this software; see the file COPYING.  If not, write to
 ;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 ;;;; Boston, MA 02111-1307 USA
-;;;; 
+;;;;
+;;;; As a special exception, the Free Software Foundation gives permission
+;;;; for additional uses of the text contained in its release of GUILE.
+;;;;
+;;;; The exception is that, if you link the GUILE library with other files
+;;;; to produce an executable, this does not by itself cause the
+;;;; resulting executable to be covered by the GNU General Public License.
+;;;; Your use of that executable is in no way restricted on account of
+;;;; linking the GUILE library code into it.
+;;;;
+;;;; This exception does not however invalidate any other reasons why
+;;;; the executable file might be covered by the GNU General Public License.
+;;;;
+;;;; This exception applies only to the code released by the
+;;;; Free Software Foundation under the name GUILE.  If you copy
+;;;; code from other Free Software Foundation releases into a copy of
+;;;; GUILE, as the General Public License permits, the exception does
+;;;; not apply to the code that you add in this way.  To avoid misleading
+;;;; anyone as to the status of such modified files, you must delete
+;;;; this exception notice from them.
+;;;;
+;;;; If you write modifications of your own for GUILE, it is your choice
+;;;; whether to permit this exception to apply to your modifications.
+;;;; If you do not wish that, delete this exception notice.
+;;;;
+
+;;; Commentary:
+
+;; These procedures are exported:
+;;  (adjoin e l)
+;;  (union l1 l2)
+;;  (intersection l1 l2)
+;;  (set-difference l1 l2)
+;;  (reduce-init p init l)
+;;  (reduce p l)
+;;  (some pred l . rest)
+;;  (every pred l . rest)
+;;  (notany pred . ls)
+;;  (notevery pred . ls)
+;;  (count-if pred l)
+;;  (find-if pred l)
+;;  (member-if pred l)
+;;  (remove-if pred l)
+;;  (remove-if-not pred l)
+;;  (delete-if! pred l)
+;;  (delete-if-not! pred l)
+;;  (butlast lst n)
+;;  (and? . args)
+;;  (or? . args)
+;;  (has-duplicates? lst)
+;;  (pick p l)
+;;  (pick-mappings p l)
+;;  (uniq l)
+;;
+;; See docstrings for each procedure for more info.  See also module
+;; `(srfi srfi-1)' for a complete list handling library.
+
+;;; Code:
 \f
-(define-module (ice-9 common-list))
+(define-module (ice-9 common-list)
+  :export (adjoin union intersection set-difference reduce-init reduce
+          some every notany notevery count-if find-if member-if remove-if
+          remove-if-not delete-if! delete-if-not! butlast and? or?
+          has-duplicates? pick pick-mappings uniq))
 
 ;;"comlist.scm" Implementation of COMMON LISP list functions for Scheme
 ; Copyright (C) 1991, 1993, 1995 Aubrey Jaffer.
 ;promotional, or sales literature without prior written consent in
 ;each case.
 
-(define-public (adjoin e l) 
-  "Returns list L, possibly with element E added if it is not already in L."
+(define (adjoin e l)
+  "Return list L, possibly with element E added if it is not already in L."
   (if (memq e l) l (cons e l)))
 
-(define-public (union l1 l2)
-  "Returns a new list that is the union of L1 and L2.
-Elements that occur in both lists will occur only once
-in the result list."
+(define (union l1 l2)
+  "Return a new list that is the union of L1 and L2.
+Elements that occur in both lists occur only once in
+the result list."
   (cond ((null? l1) l2)
        ((null? l2) l1)
        (else (union (cdr l1) (adjoin (car l1) l2)))))
 
-(define-public (intersection l1 l2)
-  "Returns a new list that is the intersection of L1 and L2.
-Only elements that occur in both lists will occur in the result list."
-  (cond ((null? l1) l1)
-       ((null? l2) l2)
-       ((memv (car l1) l2) (cons (car l1) (intersection (cdr l1) l2)))
-       (else (intersection (cdr l1) l2))))
+(define (intersection l1 l2)
+  "Return a new list that is the intersection of L1 and L2.
+Only elements that occur in both lists occur in the result list."
+  (if (null? l2) l2
+      (let loop ((l1 l1) (result '()))
+       (cond ((null? l1) (reverse! result))
+             ((memv (car l1) l2) (loop (cdr l1) (cons (car l1) result)))
+             (else (loop (cdr l1) result))))))
 
-(define-public (set-difference l1 l2)
+(define (set-difference l1 l2)
   "Return elements from list L1 that are not in list L2."
-  (cond ((null? l1) l1)
-       ((memv (car l1) l2) (set-difference (cdr l1) l2))
-       (else (cons (car l1) (set-difference (cdr l1) l2)))))
+  (let loop ((l1 l1) (result '()))
+    (cond ((null? l1) (reverse! result))
+         ((memv (car l1) l2) (loop (cdr l1) result))
+         (else (loop (cdr l1) (cons (car l1) result))))))
 
-(define-public (reduce-init p init l)
+(define (reduce-init p init l)
   "Same as `reduce' except it implicitly inserts INIT at the start of L."
   (if (null? l)
       init
       (reduce-init p (p init (car l)) (cdr l))))
 
-(define-public (reduce p l)
-  "Combines all the elements of sequence L using a binary operation P.
-The combination is left-associative. For example, using +, one can
-add up all the elements. `reduce' allows you to apply a function which
+(define (reduce p l)
+  "Combine all the elements of sequence L using a binary operation P.
+The combination is left-associative.  For example, using +, one can
+add up all the elements.  `reduce' allows you to apply a function which
 accepts only two arguments to more than 2 objects.  Functional
 programmers usually refer to this as foldl."
   (cond ((null? l) l)
        ((null? (cdr l)) (car l))
        (else (reduce-init p (car l) (cdr l)))))
 
-(define-public (some pred l . rest)
+(define (some pred l . rest)
   "PRED is a boolean function of as many arguments as there are list
-arguments to `some'. I.e., L plus any optional arguments. PRED is
-applied to successive elements of the list arguments in order. As soon
-as one of these applications returns a true value, `some' terminates
-and returns that value.  If no application returns a true value,
-`some' returns #f. All the lists should have the same length."
+arguments to `some', i.e., L plus any optional arguments.  PRED is
+applied to successive elements of the list arguments in order.  As soon
+as one of these applications returns a true value, return that value.
+If no application returns a true value, return #f.
+All the lists should have the same length."
   (cond ((null? rest)
         (let mapf ((l l))
           (and (not (null? l))
@@ -97,7 +160,7 @@ and returns that value.  If no application returns a true value,
                     (or (apply pred (car l) (map car rest))
                         (mapf (cdr l) (map cdr rest))))))))
 
-(define-public (every pred l . rest)
+(define (every pred l . rest)
   "Return #t iff every application of PRED to L, etc., returns #t.
 Analogous to `some' except it returns #t if every application of
 PRED is #t and #f otherwise."
@@ -110,66 +173,73 @@ PRED is #t and #f otherwise."
                    (and (apply pred (car l) (map car rest))
                         (mapf (cdr l) (map cdr rest))))))))
 
-(define-public (notany pred . ls) 
+(define (notany pred . ls)
   "Return #t iff every application of PRED to L, etc., returns #f.
 Analogous to some but returns #t if no application of PRED returns a
 true value or #f as soon as any one does."
   (not (apply some pred ls)))
 
-(define-public (notevery pred . ls) 
+(define (notevery pred . ls)
   "Return #t iff there is an application of PRED to L, etc., that returns #f.
 Analogous to some but returns #t as soon as an application of PRED returns #f,
 or #f otherwise."
   (not (apply every pred ls)))
 
-(define-public (find-if pred l)
-  "Searches for the first element in L such that (PRED element)
-returns true. If it finds any such element in L, element is
-returned. Otherwise, #f is returned."
+(define (count-if pred l)
+  "Return the number of elements in L for which (PRED element) returns true."
+  (let loop ((n 0) (l l))
+    (cond ((null? l) n)
+         ((pred (car l)) (loop (+ n 1) (cdr l)))
+         (else (loop n (cdr l))))))
+
+(define (find-if pred l)
+  "Search for the first element in L for which (PRED element) returns true.
+If found, return that element, otherwise return #f."
   (cond ((null? l) #f)
        ((pred (car l)) (car l))
        (else (find-if pred (cdr l)))))
 
-(define-public (member-if pred l)
-  "Returns L if (T element) is true for any element in L.  Returns #f
-if PRED does not apply to any element in L."
+(define (member-if pred l)
+  "Return the first sublist of L for whose car PRED is true."
   (cond ((null? l) #f)
        ((pred (car l)) l)
        (else (member-if pred (cdr l)))))
 
-(define-public (remove-if p l)
-  "Removes all elements from L where (P element) is true.
-Returns everything that's left."
-  (cond ((null? l) '())
-       ((p (car l)) (remove-if p (cdr l)))
-       (else (cons (car l) (remove-if p (cdr l))))))
-
-(define-public (remove-if-not p l)
-  "Removes all elements from L where (P element) is #f.
-Returns everything that's left."
-  (cond ((null? l) '())
-       ((not (p (car l))) (remove-if-not p (cdr l)))
-       (else (cons (car l) (remove-if-not p (cdr l))))))
-
-(define-public (delete-if! pred list)
+(define (remove-if pred l)
+  "Remove all elements from L where (PRED element) is true.
+Return everything that's left."
+  (let loop ((l l) (result '()))
+    (cond ((null? l) (reverse! result))
+         ((pred (car l)) (loop (cdr l) result))
+         (else (loop (cdr l) (cons (car l) result))))))
+
+(define (remove-if-not pred l)
+  "Remove all elements from L where (PRED element) is #f.
+Return everything that's left."
+  (let loop ((l l) (result '()))
+    (cond ((null? l) (reverse! result))
+         ((not (pred (car l))) (loop (cdr l) result))
+         (else (loop (cdr l) (cons (car l) result))))))
+
+(define (delete-if! pred l)
   "Destructive version of `remove-if'."
-  (let delete-if ((list list))
-    (cond ((null? list) '())
-         ((pred (car list)) (delete-if (cdr list)))
+  (let delete-if ((l l))
+    (cond ((null? l) '())
+         ((pred (car l)) (delete-if (cdr l)))
          (else
-          (set-cdr! list (delete-if (cdr list)))
-          list)))) 
+          (set-cdr! l (delete-if (cdr l)))
+          l))))
 
-(define-public (delete-if-not! pred list)
+(define (delete-if-not! pred l)
   "Destructive version of `remove-if-not'."
-  (let delete-if ((list list))
-    (cond ((null? list) '())
-         ((not (pred (car list))) (delete-if-not (cdr list)))
+  (let delete-if-not ((l l))
+    (cond ((null? l) '())
+         ((not (pred (car l))) (delete-if-not (cdr l)))
          (else
-          (set-cdr! list (delete-if-not (cdr list)))
-          list))))
+          (set-cdr! l (delete-if-not (cdr l)))
+          l))))
 
-(define-public (butlast lst n)
+(define (butlast lst n)
   "Return all but the last N elements of LST."
   (letrec ((l (- (length lst) n))
           (bl (lambda (lst n)
@@ -181,37 +251,25 @@ Returns everything that's left."
                (error "negative argument to butlast" n)
                l))))
 
-(define-public (and? . args)
+(define (and? . args)
   "Return #t iff all of ARGS are true."
   (cond ((null? args) #t)
        ((car args) (apply and? (cdr args)))
        (else #f)))
 
-(define-public (or? . args)
+(define (or? . args)
   "Return #t iff any of ARGS is true."
   (cond ((null? args) #f)
        ((car args) #t)
        (else (apply or? (cdr args)))))
 
-(define-public (has-duplicates? lst)
+(define (has-duplicates? lst)
   "Return #t iff 2 members of LST are equal?, else #f."
   (cond ((null? lst) #f)
        ((member (car lst) (cdr lst)) #t)
        (else (has-duplicates? (cdr lst)))))
 
-(define-public (list* x . y)
-  "Works like `list' except that the cdr of the last pair is
-the last argument unless there is only one argument, when
-th result is just that argument.  Sometiems called cons*."
-  (define (list*1 x)
-    (if (null? (cdr x))
-       (car x)
-       (cons (car x) (list*1 (cdr x)))))
-  (if (null? y)
-      x
-      (cons x (list*1 y))))
-
-(define-public (pick p l)
+(define (pick p l)
   "Apply P to each element of L, returning a list of elts
 for which P returns a non-#f value."
   (let loop ((s '())
@@ -221,8 +279,8 @@ for which P returns a non-#f value."
      ((p (car l))      (loop (cons (car l) s) (cdr l)))
      (else             (loop s (cdr l))))))
 
-(define-public (pick-mappings p l)
-  "Apply P to each element of L, returning a list of the 
+(define (pick-mappings p l)
+  "Apply P to each element of L, returning a list of the
 non-#f return values of P."
   (let loop ((s '())
             (l l))
@@ -231,12 +289,15 @@ non-#f return values of P."
      ((p (car l)) =>   (lambda (mapping) (loop (cons mapping s) (cdr l))))
      (else             (loop s (cdr l))))))
 
-(define-public (uniq l)
+(define (uniq l)
   "Return a list containing elements of L, with duplicates removed."
-  (if (null? l)
-      '()
-      (let ((u (uniq (cdr l))))
-       (if (memq (car l) u)
-           u
-           (cons (car l) u)))))
+  (let loop ((acc '())
+            (l l))
+    (if (null? l)
+       (reverse! acc)
+       (loop (if (memq (car l) acc)
+                 acc
+                 (cons (car l) acc))
+             (cdr l)))))
 
+;;; common-list.scm ends here