Fix type-checking of SRFI-1 `partition'.
[bpt/guile.git] / srfi / srfi-1.c
index 3a80b31..35815b3 100644 (file)
@@ -1,8 +1,8 @@
 /* srfi-1.c --- SRFI-1 procedures for Guile
  *
- *     Copyright (C) 1995, 1996, 1997, 2000, 2001, 2002, 2003 Free Software
- *     Foundation, Inc.
- * 
+ *     Copyright (C) 1995, 1996, 1997, 2000, 2001, 2002, 2003, 2005, 2006, 2008
+ *     Free Software Foundation, Inc.
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
 #include <libguile.h>
 #include <libguile/lang.h>
 
@@ -62,6 +66,33 @@ equal_trampoline (SCM proc, SCM arg1, SCM arg2)
   return scm_equal_p (arg1, arg2);
 }
 
+/* list_copy_part() copies the first COUNT cells of LST, puts the result at
+   *dst, and returns the SCM_CDRLOC of the last cell in that new list.
+
+   This function is designed to be careful about LST possibly having changed
+   in between the caller deciding what to copy, and the copy actually being
+   done here.  The COUNT ensures we terminate if LST has become circular,
+   SCM_VALIDATE_CONS guards against a cdr in the list changed to some
+   non-pair object.  */
+
+#include <stdio.h>
+static SCM *
+list_copy_part (SCM lst, int count, SCM *dst)
+#define FUNC_NAME "list_copy_part"
+{
+  SCM c;
+  for ( ; count > 0; count--)
+    {
+      SCM_VALIDATE_CONS (SCM_ARGn, lst);
+      c = scm_cons (SCM_CAR (lst), SCM_EOL);
+      *dst = c;
+      dst = SCM_CDRLOC (c);
+      lst = SCM_CDR (lst);
+    }
+  return dst;
+}
+#undef FUNC_NAME
+
 
 SCM_DEFINE (scm_srfi1_alist_copy, "alist-copy", 1, 0, 0,
             (SCM alist),
@@ -97,6 +128,146 @@ SCM_DEFINE (scm_srfi1_alist_copy, "alist-copy", 1, 0, 0,
 #undef FUNC_NAME
 
 
+
+SCM_DEFINE (scm_srfi1_append_reverse, "append-reverse", 2, 0, 0,
+            (SCM revhead, SCM tail),
+           "Reverse @var{rev-head}, append @var{tail} to it, and return the\n"
+           "result.  This is equivalent to @code{(append (reverse\n"
+           "@var{rev-head}) @var{tail})}, but its implementation is more\n"
+           "efficient.\n"
+           "\n"
+           "@example\n"
+           "(append-reverse '(1 2 3) '(4 5 6)) @result{} (3 2 1 4 5 6)\n"
+           "@end example")
+#define FUNC_NAME s_scm_srfi1_append_reverse
+{
+  while (scm_is_pair (revhead))
+    {
+      /* copy first element of revhead onto front of tail */
+      tail = scm_cons (SCM_CAR (revhead), tail);
+      revhead = SCM_CDR (revhead);
+    }
+  SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (revhead), revhead, SCM_ARG1, FUNC_NAME,
+                   "list");
+  return tail;
+}
+#undef FUNC_NAME
+
+
+SCM_DEFINE (scm_srfi1_append_reverse_x, "append-reverse!", 2, 0, 0,
+            (SCM revhead, SCM tail),
+           "Reverse @var{rev-head}, append @var{tail} to it, and return the\n"
+           "result.  This is equivalent to @code{(append! (reverse!\n"
+           "@var{rev-head}) @var{tail})}, but its implementation is more\n"
+           "efficient.\n"
+           "\n"
+           "@example\n"
+           "(append-reverse! (list 1 2 3) '(4 5 6)) @result{} (3 2 1 4 5 6)\n"
+           "@end example\n"
+           "\n"
+           "@var{rev-head} may be modified in order to produce the result.")
+#define FUNC_NAME s_scm_srfi1_append_reverse_x
+{
+  SCM newtail;
+
+  while (scm_is_pair (revhead))
+    {
+      /* take the first cons cell from revhead */
+      newtail = revhead;
+      revhead = SCM_CDR (revhead);
+
+      /* make it the new start of tail, appending the previous */
+      SCM_SETCDR (newtail, tail);
+      tail = newtail;
+    }
+  SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (revhead), revhead, SCM_ARG1, FUNC_NAME,
+                   "list");
+  return tail;
+}
+#undef FUNC_NAME
+
+
+SCM_DEFINE (scm_srfi1_break, "break", 2, 0, 0,
+            (SCM pred, SCM lst),
+           "Return two values, the longest initial prefix of @var{lst}\n"
+           "whose elements all fail the predicate @var{pred}, and the\n"
+           "remainder of @var{lst}.\n"
+           "\n"
+           "Note that the name @code{break} conflicts with the @code{break}\n"
+           "binding established by @code{while}.  Applications wanting to\n"
+           "use @code{break} from within a @code{while} loop will need to\n"
+           "make a new define under a different name.")
+#define FUNC_NAME s_scm_srfi1_break
+{
+  scm_t_trampoline_1 pred_tramp;
+  SCM ret, *p;
+
+  pred_tramp = scm_trampoline_1 (pred);
+  SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
+
+  ret = SCM_EOL;
+  p = &ret;
+  for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
+    {
+      SCM elem = SCM_CAR (lst);
+      if (scm_is_true (pred_tramp (pred, elem)))
+        goto done;
+
+      /* want this elem, tack it onto the end of ret */
+      *p = scm_cons (elem, SCM_EOL);
+      p = SCM_CDRLOC (*p);
+    }
+  SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
+
+ done:
+  return scm_values (scm_list_2 (ret, lst));
+}
+#undef FUNC_NAME
+
+
+SCM_DEFINE (scm_srfi1_break_x, "break!", 2, 0, 0,
+            (SCM pred, SCM lst),
+           "Return two values, the longest initial prefix of @var{lst}\n"
+           "whose elements all fail the predicate @var{pred}, and the\n"
+           "remainder of @var{lst}.  @var{lst} may be modified to form the\n"
+           "return.")
+#define FUNC_NAME s_scm_srfi1_break_x
+{
+  SCM upto, *p;
+  scm_t_trampoline_1 pred_tramp;
+
+  pred_tramp = scm_trampoline_1 (pred);
+  SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
+
+  p = &lst;
+  for (upto = lst; scm_is_pair (upto); upto = SCM_CDR (upto))
+    {
+      if (scm_is_true (pred_tramp (pred, SCM_CAR (upto))))
+        goto done;
+
+      /* want this element */
+      p = SCM_CDRLOC (upto);
+    }
+  SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (upto), lst, SCM_ARG2, FUNC_NAME, "list");
+
+ done:
+  *p = SCM_EOL;
+  return scm_values (scm_list_2 (lst, upto));
+}
+#undef FUNC_NAME
+
+
+SCM_DEFINE (scm_srfi1_car_plus_cdr, "car+cdr", 1, 0, 0,
+            (SCM pair),
+           "Return two values, the @sc{car} and the @sc{cdr} of @var{pair}.")
+#define FUNC_NAME s_scm_srfi1_car_plus_cdr
+{
+  SCM_VALIDATE_CONS (SCM_ARG1, pair);
+  return scm_values (scm_list_2 (SCM_CAR (pair), SCM_CDR (pair)));
+}
+#undef FUNC_NAME
+
+
 SCM_DEFINE (scm_srfi1_concatenate, "concatenate", 1, 0, 0,
             (SCM lstlst),
            "Construct a list by appending all lists in @var{lstlst}.\n"
@@ -256,6 +427,7 @@ SCM_DEFINE (scm_srfi1_delete, "delete", 2, 1, 0,
 {
   scm_t_trampoline_2 equal_p;
   SCM  ret, *p, keeplst;
+  int  count;
 
   if (SCM_UNBNDP (pred))
     return scm_delete (x, lst);
@@ -268,30 +440,28 @@ SCM_DEFINE (scm_srfi1_delete, "delete", 2, 1, 0,
      elements are considered.
 
      Elements to be retained are not immediately copied, instead keeplst is
-     the last pair in lst which is to be retained but not yet copied.  When
-     there's no more deletions, *p can be set to keeplst to share the
-     remainder of the original lst.  (The entire original lst if there's no
-     deletions at all.)  */
+     the last pair in lst which is to be retained but not yet copied, count
+     is how many from there are wanted.  When there's no more deletions, *p
+     can be set to keeplst to share the remainder of the original lst.  (The
+     entire original lst if there's no deletions at all.)  */
 
   keeplst = lst;
-  ret = SCM_EOL;
+  count = 0;
   p = &ret;
 
   for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
     {
       if (scm_is_true (equal_p (pred, x, SCM_CAR (lst))))
         {
-          /* delete this element, so copy from keeplst (inclusive) to lst
-             (exclusive) onto ret */
-          while (! scm_is_eq (keeplst, lst))
-            {
-              SCM c = scm_cons (SCM_CAR (keeplst), SCM_EOL);
-              *p = c;
-              p = SCM_CDRLOC (c);
-              keeplst = SCM_CDR (keeplst);
-            }
-
+          /* delete this element, so copy those at keeplst */
+          p = list_copy_part (keeplst, count, p);
           keeplst = SCM_CDR (lst);
+          count = 0;
+        }
+      else
+        {
+          /* keep this element */
+          count++;
         }
     }
 
@@ -378,6 +548,7 @@ SCM_DEFINE (scm_srfi1_delete_duplicates, "delete-duplicates", 1, 1, 0,
 {
   scm_t_trampoline_2 equal_p;
   SCM  ret, *p, keeplst, item, l;
+  int  count, i;
 
   /* ret is the new list constructed.  p is where to append, initially &ret
      then SCM_CDRLOC of the last pair.  lst is advanced as each element is
@@ -398,54 +569,58 @@ SCM_DEFINE (scm_srfi1_delete_duplicates, "delete-duplicates", 1, 1, 0,
      deletions.)  */
 
   /* skip to end if an empty list (or something invalid) */
-  ret = lst;
-  if (scm_is_pair (lst))
+  ret = SCM_EOL;
+
+  if (SCM_UNBNDP (pred))
+    equal_p = equal_trampoline;
+  else
     {
-      if (SCM_UNBNDP (pred))
-        equal_p = equal_trampoline;
-      else
-        {
-          equal_p = scm_trampoline_2 (pred);
-          SCM_ASSERT (equal_p, pred, SCM_ARG2, FUNC_NAME);
-        }
+      equal_p = scm_trampoline_2 (pred);
+      SCM_ASSERT (equal_p, pred, SCM_ARG2, FUNC_NAME);
+    }
+
+  keeplst = lst;
+  count = 0;
+  p = &ret;
 
-      keeplst = lst;
-      p = &ret;
+  for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
+    {
+      item = SCM_CAR (lst);
 
-      /* loop over lst elements starting from second */
-      for (;;)
+      /* look for item in "ret" list */
+      for (l = ret; scm_is_pair (l); l = SCM_CDR (l))
         {
-          lst = SCM_CDR (lst);
-          if (! scm_is_pair (lst))
-            break;
-          item = SCM_CAR (lst);
-
-          /* loop searching ret upto lst */
-          for (l = ret; ! scm_is_eq (l, lst); l = SCM_CDR (l))
+          if (scm_is_true (equal_p (pred, SCM_CAR (l), item)))
             {
-              if (scm_is_true (equal_p (pred, SCM_CAR (l), item)))
-                {
-                  /* duplicate, don't want this element, so copy keeplst
-                     (inclusive) to lst (exclusive) onto ret */
-                  while (! scm_is_eq (keeplst, lst))
-                    {
-                      SCM c = scm_cons (SCM_CAR (keeplst), SCM_EOL);
-                      *p = c;
-                      p = SCM_CDRLOC (c);
-                      keeplst = SCM_CDR (keeplst);
-                    }
-
-                  keeplst = SCM_CDR (lst);  /* elem after the one deleted */
-                  *p = keeplst;
-                  break;
-                }
+              /* "item" is a duplicate, so copy keeplst onto ret */
+            duplicate:
+              p = list_copy_part (keeplst, count, p);
+
+              keeplst = SCM_CDR (lst);  /* elem after the one deleted */
+              count = 0;
+              goto next_elem;
             }
         }
-    }
 
-  /* demand that lst was a proper list */
+      /* look for item in "keeplst" list
+         be careful traversing, in case nasty code changed the cdrs */
+      for (i = 0,       l = keeplst;
+           i < count && scm_is_pair (l);
+           i++,         l = SCM_CDR (l))
+        if (scm_is_true (equal_p (pred, SCM_CAR (l), item)))
+          goto duplicate;
+
+      /* keep this element */
+      count++;
+
+    next_elem:
+      ;
+    }
   SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG1, FUNC_NAME, "list");
 
+  /* share tail of keeplst items */
+  *p = keeplst;
+
   return ret;
 }
 #undef FUNC_NAME
@@ -604,6 +779,26 @@ SCM_DEFINE (scm_srfi1_drop_while, "drop-while", 2, 0, 0,
 #undef FUNC_NAME
 
 
+SCM_DEFINE (scm_srfi1_eighth, "eighth", 1, 0, 0,
+            (SCM lst),
+           "Return the eighth element of @var{lst}.")
+#define FUNC_NAME s_scm_srfi1_eighth
+{
+  return scm_list_ref (lst, SCM_I_MAKINUM (7));
+}
+#undef FUNC_NAME
+
+
+SCM_DEFINE (scm_srfi1_fifth, "fifth", 1, 0, 0,
+            (SCM lst),
+           "Return the fifth element of @var{lst}.")
+#define FUNC_NAME s_scm_srfi1_fifth
+{
+  return scm_list_ref (lst, SCM_I_MAKINUM (4));
+}
+#undef FUNC_NAME
+
+
 SCM_DEFINE (scm_srfi1_filter_map, "filter-map", 2, 0, 1,
             (SCM proc, SCM list1, SCM rest),
            "Apply @var{proc} to to the elements of @var{list1} @dots{} and\n"
@@ -619,7 +814,7 @@ SCM_DEFINE (scm_srfi1_filter_map, "filter-map", 2, 0, 1,
   ret = SCM_EOL;
   loc = &ret;
 
-  if (SCM_NULLP (rest))
+  if (scm_is_null (rest))
     {
       /* one list */
       scm_t_trampoline_1 proc_tramp = scm_trampoline_1 (proc);
@@ -641,7 +836,7 @@ SCM_DEFINE (scm_srfi1_filter_map, "filter-map", 2, 0, 1,
       lst = list1;
       argnum = 2;
     }
-  else if (SCM_NULLP (SCM_CDR (rest)))
+  else if (scm_is_null (SCM_CDR (rest)))
     {
       /* two lists */
       scm_t_trampoline_2 proc_tramp = scm_trampoline_2 (proc);
@@ -758,6 +953,132 @@ SCM_DEFINE (scm_srfi1_find_tail, "find-tail", 2, 0, 0,
 #undef FUNC_NAME
 
 
+SCM_DEFINE (scm_srfi1_fold, "fold", 3, 0, 1,
+            (SCM proc, SCM init, SCM list1, SCM rest),
+           "Apply @var{proc} to the elements of @var{lst1} @dots{}\n"
+           "@var{lstN} to build a result, and return that result.\n"
+           "\n"
+           "Each @var{proc} call is @code{(@var{proc} @var{elem1} @dots{}\n"
+           "@var{elemN} @var{previous})}, where @var{elem1} is from\n"
+           "@var{lst1}, through @var{elemN} from @var{lstN}.\n"
+           "@var{previous} is the return from the previous call to\n"
+           "@var{proc}, or the given @var{init} for the first call.  If any\n"
+           "list is empty, just @var{init} is returned.\n"
+           "\n"
+           "@code{fold} works through the list elements from first to last.\n"
+           "The following shows a list reversal and the calls it makes,\n"
+           "\n"
+           "@example\n"
+           "(fold cons '() '(1 2 3))\n"
+           "\n"
+           "(cons 1 '())\n"
+           "(cons 2 '(1))\n"
+           "(cons 3 '(2 1)\n"
+           "@result{} (3 2 1)\n"
+           "@end example\n"
+           "\n"
+           "If @var{lst1} through @var{lstN} have different lengths,\n"
+           "@code{fold} stops when the end of the shortest is reached.\n"
+           "Ie.@: elements past the length of the shortest are ignored in\n"
+           "the other @var{lst}s.  At least one @var{lst} must be\n"
+           "non-circular.\n"
+           "\n"
+           "The way @code{fold} builds a result from iterating is quite\n"
+           "general, it can do more than other iterations like say\n"
+           "@code{map} or @code{filter}.  The following for example removes\n"
+           "adjacent duplicate elements from a list,\n"
+           "\n"
+           "@example\n"
+           "(define (delete-adjacent-duplicates lst)\n"
+           "  (fold-right (lambda (elem ret)\n"
+           "                (if (equal? elem (first ret))\n"
+           "                    ret\n"
+           "                    (cons elem ret)))\n"
+           "              (list (last lst))\n"
+           "              lst))\n"
+           "(delete-adjacent-duplicates '(1 2 3 3 4 4 4 5))\n"
+           "@result{} (1 2 3 4 5)\n"
+           "@end example\n"
+           "\n"
+           "Clearly the same sort of thing can be done with a\n"
+           "@code{for-each} and a variable in which to build the result,\n"
+           "but a self-contained @var{proc} can be re-used in multiple\n"
+           "contexts, where a @code{for-each} would have to be written out\n"
+           "each time.")
+#define FUNC_NAME s_scm_srfi1_fold
+{
+  SCM lst;
+  int argnum;
+  SCM_VALIDATE_REST_ARGUMENT (rest);
+
+  if (scm_is_null (rest))
+    {
+      /* one list */
+      scm_t_trampoline_2 proc_tramp = scm_trampoline_2 (proc);
+      SCM_ASSERT (proc_tramp, proc, SCM_ARG1, FUNC_NAME);
+
+      for ( ; scm_is_pair (list1); list1 = SCM_CDR (list1))
+        init = proc_tramp (proc, SCM_CAR (list1), init);
+
+      /* check below that list1 is a proper list, and done */
+      lst = list1;
+      argnum = 2;
+    }
+  else
+    {
+      /* two or more lists */
+      SCM  vec, args, a;
+      size_t  len, i;
+
+      /* vec is the list arguments */
+      vec = scm_vector (scm_cons (list1, rest));
+      len = SCM_SIMPLE_VECTOR_LENGTH (vec);
+
+      /* args is the argument list to pass to proc, same length as vec,
+         re-used for each call */
+      args = scm_make_list (SCM_I_MAKINUM (len+1), SCM_UNDEFINED);
+
+      for (;;)
+        {
+          /* first elem of each list in vec into args, and step those
+             vec entries onto their next element */
+          for (i = 0, a = args, argnum = 2;
+               i < len;
+               i++, a = SCM_CDR (a), argnum++)
+            {
+              lst = SCM_SIMPLE_VECTOR_REF (vec, i);  /* list argument */
+              if (! scm_is_pair (lst))
+                goto check_lst_and_done;
+              SCM_SETCAR (a, SCM_CAR (lst));  /* arg for proc */
+              SCM_SIMPLE_VECTOR_SET (vec, i, SCM_CDR (lst));  /* rest of lst */
+            }
+          SCM_SETCAR (a, init);
+
+          init = scm_apply (proc, args, SCM_EOL);
+        }
+    }
+
+ check_lst_and_done:
+  SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, argnum, FUNC_NAME, "list");
+  return init;
+}
+#undef FUNC_NAME
+
+
+SCM_DEFINE (scm_srfi1_last, "last", 1, 0, 0,
+            (SCM lst),
+           "Like @code{cons}, but with interchanged arguments.  Useful\n"
+           "mostly when passed to higher-order procedures.")
+#define FUNC_NAME s_scm_srfi1_last
+{
+  SCM pair = scm_last_pair (lst);
+  /* scm_last_pair returns SCM_EOL for an empty list */
+  SCM_VALIDATE_CONS (SCM_ARG1, pair);
+  return SCM_CAR (pair);
+}
+#undef FUNC_NAME
+
+
 SCM_DEFINE (scm_srfi1_length_plus, "length+", 1, 0, 0,
             (SCM lst),
            "Return the length of @var{lst}, or @code{#f} if @var{lst} is\n"
@@ -770,6 +1091,109 @@ SCM_DEFINE (scm_srfi1_length_plus, "length+", 1, 0, 0,
 #undef FUNC_NAME
 
 
+SCM_DEFINE (scm_srfi1_list_index, "list-index", 2, 0, 1,
+            (SCM pred, SCM list1, SCM rest),
+           "Return the index of the first set of elements, one from each of\n"
+           "@var{lst1}@dots{}@var{lstN}, which satisfies @var{pred}.\n"
+           "\n"
+           "@var{pred} is called as @code{(@var{pred} elem1 @dots{}\n"
+           "elemN)}.  Searching stops when the end of the shortest\n"
+           "@var{lst} is reached.  The return index starts from 0 for the\n"
+           "first set of elements.  If no set of elements pass then the\n"
+           "return is @code{#f}.\n"
+           "\n"
+           "@example\n"
+           "(list-index odd? '(2 4 6 9))      @result{} 3\n"
+           "(list-index = '(1 2 3) '(3 1 2))  @result{} #f\n"
+           "@end example")
+#define FUNC_NAME s_scm_srfi1_list_index
+{
+  long  n = 0;
+  SCM   lst;
+  int   argnum;
+  SCM_VALIDATE_REST_ARGUMENT (rest);
+
+  if (scm_is_null (rest))
+    {
+      /* one list */
+      scm_t_trampoline_1 pred_tramp = scm_trampoline_1 (pred);
+      SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
+
+      for ( ; scm_is_pair (list1); n++, list1 = SCM_CDR (list1))
+        if (scm_is_true (pred_tramp (pred, SCM_CAR (list1))))
+          return SCM_I_MAKINUM (n);
+
+      /* not found, check below that list1 is a proper list */
+    end_list1:
+      lst = list1;
+      argnum = 2;
+    }
+  else if (scm_is_pair (rest) && scm_is_null (SCM_CDR (rest)))
+    {
+      /* two lists */
+      SCM list2 = SCM_CAR (rest);
+      scm_t_trampoline_2 pred_tramp = scm_trampoline_2 (pred);
+      SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
+
+      for ( ; ; n++)
+        {
+          if (! scm_is_pair (list1))
+            goto end_list1;
+          if (! scm_is_pair (list2))
+            {
+              lst = list2;
+              argnum = 3;
+              break;
+            }
+          if (scm_is_true (pred_tramp (pred,
+                                       SCM_CAR (list1), SCM_CAR (list2))))
+            return SCM_I_MAKINUM (n);
+
+          list1 = SCM_CDR (list1);
+          list2 = SCM_CDR (list2);
+        }
+    }
+  else
+    {
+      /* three or more lists */
+      SCM     vec, args, a;
+      size_t  len, i;
+
+      /* vec is the list arguments */
+      vec = scm_vector (scm_cons (list1, rest));
+      len = SCM_SIMPLE_VECTOR_LENGTH (vec);
+
+      /* args is the argument list to pass to pred, same length as vec,
+         re-used for each call */
+      args = scm_make_list (SCM_I_MAKINUM (len), SCM_UNDEFINED);
+
+      for ( ; ; n++)
+        {
+          /* first elem of each list in vec into args, and step those
+             vec entries onto their next element */
+          for (i = 0, a = args, argnum = 2;
+               i < len;
+               i++, a = SCM_CDR (a), argnum++)
+            {
+              lst = SCM_SIMPLE_VECTOR_REF (vec, i);  /* list argument */
+              if (! scm_is_pair (lst))
+                goto not_found_check_lst;
+              SCM_SETCAR (a, SCM_CAR (lst));  /* arg for pred */
+              SCM_SIMPLE_VECTOR_SET (vec, i, SCM_CDR (lst));  /* rest of lst */
+            }
+
+          if (scm_is_true (scm_apply (pred, args, SCM_EOL)))
+            return SCM_I_MAKINUM (n);
+        }
+    }
+
+ not_found_check_lst:
+  SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, argnum, FUNC_NAME, "list");
+  return SCM_BOOL_F;
+}
+#undef FUNC_NAME
+
+
 /* This routine differs from the core list-copy in allowing improper lists.
    Maybe the core could allow them similarly.  */
 
@@ -803,6 +1227,29 @@ SCM_DEFINE (scm_srfi1_list_copy, "list-copy", 1, 0, 0,
 #undef FUNC_NAME
 
 
+SCM_DEFINE (scm_srfi1_list_tabulate, "list-tabulate", 2, 0, 0,
+            (SCM n, SCM proc),
+           "Return an @var{n}-element list, where each list element is\n"
+           "produced by applying the procedure @var{init-proc} to the\n"
+           "corresponding list index.  The order in which @var{init-proc}\n"
+           "is applied to the indices is not specified.")
+#define FUNC_NAME s_scm_srfi1_list_tabulate
+{
+  long i, nn;
+  scm_t_trampoline_1 proc_tramp = scm_trampoline_1 (proc);
+  SCM ret = SCM_EOL;
+
+  nn = scm_to_signed_integer (n, 0, LONG_MAX);
+  SCM_ASSERT (proc_tramp, proc, SCM_ARG2, FUNC_NAME);
+
+  for (i = nn-1; i >= 0; i--)
+    ret = scm_cons (proc_tramp (proc, scm_from_long (i)), ret);
+
+  return ret;
+}
+#undef FUNC_NAME
+
+
 SCM_DEFINE (scm_srfi1_lset_adjoin, "lset-adjoin", 2, 0, 1,
             (SCM equal, SCM lst, SCM rest),
            "Add to @var{list} any of the given @var{elem}s not already in\n"
@@ -855,6 +1302,67 @@ SCM_DEFINE (scm_srfi1_lset_adjoin, "lset-adjoin", 2, 0, 1,
 #undef FUNC_NAME
 
 
+SCM_DEFINE (scm_srfi1_lset_difference_x, "lset-difference!", 2, 0, 1,
+            (SCM equal, SCM lst, SCM rest),
+           "Return @var{lst} with any elements in the lists in @var{rest}\n"
+           "removed (ie.@: subtracted).  For only one @var{lst} argument,\n"
+           "just that list is returned.\n"
+           "\n"
+           "The given @var{equal} procedure is used for comparing elements,\n"
+           "called as @code{(@var{equal} elem1 elemN)}.  The first argument\n"
+           "is from @var{lst} and the second from one of the subsequent\n"
+           "lists.  But exactly which calls are made and in what order is\n"
+           "unspecified.\n"
+           "\n"
+           "@example\n"
+           "(lset-difference! eqv? (list 'x 'y))           @result{} (x y)\n"
+           "(lset-difference! eqv? (list 1 2 3) '(3 1))    @result{} (2)\n"
+           "(lset-difference! eqv? (list 1 2 3) '(3) '(2)) @result{} (1)\n"
+           "@end example\n"
+           "\n"
+           "@code{lset-difference!} may modify @var{lst} to form its\n"
+           "result.")
+#define FUNC_NAME s_scm_srfi1_lset_difference_x
+{
+  scm_t_trampoline_2 equal_tramp = scm_trampoline_2 (equal);
+  SCM ret, *pos, elem, r, b;
+  int argnum;
+
+  SCM_ASSERT (equal_tramp, equal, SCM_ARG1, FUNC_NAME);
+  SCM_VALIDATE_REST_ARGUMENT (rest);
+
+  ret = SCM_EOL;
+  pos = &ret;
+  for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
+    {
+      elem = SCM_CAR (lst);
+
+      for (r = rest, argnum = SCM_ARG3;
+           scm_is_pair (r);
+           r = SCM_CDR (r), argnum++)
+        {
+          for (b = SCM_CAR (r); scm_is_pair (b); b = SCM_CDR (b))
+            if (scm_is_true (equal_tramp (equal, elem, SCM_CAR (b))))
+              goto next_elem; /* equal to elem, so drop that elem */
+
+          SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (b), b, argnum, FUNC_NAME,"list");
+        }
+
+      /* elem not equal to anything in later lists, so keep it */
+      *pos = lst;
+      pos = SCM_CDRLOC (lst);
+
+    next_elem:
+      ;
+    }
+  SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
+
+  *pos = SCM_EOL;
+  return ret;
+}
+#undef FUNC_NAME
+
+
 /* Typechecking for multi-argument MAP and FOR-EACH.
 
    Verify that each element of the vector ARGV, except for the first,
@@ -869,20 +1377,15 @@ check_map_args (SCM argv,
                const char *who)
 {
   long i;
+  SCM elt;
 
   for (i = SCM_SIMPLE_VECTOR_LENGTH (argv) - 1; i >= 1; i--)
     {
-      SCM elt = SCM_SIMPLE_VECTOR_REF (argv, i);
       long elt_len;
+      elt = SCM_SIMPLE_VECTOR_REF (argv, i);
 
       if (!(scm_is_null (elt) || scm_is_pair (elt)))
-       {
-       check_map_error:
-         if (gf)
-           scm_apply_generic (gf, scm_cons (proc, args));
-         else
-           scm_wrong_type_arg (who, i + 2, elt);
-       }
+       goto check_map_error;
        
       elt_len = srfi1_ilength (elt);
       if (elt_len < -1)
@@ -891,10 +1394,18 @@ check_map_args (SCM argv,
       if (len < 0 || (elt_len >= 0 && elt_len < len))
        len = elt_len;
     }
+
   if (len < 0)
-    /* i == 0 */
-    goto check_map_error;
-  
+    {
+      /* i == 0 */
+      elt = SCM_EOL;
+    check_map_error:
+      if (gf)
+       scm_apply_generic (gf, scm_cons (proc, args));
+      else
+       scm_wrong_type_arg (who, i + 2, elt);
+    }
+
   scm_remember_upto_here_1 (argv);
   return len;
 }
@@ -1109,7 +1620,7 @@ SCM_DEFINE (scm_srfi1_assoc, "assoc", 2, 1, 0,
       SCM tmp = SCM_CAR (ls);
       SCM_ASSERT_TYPE (scm_is_pair (tmp), alist, SCM_ARG2, FUNC_NAME,
                       "association list");
-      if (scm_is_true (equal_p (pred, SCM_CAR (tmp), key)))
+      if (scm_is_true (equal_p (pred, key, SCM_CAR (tmp))))
        return tmp;
     }
   SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (ls), alist, SCM_ARG2, FUNC_NAME,
@@ -1118,6 +1629,32 @@ SCM_DEFINE (scm_srfi1_assoc, "assoc", 2, 1, 0,
 }
 #undef FUNC_NAME
 
+
+SCM_DEFINE (scm_srfi1_ninth, "ninth", 1, 0, 0,
+            (SCM lst),
+           "Return the ninth element of @var{lst}.")
+#define FUNC_NAME s_scm_srfi1_ninth
+{
+  return scm_list_ref (lst, scm_from_int (8));
+}
+#undef FUNC_NAME
+
+
+SCM_DEFINE (scm_srfi1_not_pair_p, "not-pair?", 1, 0, 0,
+            (SCM obj),
+           "Return @code{#t} is @var{obj} is not a pair, @code{#f}\n"
+           "otherwise.\n"
+           "\n"
+           "This is shorthand notation @code{(not (pair?  @var{obj}))} and\n"
+           "is supposed to be used for end-of-list checking in contexts\n"
+           "where dotted lists are allowed.")
+#define FUNC_NAME s_scm_srfi1_not_pair_p
+{
+  return scm_from_bool (! scm_is_pair (obj));
+}
+#undef FUNC_NAME
+
+
 SCM_DEFINE (scm_srfi1_partition, "partition", 2, 0, 0,
            (SCM pred, SCM list),
            "Partition the elements of @var{list} with predicate @var{pred}.\n"
@@ -1130,6 +1667,7 @@ SCM_DEFINE (scm_srfi1_partition, "partition", 2, 0, 0,
   /* In this implementation, the output lists don't share memory with
      list, because it's probably not worth the effort. */
   scm_t_trampoline_1 call = scm_trampoline_1(pred);
+  SCM orig_list = list;
   SCM kept = scm_cons(SCM_EOL, SCM_EOL);
   SCM kept_tail = kept;
   SCM dropped = scm_cons(SCM_EOL, SCM_EOL);
@@ -1138,8 +1676,14 @@ SCM_DEFINE (scm_srfi1_partition, "partition", 2, 0, 0,
   SCM_ASSERT(call, pred, 2, FUNC_NAME);
   
   for (; !SCM_NULL_OR_NIL_P (list); list = SCM_CDR(list)) {
-    SCM elt = SCM_CAR(list);
-    SCM new_tail = scm_cons(SCM_CAR(list), SCM_EOL);
+    SCM elt, new_tail;
+
+    /* Make sure LIST is not a dotted list.  */
+    SCM_ASSERT (scm_is_pair (list), orig_list, SCM_ARG2, FUNC_NAME);
+
+    elt = SCM_CAR (list);
+    new_tail = scm_cons (SCM_CAR (list), SCM_EOL);
+
     if (scm_is_true (call (pred, elt))) {
       SCM_SETCDR(kept_tail, new_tail);
       kept_tail = new_tail;
@@ -1404,6 +1948,26 @@ SCM_DEFINE (scm_srfi1_remove_x, "remove!", 2, 0, 0,
 #undef FUNC_NAME
 
 
+SCM_DEFINE (scm_srfi1_seventh, "seventh", 1, 0, 0,
+            (SCM lst),
+           "Return the seventh element of @var{lst}.")
+#define FUNC_NAME s_scm_srfi1_seventh
+{
+  return scm_list_ref (lst, scm_from_int (6));
+}
+#undef FUNC_NAME
+
+
+SCM_DEFINE (scm_srfi1_sixth, "sixth", 1, 0, 0,
+            (SCM lst),
+           "Return the sixth element of @var{lst}.")
+#define FUNC_NAME s_scm_srfi1_sixth
+{
+  return scm_list_ref (lst, scm_from_int (5));
+}
+#undef FUNC_NAME
+
+
 SCM_DEFINE (scm_srfi1_span, "span", 2, 0, 0,
             (SCM pred, SCM lst),
            "Return two values, the longest initial prefix of @var{lst}\n"
@@ -1529,12 +2093,11 @@ SCM_DEFINE (scm_srfi1_take_x, "take!", 2, 0, 0,
   long nn;
   SCM pos;
 
-  SCM_VALIDATE_INUM_MIN_COPY (SCM_ARG2, n, 0, nn);
-
+  nn = scm_to_signed_integer (n, 0, LONG_MAX);
   if (nn == 0)
     return SCM_EOL;
 
-  pos = scm_list_tail (lst, SCM_I_MAKINUM (nn - 1));
+  pos = scm_list_tail (lst, scm_from_long (nn - 1));
 
   /* Must have at least one cell left, mustn't have reached the end of an
      n-1 element list.  SCM_VALIDATE_CONS here gives the same error as
@@ -1629,6 +2192,27 @@ SCM_DEFINE (scm_srfi1_take_while_x, "take-while!", 2, 0, 0,
 #undef FUNC_NAME
 
 
+SCM_DEFINE (scm_srfi1_tenth, "tenth", 1, 0, 0,
+            (SCM lst),
+           "Return the tenth element of @var{lst}.")
+#define FUNC_NAME s_scm_srfi1_tenth
+{
+  return scm_list_ref (lst, scm_from_int (9));
+}
+#undef FUNC_NAME
+
+
+SCM_DEFINE (scm_srfi1_xcons, "xcons", 2, 0, 0,
+            (SCM d, SCM a),
+           "Like @code{cons}, but with interchanged arguments.  Useful\n"
+           "mostly when passed to higher-order procedures.")
+#define FUNC_NAME s_scm_srfi1_xcons
+{
+  return scm_cons (a, d);
+}
+#undef FUNC_NAME
+
+
 void
 scm_init_srfi_1 (void)
 {