(SRFI-1 Association Lists): In alist-cons, clarify
[bpt/guile.git] / srfi / srfi-1.c
CommitLineData
ee6aac97
MD
1/* srfi-1.c --- SRFI-1 procedures for Guile
2 *
d0a634de
KR
3 * Copyright (C) 1995, 1996, 1997, 2000, 2001, 2002, 2003 Free Software
4 * Foundation, Inc.
ee6aac97 5 *
73be1d9e
MV
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
ee6aac97 10 *
73be1d9e
MV
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
ee6aac97 15 *
73be1d9e
MV
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
ee6aac97
MD
20
21#include <libguile.h>
22#include <libguile/lang.h>
23
24#include "srfi-1.h"
25
26/* The intent of this file is to gradually replace those Scheme
27 * procedures in srfi-1.scm which extends core primitive procedures,
28 * so that using srfi-1 won't have performance penalties.
29 *
30 * Please feel free to contribute any new replacements!
31 */
32
33static long
34srfi1_ilength (SCM sx)
35{
36 long i = 0;
37 SCM tortoise = sx;
38 SCM hare = sx;
39
40 do {
41 if (SCM_NULL_OR_NIL_P(hare)) return i;
896df2d5 42 if (!scm_is_pair (hare)) return -2;
ee6aac97
MD
43 hare = SCM_CDR(hare);
44 i++;
45 if (SCM_NULL_OR_NIL_P(hare)) return i;
896df2d5 46 if (!scm_is_pair (hare)) return -2;
ee6aac97
MD
47 hare = SCM_CDR(hare);
48 i++;
49 /* For every two steps the hare takes, the tortoise takes one. */
50 tortoise = SCM_CDR(tortoise);
51 }
bc36d050 52 while (! scm_is_eq (hare, tortoise));
ee6aac97
MD
53
54 /* If the tortoise ever catches the hare, then the list must contain
55 a cycle. */
56 return -1;
57}
58
d0a634de
KR
59static SCM
60equal_trampoline (SCM proc, SCM arg1, SCM arg2)
61{
62 return scm_equal_p (arg1, arg2);
63}
64
65
47f2726f
KR
66/* scm_append and scm_append_x don't modify their list argument (only the
67 lists within that list in the case of scm_append_x), hence making them
68 suitable for direct use for concatentate. */
69
70SCM_REGISTER_PROC (s_srfi1_concatenate, "concatenate", 1, 0, 0, scm_append);
71SCM_REGISTER_PROC (s_srfi1_concatenate_x, "concatenate!", 1, 0, 0, scm_append_x);
72
73
110348ae 74SCM_DEFINE (scm_srfi1_count, "count", 2, 0, 1,
edea856c 75 (SCM pred, SCM list1, SCM rest),
110348ae
KR
76 "Return a count of the number of times @var{pred} returns true\n"
77 "when called on elements from the given lists.\n"
78 "\n"
79 "@var{pred} is called with @var{N} parameters @code{(@var{pred}\n"
80 "@var{elem1} @dots{} @var{elemN})}, each element being from the\n"
edea856c 81 "corresponding @var{list1} @dots{} @var{lstN}. The first call is\n"
110348ae
KR
82 "with the first element of each list, the second with the second\n"
83 "element from each, and so on.\n"
84 "\n"
85 "Counting stops when the end of the shortest list is reached.\n"
86 "At least one list must be non-circular.")
87#define FUNC_NAME s_scm_srfi1_count
88{
89 long count;
90 SCM_VALIDATE_REST_ARGUMENT (rest);
91
92 count = 0;
93
896df2d5 94 if (scm_is_null (rest))
110348ae
KR
95 {
96 /* one list */
97 scm_t_trampoline_1 pred_tramp;
98 pred_tramp = scm_trampoline_1 (pred);
99 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
100
896df2d5 101 for ( ; scm_is_pair (list1); list1 = SCM_CDR (list1))
edea856c 102 count += scm_is_true (pred_tramp (pred, SCM_CAR (list1)));
110348ae
KR
103
104 end_lst1:
edea856c 105 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (list1), list1, SCM_ARG2, FUNC_NAME,
110348ae
KR
106 "list");
107 }
896df2d5 108 else if (scm_is_pair (rest) && scm_is_null (SCM_CDR (rest)))
110348ae
KR
109 {
110 /* two lists */
111 scm_t_trampoline_2 pred_tramp;
edea856c 112 SCM list2;
110348ae
KR
113
114 pred_tramp = scm_trampoline_2 (pred);
115 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
116
edea856c 117 list2 = SCM_CAR (rest);
110348ae
KR
118 for (;;)
119 {
896df2d5 120 if (! scm_is_pair (list1))
110348ae 121 goto end_lst1;
896df2d5 122 if (! scm_is_pair (list2))
110348ae 123 {
edea856c 124 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (list2), list2, SCM_ARG3,
110348ae
KR
125 FUNC_NAME, "list");
126 break;
127 }
00874d5f 128 count += scm_is_true (pred_tramp
edea856c
SJ
129 (pred, SCM_CAR (list1), SCM_CAR (list2)));
130 list1 = SCM_CDR (list1);
131 list2 = SCM_CDR (list2);
110348ae
KR
132 }
133 }
134 else
135 {
136 /* three or more lists */
137 SCM lstlst, args, l, a, lst;
138 int argnum;
139
140 /* lstlst is a list of the list arguments */
edea856c 141 lstlst = scm_cons (list1, rest);
110348ae
KR
142
143 /* args is the argument list to pass to pred, same length as lstlst,
144 re-used for each call */
145 args = SCM_EOL;
896df2d5 146 for (l = lstlst; scm_is_pair (l); l = SCM_CDR (l))
110348ae
KR
147 args = scm_cons (SCM_BOOL_F, args);
148
149 for (;;)
150 {
151 /* first elem of each list in lstlst into args, and step those
152 lstlst entries onto their next element */
153 for (l = lstlst, a = args, argnum = 2;
896df2d5 154 scm_is_pair (l);
110348ae
KR
155 l = SCM_CDR (l), a = SCM_CDR (a), argnum++)
156 {
157 lst = SCM_CAR (l); /* list argument */
896df2d5 158 if (! scm_is_pair (lst))
110348ae
KR
159 {
160 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst,
161 argnum, FUNC_NAME, "list");
162 goto done;
163 }
164 SCM_SETCAR (a, SCM_CAR (lst)); /* arg for pred */
165 SCM_SETCAR (l, SCM_CDR (lst)); /* keep rest of lst */
166 }
167
00874d5f 168 count += scm_is_true (scm_apply (pred, args, SCM_EOL));
110348ae
KR
169 }
170 }
171 done:
93ccaef0 172 return scm_from_long (count);
110348ae
KR
173}
174#undef FUNC_NAME
175
176
d0a634de
KR
177SCM_DEFINE (scm_srfi1_delete, "delete", 2, 1, 0,
178 (SCM x, SCM lst, SCM pred),
179 "Return a list containing the elements of @var{lst} but with\n"
180 "those equal to @var{x} deleted. The returned elements will be\n"
181 "in the same order as they were in @var{lst}.\n"
182 "\n"
183 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
184 "given. An equality call is made just once for each element,\n"
185 "but the order in which the calls are made on the elements is\n"
186 "unspecified.\n"
187 "\n"
188 "The equality calls are always @code{(pred x elem)}, ie.@: the\n"
189 "given @var{x} is first. This means for instance elements\n"
190 "greater than 5 can be deleted with @code{(delete 5 lst <)}.\n"
191 "\n"
192 "@var{lst} is not modified, but the returned list might share a\n"
193 "common tail with @var{lst}.")
194#define FUNC_NAME s_scm_srfi1_delete
195{
196 scm_t_trampoline_2 equal_p;
197 SCM ret, *p, keeplst;
198
199 if (SCM_UNBNDP (pred))
200 return scm_delete (x, lst);
201
202 equal_p = scm_trampoline_2 (pred);
203 SCM_ASSERT (equal_p, pred, SCM_ARG3, FUNC_NAME);
204
205 /* ret is the return list being constructed. p is where to append to it,
206 initially &ret then SCM_CDRLOC of the last pair. lst progresses as
207 elements are considered.
208
209 Elements to be retained are not immediately copied, instead keeplst is
210 the last pair in lst which is to be retained but not yet copied. When
211 there's no more deletions, *p can be set to keeplst to share the
212 remainder of the original lst. (The entire original lst if there's no
213 deletions at all.) */
214
215 keeplst = lst;
216 ret = SCM_EOL;
217 p = &ret;
218
896df2d5 219 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
d0a634de 220 {
00874d5f 221 if (scm_is_true (equal_p (pred, x, SCM_CAR (lst))))
d0a634de
KR
222 {
223 /* delete this element, so copy from keeplst (inclusive) to lst
224 (exclusive) onto ret */
bc36d050 225 while (! scm_is_eq (keeplst, lst))
d0a634de
KR
226 {
227 SCM c = scm_cons (SCM_CAR (keeplst), SCM_EOL);
228 *p = c;
229 p = SCM_CDRLOC (c);
230 keeplst = SCM_CDR (keeplst);
231 }
232
233 keeplst = SCM_CDR (lst);
234 }
235 }
236
237 /* final retained elements */
238 *p = keeplst;
239
240 /* demand that lst was a proper list */
241 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
242
243 return ret;
244}
245#undef FUNC_NAME
246
247
248SCM_DEFINE (scm_srfi1_delete_x, "delete!", 2, 1, 0,
249 (SCM x, SCM lst, SCM pred),
250 "Return a list containing the elements of @var{lst} but with\n"
251 "those equal to @var{x} deleted. The returned elements will be\n"
252 "in the same order as they were in @var{lst}.\n"
253 "\n"
254 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
255 "given. An equality call is made just once for each element,\n"
256 "but the order in which the calls are made on the elements is\n"
257 "unspecified.\n"
258 "\n"
259 "The equality calls are always @code{(pred x elem)}, ie.@: the\n"
260 "given @var{x} is first. This means for instance elements\n"
261 "greater than 5 can be deleted with @code{(delete 5 lst <)}.\n"
262 "\n"
263 "@var{lst} may be modified to construct the returned list.")
264#define FUNC_NAME s_scm_srfi1_delete_x
265{
266 scm_t_trampoline_2 equal_p;
267 SCM walk;
268 SCM *prev;
269
270 if (SCM_UNBNDP (pred))
271 return scm_delete_x (x, lst);
272
273 equal_p = scm_trampoline_2 (pred);
274 SCM_ASSERT (equal_p, pred, SCM_ARG3, FUNC_NAME);
275
276 for (prev = &lst, walk = lst;
896df2d5 277 scm_is_pair (walk);
d0a634de
KR
278 walk = SCM_CDR (walk))
279 {
00874d5f 280 if (scm_is_true (equal_p (pred, x, SCM_CAR (walk))))
d0a634de
KR
281 *prev = SCM_CDR (walk);
282 else
283 prev = SCM_CDRLOC (walk);
284 }
285
286 /* demand the input was a proper list */
287 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (walk), walk, SCM_ARG2, FUNC_NAME,"list");
288 return lst;
289}
290#undef FUNC_NAME
291
292
293SCM_DEFINE (scm_srfi1_delete_duplicates, "delete-duplicates", 1, 1, 0,
294 (SCM lst, SCM pred),
295 "Return a list containing the elements of @var{lst} but without\n"
296 "duplicates.\n"
297 "\n"
298 "When elements are equal, only the first in @var{lst} is\n"
299 "retained. Equal elements can be anywhere in @var{lst}, they\n"
300 "don't have to be adjacent. The returned list will have the\n"
301 "retained elements in the same order as they were in @var{lst}.\n"
302 "\n"
303 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
304 "given. Calls @code{(pred x y)} are made with element @var{x}\n"
305 "being before @var{y} in @var{lst}. A call is made at most once\n"
306 "for each combination, but the sequence of the calls across the\n"
307 "elements is unspecified.\n"
308 "\n"
309 "@var{lst} is not modified, but the return might share a common\n"
310 "tail with @var{lst}.\n"
311 "\n"
312 "In the worst case, this is an @math{O(N^2)} algorithm because\n"
313 "it must check each element against all those preceding it. For\n"
314 "long lists it is more efficient to sort and then compare only\n"
315 "adjacent elements.")
316#define FUNC_NAME s_scm_srfi1_delete_duplicates
317{
318 scm_t_trampoline_2 equal_p;
319 SCM ret, *p, keeplst, item, l;
320
321 /* ret is the new list constructed. p is where to append, initially &ret
322 then SCM_CDRLOC of the last pair. lst is advanced as each element is
323 considered.
324
325 Elements retained are not immediately appended to ret, instead keeplst
326 is the last pair in lst which is to be kept but is not yet copied.
327 Initially this is the first pair of lst, since the first element is
328 always retained.
329
330 *p is kept set to keeplst, so ret (inclusive) to lst (exclusive) is all
331 the elements retained, making the equality search loop easy.
332
333 If an item must be deleted, elements from keeplst (inclusive) to lst
334 (exclusive) must be copied and appended to ret. When there's no more
335 deletions, *p is left set to keeplst, so ret shares structure with the
336 original lst. (ret will be the entire original lst if there are no
337 deletions.) */
338
339 /* skip to end if an empty list (or something invalid) */
340 ret = lst;
896df2d5 341 if (scm_is_pair (lst))
d0a634de
KR
342 {
343 if (SCM_UNBNDP (pred))
344 equal_p = equal_trampoline;
345 else
346 {
347 equal_p = scm_trampoline_2 (pred);
348 SCM_ASSERT (equal_p, pred, SCM_ARG2, FUNC_NAME);
349 }
350
351 keeplst = lst;
352 p = &ret;
353
354 /* loop over lst elements starting from second */
355 for (;;)
356 {
357 lst = SCM_CDR (lst);
896df2d5 358 if (! scm_is_pair (lst))
d0a634de
KR
359 break;
360 item = SCM_CAR (lst);
361
362 /* loop searching ret upto lst */
bc36d050 363 for (l = ret; ! scm_is_eq (l, lst); l = SCM_CDR (l))
d0a634de 364 {
00874d5f 365 if (scm_is_true (equal_p (pred, SCM_CAR (l), item)))
d0a634de
KR
366 {
367 /* duplicate, don't want this element, so copy keeplst
368 (inclusive) to lst (exclusive) onto ret */
bc36d050 369 while (! scm_is_eq (keeplst, lst))
d0a634de
KR
370 {
371 SCM c = scm_cons (SCM_CAR (keeplst), SCM_EOL);
372 *p = c;
373 p = SCM_CDRLOC (c);
374 keeplst = SCM_CDR (keeplst);
375 }
376
377 keeplst = SCM_CDR (lst); /* elem after the one deleted */
378 *p = keeplst;
379 break;
380 }
381 }
382 }
383 }
384
385 /* demand that lst was a proper list */
386 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG1, FUNC_NAME, "list");
387
388 return ret;
389}
390#undef FUNC_NAME
391
392
393SCM_DEFINE (scm_srfi1_delete_duplicates_x, "delete-duplicates!", 1, 1, 0,
394 (SCM lst, SCM pred),
395 "Return a list containing the elements of @var{lst} but without\n"
396 "duplicates.\n"
397 "\n"
398 "When elements are equal, only the first in @var{lst} is\n"
399 "retained. Equal elements can be anywhere in @var{lst}, they\n"
400 "don't have to be adjacent. The returned list will have the\n"
401 "retained elements in the same order as they were in @var{lst}.\n"
402 "\n"
403 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
404 "given. Calls @code{(pred x y)} are made with element @var{x}\n"
405 "being before @var{y} in @var{lst}. A call is made at most once\n"
406 "for each combination, but the sequence of the calls across the\n"
407 "elements is unspecified.\n"
408 "\n"
409 "@var{lst} may be modified to construct the returned list.\n"
410 "\n"
411 "In the worst case, this is an @math{O(N^2)} algorithm because\n"
412 "it must check each element against all those preceding it. For\n"
413 "long lists it is more efficient to sort and then compare only\n"
414 "adjacent elements.")
415#define FUNC_NAME s_scm_srfi1_delete_duplicates_x
416{
417 scm_t_trampoline_2 equal_p;
418 SCM ret, endret, item, l;
419
420 /* ret is the return list, constructed from the pairs in lst. endret is
421 the last pair of ret, initially the first pair. lst is advanced as
422 elements are considered. */
423
424 /* skip to end if an empty list (or something invalid) */
425 ret = lst;
896df2d5 426 if (scm_is_pair (lst))
d0a634de
KR
427 {
428 if (SCM_UNBNDP (pred))
429 equal_p = equal_trampoline;
430 else
431 {
432 equal_p = scm_trampoline_2 (pred);
433 SCM_ASSERT (equal_p, pred, SCM_ARG2, FUNC_NAME);
434 }
435
436 endret = ret;
437
438 /* loop over lst elements starting from second */
439 for (;;)
440 {
441 lst = SCM_CDR (lst);
896df2d5 442 if (! scm_is_pair (lst))
d0a634de
KR
443 break;
444 item = SCM_CAR (lst);
445
446 /* is item equal to any element from ret to endret (inclusive)? */
447 l = ret;
448 for (;;)
449 {
00874d5f 450 if (scm_is_true (equal_p (pred, SCM_CAR (l), item)))
d0a634de
KR
451 break; /* equal, forget this element */
452
bc36d050 453 if (scm_is_eq (l, endret))
d0a634de
KR
454 {
455 /* not equal to any, so append this pair */
456 SCM_SETCDR (endret, lst);
457 endret = lst;
458 break;
459 }
460 l = SCM_CDR (l);
461 }
462 }
463
464 /* terminate, in case last element was deleted */
465 SCM_SETCDR (endret, SCM_EOL);
466 }
467
468 /* demand that lst was a proper list */
469 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG1, FUNC_NAME, "list");
470
471 return ret;
472}
473#undef FUNC_NAME
474
475
2b077051
KR
476SCM_DEFINE (scm_srfi1_drop_right, "drop-right", 2, 0, 0,
477 (SCM lst, SCM n),
478 "Return a new list containing all except the last @var{n}\n"
479 "elements of @var{lst}.")
480#define FUNC_NAME s_scm_srfi1_drop_right
481{
482 SCM tail = scm_list_tail (lst, n);
483 SCM ret = SCM_EOL;
484 SCM *rend = &ret;
485 while (scm_is_pair (tail))
486 {
487 *rend = scm_cons (SCM_CAR (lst), SCM_EOL);
488 rend = SCM_CDRLOC (*rend);
489
490 lst = SCM_CDR (lst);
491 tail = SCM_CDR (tail);
492 }
493 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P(tail), tail, SCM_ARG1, FUNC_NAME, "list");
494 return ret;
495}
496#undef FUNC_NAME
c1635946
KR
497
498
499SCM_DEFINE (scm_srfi1_filter_map, "filter-map", 2, 0, 1,
500 (SCM proc, SCM list1, SCM rest),
501 "Apply @var{proc} to to the elements of @var{list1} @dots{} and\n"
502 "return a list of the results as per SRFI-1 @code{map}, except\n"
503 "that any @code{#f} results are omitted from the list returned.")
504#define FUNC_NAME s_scm_srfi1_filter_map
505{
506 SCM ret, *loc, elem, newcell, lst;
507 int argnum;
508
509 SCM_VALIDATE_REST_ARGUMENT (rest);
510
511 ret = SCM_EOL;
512 loc = &ret;
513
514 if (SCM_NULLP (rest))
515 {
516 /* one list */
517 scm_t_trampoline_1 proc_tramp = scm_trampoline_1 (proc);
518 SCM_ASSERT (proc_tramp, proc, SCM_ARG1, FUNC_NAME);
519
520 for ( ; scm_is_pair (list1); list1 = SCM_CDR (list1))
521 {
522 elem = proc_tramp (proc, SCM_CAR (list1));
523 if (scm_is_true (elem))
524 {
525 newcell = scm_cons (elem, SCM_EOL);
526 *loc = newcell;
527 loc = SCM_CDRLOC (newcell);
528 }
529 }
530
531 /* check below that list1 is a proper list, and done */
532 lst = list1;
533 argnum = 2;
534 }
535 else if (SCM_NULLP (SCM_CDR (rest)))
536 {
537 /* two lists */
538 scm_t_trampoline_2 proc_tramp = scm_trampoline_2 (proc);
539 SCM list2 = SCM_CAR (rest);
540 SCM_ASSERT (proc_tramp, proc, SCM_ARG1, FUNC_NAME);
541
542 for (;;)
543 {
544 if (! scm_is_pair (list1))
545 {
546 lst = list1;
547 argnum = 2;
548 goto check_lst_and_done;
549 }
550 if (! scm_is_pair (list2))
551 {
552 lst = list2;
553 argnum = 3;
554 goto check_lst_and_done;
555 }
556 elem = proc_tramp (proc, SCM_CAR (list1), SCM_CAR (list2));
557 if (scm_is_true (elem))
558 {
559 newcell = scm_cons (elem, SCM_EOL);
560 *loc = newcell;
561 loc = SCM_CDRLOC (newcell);
562 }
563 list1 = SCM_CDR (list1);
564 list2 = SCM_CDR (list2);
565 }
566 }
567 else
568 {
569 /* three or more lists */
570 SCM lstlst, args, l, a;
571
572 /* lstlst is a list of the list arguments */
573 lstlst = scm_cons (list1, rest);
574
575 /* args is the argument list to pass to proc, same length as lstlst,
576 re-used for each call */
577 args = scm_list_copy (lstlst);
578
579 for (;;)
580 {
581 /* first elem of each list in lstlst into args, and step those
582 lstlst entries onto their next element */
583 for (l = lstlst, a = args, argnum = 2;
584 scm_is_pair (l);
585 l = SCM_CDR (l), a = SCM_CDR (a), argnum++)
586 {
587 lst = SCM_CAR (l); /* list argument */
588 if (! scm_is_pair (lst))
589 goto check_lst_and_done;
590 SCM_SETCAR (a, SCM_CAR (lst)); /* arg for proc */
591 SCM_SETCAR (l, SCM_CDR (lst)); /* keep rest of lst */
592 }
593
594 elem = scm_apply (proc, args, SCM_EOL);
595 if (scm_is_true (elem))
596 {
597 newcell = scm_cons (elem, SCM_EOL);
598 *loc = newcell;
599 loc = SCM_CDRLOC (newcell);
600 }
601 }
602 }
603
604 check_lst_and_done:
605 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, argnum, FUNC_NAME, "list");
606 return ret;
607}
608#undef FUNC_NAME
2b077051
KR
609
610
5df2ac97
KR
611SCM_DEFINE (scm_srfi1_find, "find", 2, 0, 0,
612 (SCM pred, SCM lst),
613 "Return the first element of @var{lst} which satisfies the\n"
614 "predicate @var{pred}, or return @code{#f} if no such element is\n"
615 "found.")
616#define FUNC_NAME s_scm_srfi1_find
617{
618 scm_t_trampoline_1 pred_tramp = scm_trampoline_1 (pred);
619 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
620
621 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
622 {
623 SCM elem = SCM_CAR (lst);
624 if (scm_is_true (pred_tramp (pred, elem)))
625 return elem;
626 }
627 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
628
629 return SCM_BOOL_F;
630}
631#undef FUNC_NAME
632
633
634SCM_DEFINE (scm_srfi1_find_tail, "find-tail", 2, 0, 0,
635 (SCM pred, SCM lst),
636 "Return the first pair of @var{lst} whose @sc{car} satisfies the\n"
637 "predicate @var{pred}, or return @code{#f} if no such element is\n"
638 "found.")
639#define FUNC_NAME s_scm_srfi1_find_tail
640{
641 scm_t_trampoline_1 pred_tramp = scm_trampoline_1 (pred);
642 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
643
644 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
645 if (scm_is_true (pred_tramp (pred, SCM_CAR (lst))))
646 return lst;
647 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
648
649 return SCM_BOOL_F;
650}
651#undef FUNC_NAME
652
653
de51f595
KR
654SCM_DEFINE (scm_srfi1_length_plus, "length+", 1, 0, 0,
655 (SCM lst),
656 "Return the length of @var{lst}, or @code{#f} if @var{lst} is\n"
657 "circular.")
658#define FUNC_NAME s_scm_srfi1_length_plus
659{
660 long len = scm_ilength (lst);
93ccaef0 661 return (len >= 0 ? SCM_I_MAKINUM (len) : SCM_BOOL_F);
de51f595
KR
662}
663#undef FUNC_NAME
664
665
d61261f0
KR
666/* This routine differs from the core list-copy in allowing improper lists.
667 Maybe the core could allow them similarly. */
668
669SCM_DEFINE (scm_srfi1_list_copy, "list-copy", 1, 0, 0,
670 (SCM lst),
671 "Return a copy of the given list @var{lst}.\n"
672 "\n"
673 "@var{lst} can be a proper or improper list. And if @var{lst}\n"
674 "is not a pair then it's treated as the final tail of an\n"
675 "improper list and simply returned.")
676#define FUNC_NAME s_scm_srfi1_list_copy
677{
678 SCM newlst;
679 SCM * fill_here;
680 SCM from_here;
681
682 newlst = lst;
683 fill_here = &newlst;
684 from_here = lst;
685
896df2d5 686 while (scm_is_pair (from_here))
d61261f0
KR
687 {
688 SCM c;
689 c = scm_cons (SCM_CAR (from_here), SCM_CDR (from_here));
690 *fill_here = c;
691 fill_here = SCM_CDRLOC (c);
692 from_here = SCM_CDR (from_here);
693 }
694 return newlst;
695}
696#undef FUNC_NAME
697
698
ee6aac97
MD
699/* Typechecking for multi-argument MAP and FOR-EACH.
700
701 Verify that each element of the vector ARGV, except for the first,
702 is a list and return minimum length. Attribute errors to WHO,
703 and claim that the i'th element of ARGV is WHO's i+2'th argument. */
704static inline int
705check_map_args (SCM argv,
706 long len,
707 SCM gf,
708 SCM proc,
709 SCM args,
710 const char *who)
711{
ee6aac97
MD
712 long i;
713
3c4ce91b 714 for (i = SCM_SIMPLE_VECTOR_LENGTH (argv) - 1; i >= 1; i--)
ee6aac97 715 {
3a0cf656 716 SCM elt = SCM_SIMPLE_VECTOR_REF (argv, i);
ee6aac97
MD
717 long elt_len;
718
896df2d5 719 if (!(scm_is_null (elt) || scm_is_pair (elt)))
ee6aac97
MD
720 {
721 check_map_error:
722 if (gf)
723 scm_apply_generic (gf, scm_cons (proc, args));
724 else
3c4ce91b 725 scm_wrong_type_arg (who, i + 2, elt);
ee6aac97
MD
726 }
727
3c4ce91b 728 elt_len = srfi1_ilength (elt);
ee6aac97
MD
729 if (elt_len < -1)
730 goto check_map_error;
731
732 if (len < 0 || (elt_len >= 0 && elt_len < len))
733 len = elt_len;
734 }
735 if (len < 0)
736 /* i == 0 */
737 goto check_map_error;
738
739 scm_remember_upto_here_1 (argv);
740 return len;
741}
742
743
744SCM_GPROC (s_srfi1_map, "map", 2, 0, 1, scm_srfi1_map, g_srfi1_map);
745
746/* Note: Currently, scm_srfi1_map applies PROC to the argument list(s)
747 sequentially, starting with the first element(s). This is used in
748 the Scheme procedure `map-in-order', which guarantees sequential
749 behaviour, is implemented using scm_map. If the behaviour changes,
750 we need to update `map-in-order'.
751*/
752
753SCM
754scm_srfi1_map (SCM proc, SCM arg1, SCM args)
755#define FUNC_NAME s_srfi1_map
756{
757 long i, len;
758 SCM res = SCM_EOL;
759 SCM *pres = &res;
ee6aac97
MD
760
761 len = srfi1_ilength (arg1);
896df2d5 762 SCM_GASSERTn ((scm_is_null (arg1) || scm_is_pair (arg1)) && len >= -1,
ee6aac97
MD
763 g_srfi1_map,
764 scm_cons2 (proc, arg1, args), SCM_ARG2, s_srfi1_map);
765 SCM_VALIDATE_REST_ARGUMENT (args);
896df2d5 766 if (scm_is_null (args))
ee6aac97
MD
767 {
768 scm_t_trampoline_1 call = scm_trampoline_1 (proc);
769 SCM_GASSERT2 (call, g_srfi1_map, proc, arg1, SCM_ARG1, s_srfi1_map);
770 SCM_GASSERT2 (len >= 0, g_srfi1_map, proc, arg1, SCM_ARG2, s_srfi1_map);
771 while (SCM_NIMP (arg1))
772 {
773 *pres = scm_list_1 (call (proc, SCM_CAR (arg1)));
774 pres = SCM_CDRLOC (*pres);
775 arg1 = SCM_CDR (arg1);
776 }
777 return res;
778 }
896df2d5 779 if (scm_is_null (SCM_CDR (args)))
ee6aac97
MD
780 {
781 SCM arg2 = SCM_CAR (args);
782 int len2 = srfi1_ilength (arg2);
783 scm_t_trampoline_2 call = scm_trampoline_2 (proc);
784 SCM_GASSERTn (call, g_srfi1_map,
785 scm_cons2 (proc, arg1, args), SCM_ARG1, s_srfi1_map);
786 if (len < 0 || (len2 >= 0 && len2 < len))
787 len = len2;
896df2d5 788 SCM_GASSERTn ((scm_is_null (arg2) || scm_is_pair (arg2))
ee6aac97
MD
789 && len >= 0 && len2 >= -1,
790 g_srfi1_map,
791 scm_cons2 (proc, arg1, args),
f9ac1c2d 792 len2 >= 0 ? SCM_ARG2 : SCM_ARG3,
ee6aac97
MD
793 s_srfi1_map);
794 while (len > 0)
795 {
796 *pres = scm_list_1 (call (proc, SCM_CAR (arg1), SCM_CAR (arg2)));
797 pres = SCM_CDRLOC (*pres);
798 arg1 = SCM_CDR (arg1);
799 arg2 = SCM_CDR (arg2);
800 --len;
801 }
802 return res;
803 }
804 args = scm_vector (arg1 = scm_cons (arg1, args));
ee6aac97
MD
805 len = check_map_args (args, len, g_srfi1_map, proc, arg1, s_srfi1_map);
806 while (len > 0)
807 {
808 arg1 = SCM_EOL;
3c4ce91b 809 for (i = SCM_SIMPLE_VECTOR_LENGTH (args) - 1; i >= 0; i--)
ee6aac97 810 {
3c4ce91b
MV
811 SCM elt = SCM_SIMPLE_VECTOR_REF (args, i);
812 arg1 = scm_cons (SCM_CAR (elt), arg1);
813 SCM_SIMPLE_VECTOR_SET (args, i, SCM_CDR (elt));
ee6aac97
MD
814 }
815 *pres = scm_list_1 (scm_apply (proc, arg1, SCM_EOL));
816 pres = SCM_CDRLOC (*pres);
817 --len;
818 }
819 return res;
820}
821#undef FUNC_NAME
822
823SCM_REGISTER_PROC (s_srfi1_map_in_order, "map-in-order", 2, 0, 1, scm_srfi1_map);
824
825SCM_GPROC (s_srfi1_for_each, "for-each", 2, 0, 1, scm_srfi1_for_each, g_srfi1_for_each);
826
827SCM
828scm_srfi1_for_each (SCM proc, SCM arg1, SCM args)
829#define FUNC_NAME s_srfi1_for_each
830{
ee6aac97
MD
831 long i, len;
832 len = srfi1_ilength (arg1);
896df2d5 833 SCM_GASSERTn ((scm_is_null (arg1) || scm_is_pair (arg1)) && len >= -1,
ee6aac97
MD
834 g_srfi1_for_each, scm_cons2 (proc, arg1, args),
835 SCM_ARG2, s_srfi1_for_each);
836 SCM_VALIDATE_REST_ARGUMENT (args);
896df2d5 837 if (scm_is_null (args))
ee6aac97
MD
838 {
839 scm_t_trampoline_1 call = scm_trampoline_1 (proc);
840 SCM_GASSERT2 (call, g_srfi1_for_each, proc, arg1,
841 SCM_ARG1, s_srfi1_for_each);
842 SCM_GASSERT2 (len >= 0, g_srfi1_for_each, proc, arg1,
843 SCM_ARG2, s_srfi1_map);
844 while (SCM_NIMP (arg1))
845 {
846 call (proc, SCM_CAR (arg1));
847 arg1 = SCM_CDR (arg1);
848 }
849 return SCM_UNSPECIFIED;
850 }
896df2d5 851 if (scm_is_null (SCM_CDR (args)))
ee6aac97
MD
852 {
853 SCM arg2 = SCM_CAR (args);
854 int len2 = srfi1_ilength (arg2);
855 scm_t_trampoline_2 call = scm_trampoline_2 (proc);
856 SCM_GASSERTn (call, g_srfi1_for_each,
857 scm_cons2 (proc, arg1, args), SCM_ARG1, s_srfi1_for_each);
858 if (len < 0 || (len2 >= 0 && len2 < len))
859 len = len2;
896df2d5 860 SCM_GASSERTn ((scm_is_null (arg2) || scm_is_pair (arg2))
f9ac1c2d 861 && len >= 0 && len2 >= -1,
ee6aac97
MD
862 g_srfi1_for_each,
863 scm_cons2 (proc, arg1, args),
f9ac1c2d 864 len2 >= 0 ? SCM_ARG2 : SCM_ARG3,
ee6aac97
MD
865 s_srfi1_for_each);
866 while (len > 0)
867 {
868 call (proc, SCM_CAR (arg1), SCM_CAR (arg2));
869 arg1 = SCM_CDR (arg1);
870 arg2 = SCM_CDR (arg2);
871 --len;
872 }
873 return SCM_UNSPECIFIED;
874 }
875 args = scm_vector (arg1 = scm_cons (arg1, args));
ee6aac97
MD
876 len = check_map_args (args, len, g_srfi1_for_each, proc, arg1,
877 s_srfi1_for_each);
878 while (len > 0)
879 {
880 arg1 = SCM_EOL;
3c4ce91b 881 for (i = SCM_SIMPLE_VECTOR_LENGTH (args) - 1; i >= 0; i--)
ee6aac97 882 {
3c4ce91b
MV
883 SCM elt = SCM_SIMPLE_VECTOR_REF (args, i);
884 arg1 = scm_cons (SCM_CAR (elt), arg1);
885 SCM_SIMPLE_VECTOR_SET (args, i, SCM_CDR (elt));
ee6aac97
MD
886 }
887 scm_apply (proc, arg1, SCM_EOL);
888 --len;
889 }
890 return SCM_UNSPECIFIED;
891}
892#undef FUNC_NAME
893
894
ee6aac97
MD
895SCM_DEFINE (scm_srfi1_member, "member", 2, 1, 0,
896 (SCM x, SCM lst, SCM pred),
4e3cc389
KR
897 "Return the first sublist of @var{lst} whose @sc{car} is equal\n"
898 "to @var{x}. If @var{x} does not appear in @var{lst}, return\n"
899 "@code{#f}.\n"
900 "\n"
901 "Equality is determined by @code{equal?}, or by the equality\n"
902 "predicate @var{=} if given. @var{=} is called @code{(= @var{x}\n"
903 "elem)}, ie.@: with the given @var{x} first, so for example to\n"
904 "find the first element greater than 5,\n"
905 "\n"
906 "@example\n"
907 "(member 5 '(3 5 1 7 2 9) <) @result{} (7 2 9)\n"
908 "@end example\n"
909 "\n"
910 "This version of @code{member} extends the core @code{member} by\n"
911 "accepting an equality predicate.")
ee6aac97
MD
912#define FUNC_NAME s_scm_srfi1_member
913{
914 scm_t_trampoline_2 equal_p;
915 SCM_VALIDATE_LIST (2, lst);
916 if (SCM_UNBNDP (pred))
917 equal_p = equal_trampoline;
918 else
919 {
920 equal_p = scm_trampoline_2 (pred);
921 SCM_ASSERT (equal_p, pred, 3, FUNC_NAME);
922 }
923 for (; !SCM_NULL_OR_NIL_P (lst); lst = SCM_CDR (lst))
924 {
2796304a 925 if (scm_is_true (equal_p (pred, x, SCM_CAR (lst))))
ee6aac97
MD
926 return lst;
927 }
928 return SCM_BOOL_F;
929}
930#undef FUNC_NAME
931
7692d26b
MD
932SCM_DEFINE (scm_srfi1_assoc, "assoc", 2, 1, 0,
933 (SCM key, SCM alist, SCM pred),
934 "Behaves like @code{assq} but uses third argument @var{pred?}\n"
935 "for key comparison. If @var{pred?} is not supplied,\n"
936 "@code{equal?} is used. (Extended from R5RS.)\n")
937#define FUNC_NAME s_scm_srfi1_assoc
938{
939 SCM ls = alist;
940 scm_t_trampoline_2 equal_p;
941 if (SCM_UNBNDP (pred))
942 equal_p = equal_trampoline;
943 else
944 {
945 equal_p = scm_trampoline_2 (pred);
946 SCM_ASSERT (equal_p, pred, 3, FUNC_NAME);
947 }
896df2d5 948 for(; scm_is_pair (ls); ls = SCM_CDR (ls))
7692d26b
MD
949 {
950 SCM tmp = SCM_CAR (ls);
896df2d5 951 SCM_ASSERT_TYPE (scm_is_pair (tmp), alist, SCM_ARG2, FUNC_NAME,
7692d26b 952 "association list");
00874d5f 953 if (scm_is_true (equal_p (pred, SCM_CAR (tmp), key)))
7692d26b
MD
954 return tmp;
955 }
956 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (ls), alist, SCM_ARG2, FUNC_NAME,
957 "association list");
958 return SCM_BOOL_F;
959}
960#undef FUNC_NAME
961
65978fb2
KR
962SCM_DEFINE (scm_srfi1_partition, "partition", 2, 0, 0,
963 (SCM pred, SCM list),
964 "Partition the elements of @var{list} with predicate @var{pred}.\n"
965 "Return two values: the list of elements satifying @var{pred} and\n"
966 "the list of elements @emph{not} satisfying @var{pred}. The order\n"
967 "of the output lists follows the order of @var{list}. @var{list}\n"
968 "is not mutated. One of the output lists may share memory with @var{list}.\n")
969#define FUNC_NAME s_scm_srfi1_partition
970{
971 /* In this implementation, the output lists don't share memory with
972 list, because it's probably not worth the effort. */
973 scm_t_trampoline_1 call = scm_trampoline_1(pred);
974 SCM kept = scm_cons(SCM_EOL, SCM_EOL);
975 SCM kept_tail = kept;
976 SCM dropped = scm_cons(SCM_EOL, SCM_EOL);
977 SCM dropped_tail = dropped;
978
979 SCM_ASSERT(call, pred, 2, FUNC_NAME);
980
981 for (; !SCM_NULL_OR_NIL_P (list); list = SCM_CDR(list)) {
982 SCM elt = SCM_CAR(list);
983 SCM new_tail = scm_cons(SCM_CAR(list), SCM_EOL);
00874d5f 984 if (scm_is_true (call (pred, elt))) {
65978fb2
KR
985 SCM_SETCDR(kept_tail, new_tail);
986 kept_tail = new_tail;
987 }
988 else {
989 SCM_SETCDR(dropped_tail, new_tail);
990 dropped_tail = new_tail;
991 }
992 }
993 /* re-use the initial conses for the values list */
994 SCM_SETCAR(kept, SCM_CDR(kept));
995 SCM_SETCDR(kept, dropped);
996 SCM_SETCAR(dropped, SCM_CDR(dropped));
997 SCM_SETCDR(dropped, SCM_EOL);
998 return scm_values(kept);
999}
1000#undef FUNC_NAME
1001
2b077051
KR
1002
1003SCM_DEFINE (scm_srfi1_partition_x, "partition!", 2, 0, 0,
1004 (SCM pred, SCM lst),
1005 "Split @var{lst} into those elements which do and don't satisfy\n"
1006 "the predicate @var{pred}.\n"
1007 "\n"
1008 "The return is two values (@pxref{Multiple Values}), the first\n"
1009 "being a list of all elements from @var{lst} which satisfy\n"
1010 "@var{pred}, the second a list of those which do not.\n"
1011 "\n"
1012 "The elements in the result lists are in the same order as in\n"
1013 "@var{lst} but the order in which the calls @code{(@var{pred}\n"
1014 "elem)} are made on the list elements is unspecified.\n"
1015 "\n"
1016 "@var{lst} may be modified to construct the return lists.")
1017#define FUNC_NAME s_scm_srfi1_partition_x
1018{
1019 SCM tlst, flst, *tp, *fp;
1020 scm_t_trampoline_1 pred_tramp;
1021
1022 pred_tramp = scm_trampoline_1 (pred);
1023 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
1024
1025 /* tlst and flst are the lists of true and false elements. tp and fp are
1026 where to store to append to them, initially &tlst and &flst, then
1027 SCM_CDRLOC of the last pair in the respective lists. */
1028
1029 tlst = SCM_EOL;
1030 flst = SCM_EOL;
1031 tp = &tlst;
1032 fp = &flst;
1033
1034 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
1035 {
1036 if (scm_is_true (pred_tramp (pred, SCM_CAR (lst))))
1037 {
1038 *tp = lst;
1039 tp = SCM_CDRLOC (lst);
1040 }
1041 else
1042 {
1043 *fp = lst;
1044 fp = SCM_CDRLOC (lst);
1045 }
1046 }
1047
1048 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
1049
1050 /* terminate whichever didn't get the last element(s) */
1051 *tp = SCM_EOL;
1052 *fp = SCM_EOL;
1053
1054 return scm_values (scm_list_2 (tlst, flst));
1055}
1056#undef FUNC_NAME
1057
1058
59747b8d
KR
1059SCM_DEFINE (scm_srfi1_remove, "remove", 2, 0, 0,
1060 (SCM pred, SCM list),
1061 "Return a list containing all elements from @var{lst} which do\n"
1062 "not satisfy the predicate @var{pred}. The elements in the\n"
1063 "result list have the same order as in @var{lst}. The order in\n"
1064 "which @var{pred} is applied to the list elements is not\n"
1065 "specified.")
1066#define FUNC_NAME s_scm_srfi1_remove
1067{
1068 scm_t_trampoline_1 call = scm_trampoline_1 (pred);
1069 SCM walk;
1070 SCM *prev;
1071 SCM res = SCM_EOL;
1072 SCM_ASSERT (call, pred, 1, FUNC_NAME);
1073 SCM_VALIDATE_LIST (2, list);
1074
1075 for (prev = &res, walk = list;
1076 scm_is_pair (walk);
1077 walk = SCM_CDR (walk))
1078 {
1079 if (scm_is_false (call (pred, SCM_CAR (walk))))
1080 {
1081 *prev = scm_cons (SCM_CAR (walk), SCM_EOL);
1082 prev = SCM_CDRLOC (*prev);
1083 }
1084 }
1085
1086 return res;
1087}
1088#undef FUNC_NAME
1089
2b077051
KR
1090
1091SCM_DEFINE (scm_srfi1_remove_x, "remove!", 2, 0, 0,
1092 (SCM pred, SCM list),
1093 "Return a list containing all elements from @var{list} which do\n"
1094 "not satisfy the predicate @var{pred}. The elements in the\n"
1095 "result list have the same order as in @var{list}. The order in\n"
1096 "which @var{pred} is applied to the list elements is not\n"
1097 "specified. @var{list} may be modified to build the return\n"
1098 "list.")
1099#define FUNC_NAME s_scm_srfi1_remove_x
1100{
1101 scm_t_trampoline_1 call = scm_trampoline_1 (pred);
1102 SCM walk;
1103 SCM *prev;
1104 SCM_ASSERT (call, pred, 1, FUNC_NAME);
1105 SCM_VALIDATE_LIST (2, list);
1106
1107 for (prev = &list, walk = list;
1108 scm_is_pair (walk);
1109 walk = SCM_CDR (walk))
1110 {
1111 if (scm_is_false (call (pred, SCM_CAR (walk))))
1112 prev = SCM_CDRLOC (walk);
1113 else
1114 *prev = SCM_CDR (walk);
1115 }
1116
1117 return list;
1118}
1119#undef FUNC_NAME
1120
1121
d2f57ee0
KR
1122SCM_DEFINE (scm_srfi1_split_at, "split-at", 2, 0, 0,
1123 (SCM lst, SCM n),
1124 "Return two values (multiple values), being a list of the\n"
1125 "elements before index @var{n} in @var{lst}, and a list of those\n"
1126 "after.")
1127#define FUNC_NAME s_scm_srfi1_split_at
1128{
1129 size_t nn;
1130 /* pre is a list of elements before the i split point, loc is the CDRLOC
1131 of the last cell, ie. where to store to append to it */
1132 SCM pre = SCM_EOL;
1133 SCM *loc = &pre;
1134
1135 for (nn = scm_to_size_t (n); nn != 0; nn--)
1136 {
1137 SCM_VALIDATE_CONS (SCM_ARG1, lst);
1138
1139 *loc = scm_cons (SCM_CAR (lst), SCM_EOL);
1140 loc = SCM_CDRLOC (*loc);
1141 lst = SCM_CDR(lst);
1142 }
1143 return scm_values (scm_list_2 (pre, lst));
1144}
1145#undef FUNC_NAME
1146
1147
1148SCM_DEFINE (scm_srfi1_split_at_x, "split-at!", 2, 0, 0,
1149 (SCM lst, SCM n),
1150 "Return two values (multiple values), being a list of the\n"
1151 "elements before index @var{n} in @var{lst}, and a list of those\n"
1152 "after. @var{lst} is modified to form those values.")
1153#define FUNC_NAME s_scm_srfi1_split_at
1154{
1155 size_t nn;
1156 SCM upto = lst;
1157 SCM *loc = &lst;
1158
1159 for (nn = scm_to_size_t (n); nn != 0; nn--)
1160 {
1161 SCM_VALIDATE_CONS (SCM_ARG1, upto);
1162
1163 loc = SCM_CDRLOC (upto);
1164 upto = SCM_CDR (upto);
1165 }
1166
1167 *loc = SCM_EOL;
1168 return scm_values (scm_list_2 (lst, upto));
1169}
1170#undef FUNC_NAME
1171
1172
2b077051
KR
1173SCM_DEFINE (scm_srfi1_take_right, "take-right", 2, 0, 0,
1174 (SCM lst, SCM n),
1175 "Return the a list containing the @var{n} last elements of\n"
1176 "@var{lst}.")
1177#define FUNC_NAME s_scm_srfi1_take_right
1178{
1179 SCM tail = scm_list_tail (lst, n);
1180 while (scm_is_pair (tail))
1181 {
1182 lst = SCM_CDR (lst);
1183 tail = SCM_CDR (tail);
1184 }
1185 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P(tail), tail, SCM_ARG1, FUNC_NAME, "list");
1186 return lst;
1187}
1188#undef FUNC_NAME
1189
1190
ee6aac97
MD
1191void
1192scm_init_srfi_1 (void)
1193{
a48d60b1 1194 SCM the_root_module = scm_lookup_closure_module (SCM_BOOL_F);
ee6aac97
MD
1195#ifndef SCM_MAGIC_SNARFER
1196#include "srfi/srfi-1.x"
1197#endif
a48d60b1
MD
1198 scm_c_extend_primitive_generic
1199 (SCM_VARIABLE_REF (scm_c_module_lookup (the_root_module, "map")),
1200 SCM_VARIABLE_REF (scm_c_lookup ("map")));
1201 scm_c_extend_primitive_generic
1202 (SCM_VARIABLE_REF (scm_c_module_lookup (the_root_module, "for-each")),
1203 SCM_VARIABLE_REF (scm_c_lookup ("for-each")));
ee6aac97
MD
1204}
1205
1206/* End of srfi-1.c. */