typo in lset-difference! name in with-test-prefix
[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
92205699 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
73be1d9e 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
b1fff4e7
KR
66SCM_DEFINE (scm_srfi1_alist_copy, "alist-copy", 1, 0, 0,
67 (SCM alist),
68 "Return a copy of @var{alist}, copying both the pairs comprising\n"
69 "the list and those making the associations.")
70#define FUNC_NAME s_scm_srfi1_alist_copy
71{
72 SCM ret, *p, elem, c;
73
74 /* ret is the list to return. p is where to append to it, initially &ret
75 then SCM_CDRLOC of the last pair. */
76 ret = SCM_EOL;
77 p = &ret;
78
79 for ( ; scm_is_pair (alist); alist = SCM_CDR (alist))
80 {
81 elem = SCM_CAR (alist);
82
83 /* each element of alist must be a pair */
84 SCM_ASSERT_TYPE (scm_is_pair (elem), alist, SCM_ARG1, FUNC_NAME,
85 "association list");
86
87 c = scm_cons (scm_cons (SCM_CAR (elem), SCM_CDR (elem)), SCM_EOL);
88 *p = c;
89 p = SCM_CDRLOC (c);
90 }
91
92 /* alist must be a proper list */
93 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (alist), alist, SCM_ARG1, FUNC_NAME,
94 "association list");
95 return ret;
96}
97#undef FUNC_NAME
98
99
6e9f3c26
KR
100SCM_DEFINE (scm_srfi1_break, "break", 2, 0, 0,
101 (SCM pred, SCM lst),
102 "Return two values, the longest initial prefix of @var{lst}\n"
103 "whose elements all fail the predicate @var{pred}, and the\n"
104 "remainder of @var{lst}.\n"
105 "\n"
106 "Note that the name @code{break} conflicts with the @code{break}\n"
107 "binding established by @code{while}. Applications wanting to\n"
108 "use @code{break} from within a @code{while} loop will need to\n"
109 "make a new define under a different name.")
110#define FUNC_NAME s_scm_srfi1_break
111{
112 scm_t_trampoline_1 pred_tramp;
113 SCM ret, *p;
114
115 pred_tramp = scm_trampoline_1 (pred);
116 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
117
118 ret = SCM_EOL;
119 p = &ret;
120 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
121 {
122 SCM elem = SCM_CAR (lst);
123 if (scm_is_true (pred_tramp (pred, elem)))
124 goto done;
125
126 /* want this elem, tack it onto the end of ret */
127 *p = scm_cons (elem, SCM_EOL);
128 p = SCM_CDRLOC (*p);
129 }
130 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
131
132 done:
133 return scm_values (scm_list_2 (ret, lst));
134}
135#undef FUNC_NAME
136
137
138SCM_DEFINE (scm_srfi1_break_x, "break!", 2, 0, 0,
139 (SCM pred, SCM lst),
140 "Return two values, the longest initial prefix of @var{lst}\n"
141 "whose elements all fail the predicate @var{pred}, and the\n"
142 "remainder of @var{lst}. @var{lst} may be modified to form the\n"
143 "return.")
144#define FUNC_NAME s_scm_srfi1_break_x
145{
146 SCM upto, *p;
147 scm_t_trampoline_1 pred_tramp;
148
149 pred_tramp = scm_trampoline_1 (pred);
150 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
151
152 p = &lst;
153 for (upto = lst; scm_is_pair (upto); upto = SCM_CDR (upto))
154 {
155 if (scm_is_true (pred_tramp (pred, SCM_CAR (upto))))
156 goto done;
157
158 /* want this element */
159 p = SCM_CDRLOC (upto);
160 }
161 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (upto), lst, SCM_ARG2, FUNC_NAME, "list");
162
163 done:
164 *p = SCM_EOL;
165 return scm_values (scm_list_2 (lst, upto));
166}
167#undef FUNC_NAME
168
169
e556f8c3
KR
170SCM_DEFINE (scm_srfi1_car_plus_cdr, "car+cdr", 1, 0, 0,
171 (SCM pair),
172 "Return two values, the @sc{car} and the @sc{cdr} of @var{pair}.")
173#define FUNC_NAME s_scm_srfi1_car_plus_cdr
174{
175 SCM_VALIDATE_CONS (SCM_ARG1, pair);
176 return scm_values (scm_list_2 (SCM_CAR (pair), SCM_CDR (pair)));
177}
178#undef FUNC_NAME
179
180
c66c6d53
KR
181SCM_DEFINE (scm_srfi1_concatenate, "concatenate", 1, 0, 0,
182 (SCM lstlst),
183 "Construct a list by appending all lists in @var{lstlst}.\n"
184 "\n"
185 "@code{concatenate} is the same as @code{(apply append\n"
186 "@var{lstlst})}. It exists because some Scheme implementations\n"
187 "have a limit on the number of arguments a function takes, which\n"
188 "the @code{apply} might exceed. In Guile there is no such\n"
189 "limit.")
190#define FUNC_NAME s_scm_srfi1_concatenate
191{
192 SCM_VALIDATE_LIST (SCM_ARG1, lstlst);
193 return scm_append (lstlst);
194}
195#undef FUNC_NAME
196
47f2726f 197
c66c6d53
KR
198SCM_DEFINE (scm_srfi1_concatenate_x, "concatenate!", 1, 0, 0,
199 (SCM lstlst),
200 "Construct a list by appending all lists in @var{lstlst}. Those\n"
201 "lists may be modified to produce the result.\n"
202 "\n"
203 "@code{concatenate!} is the same as @code{(apply append!\n"
204 "@var{lstlst})}. It exists because some Scheme implementations\n"
205 "have a limit on the number of arguments a function takes, which\n"
206 "the @code{apply} might exceed. In Guile there is no such\n"
207 "limit.")
208#define FUNC_NAME s_scm_srfi1_concatenate
209{
210 SCM_VALIDATE_LIST (SCM_ARG1, lstlst);
211 return scm_append_x (lstlst);
212}
213#undef FUNC_NAME
47f2726f
KR
214
215
110348ae 216SCM_DEFINE (scm_srfi1_count, "count", 2, 0, 1,
edea856c 217 (SCM pred, SCM list1, SCM rest),
110348ae
KR
218 "Return a count of the number of times @var{pred} returns true\n"
219 "when called on elements from the given lists.\n"
220 "\n"
221 "@var{pred} is called with @var{N} parameters @code{(@var{pred}\n"
222 "@var{elem1} @dots{} @var{elemN})}, each element being from the\n"
edea856c 223 "corresponding @var{list1} @dots{} @var{lstN}. The first call is\n"
110348ae
KR
224 "with the first element of each list, the second with the second\n"
225 "element from each, and so on.\n"
226 "\n"
227 "Counting stops when the end of the shortest list is reached.\n"
228 "At least one list must be non-circular.")
229#define FUNC_NAME s_scm_srfi1_count
230{
231 long count;
5fc743b4
KR
232 SCM lst;
233 int argnum;
110348ae
KR
234 SCM_VALIDATE_REST_ARGUMENT (rest);
235
236 count = 0;
237
896df2d5 238 if (scm_is_null (rest))
110348ae
KR
239 {
240 /* one list */
241 scm_t_trampoline_1 pred_tramp;
242 pred_tramp = scm_trampoline_1 (pred);
243 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
244
896df2d5 245 for ( ; scm_is_pair (list1); list1 = SCM_CDR (list1))
edea856c 246 count += scm_is_true (pred_tramp (pred, SCM_CAR (list1)));
110348ae 247
5fc743b4
KR
248 /* check below that list1 is a proper list, and done */
249 end_list1:
250 lst = list1;
251 argnum = 2;
110348ae 252 }
896df2d5 253 else if (scm_is_pair (rest) && scm_is_null (SCM_CDR (rest)))
110348ae
KR
254 {
255 /* two lists */
256 scm_t_trampoline_2 pred_tramp;
edea856c 257 SCM list2;
110348ae
KR
258
259 pred_tramp = scm_trampoline_2 (pred);
260 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
261
edea856c 262 list2 = SCM_CAR (rest);
110348ae
KR
263 for (;;)
264 {
896df2d5 265 if (! scm_is_pair (list1))
5fc743b4 266 goto end_list1;
896df2d5 267 if (! scm_is_pair (list2))
110348ae 268 {
5fc743b4
KR
269 lst = list2;
270 argnum = 3;
110348ae
KR
271 break;
272 }
00874d5f 273 count += scm_is_true (pred_tramp
edea856c
SJ
274 (pred, SCM_CAR (list1), SCM_CAR (list2)));
275 list1 = SCM_CDR (list1);
276 list2 = SCM_CDR (list2);
110348ae
KR
277 }
278 }
279 else
280 {
281 /* three or more lists */
eccd308a
KR
282 SCM vec, args, a;
283 size_t len, i;
110348ae 284
eccd308a
KR
285 /* vec is the list arguments */
286 vec = scm_vector (scm_cons (list1, rest));
287 len = SCM_SIMPLE_VECTOR_LENGTH (vec);
110348ae 288
eccd308a 289 /* args is the argument list to pass to pred, same length as vec,
110348ae 290 re-used for each call */
eccd308a 291 args = scm_make_list (SCM_I_MAKINUM (len), SCM_UNDEFINED);
110348ae
KR
292
293 for (;;)
294 {
eccd308a
KR
295 /* first elem of each list in vec into args, and step those
296 vec entries onto their next element */
297 for (i = 0, a = args, argnum = 2;
298 i < len;
299 i++, a = SCM_CDR (a), argnum++)
110348ae 300 {
eccd308a 301 lst = SCM_SIMPLE_VECTOR_REF (vec, i); /* list argument */
896df2d5 302 if (! scm_is_pair (lst))
5fc743b4 303 goto check_lst_and_done;
110348ae 304 SCM_SETCAR (a, SCM_CAR (lst)); /* arg for pred */
eccd308a 305 SCM_SIMPLE_VECTOR_SET (vec, i, SCM_CDR (lst)); /* rest of lst */
110348ae
KR
306 }
307
00874d5f 308 count += scm_is_true (scm_apply (pred, args, SCM_EOL));
110348ae
KR
309 }
310 }
5fc743b4
KR
311
312 check_lst_and_done:
313 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, argnum, FUNC_NAME, "list");
93ccaef0 314 return scm_from_long (count);
110348ae
KR
315}
316#undef FUNC_NAME
317
318
d0a634de
KR
319SCM_DEFINE (scm_srfi1_delete, "delete", 2, 1, 0,
320 (SCM x, SCM lst, SCM pred),
321 "Return a list containing the elements of @var{lst} but with\n"
322 "those equal to @var{x} deleted. The returned elements will be\n"
323 "in the same order as they were in @var{lst}.\n"
324 "\n"
325 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
326 "given. An equality call is made just once for each element,\n"
327 "but the order in which the calls are made on the elements is\n"
328 "unspecified.\n"
329 "\n"
330 "The equality calls are always @code{(pred x elem)}, ie.@: the\n"
331 "given @var{x} is first. This means for instance elements\n"
332 "greater than 5 can be deleted with @code{(delete 5 lst <)}.\n"
333 "\n"
334 "@var{lst} is not modified, but the returned list might share a\n"
335 "common tail with @var{lst}.")
336#define FUNC_NAME s_scm_srfi1_delete
337{
338 scm_t_trampoline_2 equal_p;
339 SCM ret, *p, keeplst;
340
341 if (SCM_UNBNDP (pred))
342 return scm_delete (x, lst);
343
344 equal_p = scm_trampoline_2 (pred);
345 SCM_ASSERT (equal_p, pred, SCM_ARG3, FUNC_NAME);
346
347 /* ret is the return list being constructed. p is where to append to it,
348 initially &ret then SCM_CDRLOC of the last pair. lst progresses as
349 elements are considered.
350
351 Elements to be retained are not immediately copied, instead keeplst is
352 the last pair in lst which is to be retained but not yet copied. When
353 there's no more deletions, *p can be set to keeplst to share the
354 remainder of the original lst. (The entire original lst if there's no
355 deletions at all.) */
356
357 keeplst = lst;
358 ret = SCM_EOL;
359 p = &ret;
360
896df2d5 361 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
d0a634de 362 {
00874d5f 363 if (scm_is_true (equal_p (pred, x, SCM_CAR (lst))))
d0a634de
KR
364 {
365 /* delete this element, so copy from keeplst (inclusive) to lst
366 (exclusive) onto ret */
bc36d050 367 while (! scm_is_eq (keeplst, lst))
d0a634de
KR
368 {
369 SCM c = scm_cons (SCM_CAR (keeplst), SCM_EOL);
370 *p = c;
371 p = SCM_CDRLOC (c);
372 keeplst = SCM_CDR (keeplst);
373 }
374
375 keeplst = SCM_CDR (lst);
376 }
377 }
378
379 /* final retained elements */
380 *p = keeplst;
381
382 /* demand that lst was a proper list */
383 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
384
385 return ret;
386}
387#undef FUNC_NAME
388
389
390SCM_DEFINE (scm_srfi1_delete_x, "delete!", 2, 1, 0,
391 (SCM x, SCM lst, SCM pred),
392 "Return a list containing the elements of @var{lst} but with\n"
393 "those equal to @var{x} deleted. The returned elements will be\n"
394 "in the same order as they were in @var{lst}.\n"
395 "\n"
396 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
397 "given. An equality call is made just once for each element,\n"
398 "but the order in which the calls are made on the elements is\n"
399 "unspecified.\n"
400 "\n"
401 "The equality calls are always @code{(pred x elem)}, ie.@: the\n"
402 "given @var{x} is first. This means for instance elements\n"
403 "greater than 5 can be deleted with @code{(delete 5 lst <)}.\n"
404 "\n"
405 "@var{lst} may be modified to construct the returned list.")
406#define FUNC_NAME s_scm_srfi1_delete_x
407{
408 scm_t_trampoline_2 equal_p;
409 SCM walk;
410 SCM *prev;
411
412 if (SCM_UNBNDP (pred))
413 return scm_delete_x (x, lst);
414
415 equal_p = scm_trampoline_2 (pred);
416 SCM_ASSERT (equal_p, pred, SCM_ARG3, FUNC_NAME);
417
418 for (prev = &lst, walk = lst;
896df2d5 419 scm_is_pair (walk);
d0a634de
KR
420 walk = SCM_CDR (walk))
421 {
00874d5f 422 if (scm_is_true (equal_p (pred, x, SCM_CAR (walk))))
d0a634de
KR
423 *prev = SCM_CDR (walk);
424 else
425 prev = SCM_CDRLOC (walk);
426 }
427
428 /* demand the input was a proper list */
429 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (walk), walk, SCM_ARG2, FUNC_NAME,"list");
430 return lst;
431}
432#undef FUNC_NAME
433
434
435SCM_DEFINE (scm_srfi1_delete_duplicates, "delete-duplicates", 1, 1, 0,
436 (SCM lst, SCM pred),
437 "Return a list containing the elements of @var{lst} but without\n"
438 "duplicates.\n"
439 "\n"
440 "When elements are equal, only the first in @var{lst} is\n"
441 "retained. Equal elements can be anywhere in @var{lst}, they\n"
442 "don't have to be adjacent. The returned list will have the\n"
443 "retained elements in the same order as they were in @var{lst}.\n"
444 "\n"
445 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
446 "given. Calls @code{(pred x y)} are made with element @var{x}\n"
447 "being before @var{y} in @var{lst}. A call is made at most once\n"
448 "for each combination, but the sequence of the calls across the\n"
449 "elements is unspecified.\n"
450 "\n"
451 "@var{lst} is not modified, but the return might share a common\n"
452 "tail with @var{lst}.\n"
453 "\n"
454 "In the worst case, this is an @math{O(N^2)} algorithm because\n"
455 "it must check each element against all those preceding it. For\n"
456 "long lists it is more efficient to sort and then compare only\n"
457 "adjacent elements.")
458#define FUNC_NAME s_scm_srfi1_delete_duplicates
459{
460 scm_t_trampoline_2 equal_p;
461 SCM ret, *p, keeplst, item, l;
462
463 /* ret is the new list constructed. p is where to append, initially &ret
464 then SCM_CDRLOC of the last pair. lst is advanced as each element is
465 considered.
466
467 Elements retained are not immediately appended to ret, instead keeplst
468 is the last pair in lst which is to be kept but is not yet copied.
469 Initially this is the first pair of lst, since the first element is
470 always retained.
471
472 *p is kept set to keeplst, so ret (inclusive) to lst (exclusive) is all
473 the elements retained, making the equality search loop easy.
474
475 If an item must be deleted, elements from keeplst (inclusive) to lst
476 (exclusive) must be copied and appended to ret. When there's no more
477 deletions, *p is left set to keeplst, so ret shares structure with the
478 original lst. (ret will be the entire original lst if there are no
479 deletions.) */
480
481 /* skip to end if an empty list (or something invalid) */
482 ret = lst;
896df2d5 483 if (scm_is_pair (lst))
d0a634de
KR
484 {
485 if (SCM_UNBNDP (pred))
486 equal_p = equal_trampoline;
487 else
488 {
489 equal_p = scm_trampoline_2 (pred);
490 SCM_ASSERT (equal_p, pred, SCM_ARG2, FUNC_NAME);
491 }
492
493 keeplst = lst;
494 p = &ret;
495
496 /* loop over lst elements starting from second */
497 for (;;)
498 {
499 lst = SCM_CDR (lst);
896df2d5 500 if (! scm_is_pair (lst))
d0a634de
KR
501 break;
502 item = SCM_CAR (lst);
503
504 /* loop searching ret upto lst */
bc36d050 505 for (l = ret; ! scm_is_eq (l, lst); l = SCM_CDR (l))
d0a634de 506 {
00874d5f 507 if (scm_is_true (equal_p (pred, SCM_CAR (l), item)))
d0a634de
KR
508 {
509 /* duplicate, don't want this element, so copy keeplst
510 (inclusive) to lst (exclusive) onto ret */
bc36d050 511 while (! scm_is_eq (keeplst, lst))
d0a634de
KR
512 {
513 SCM c = scm_cons (SCM_CAR (keeplst), SCM_EOL);
514 *p = c;
515 p = SCM_CDRLOC (c);
516 keeplst = SCM_CDR (keeplst);
517 }
518
519 keeplst = SCM_CDR (lst); /* elem after the one deleted */
520 *p = keeplst;
521 break;
522 }
523 }
524 }
525 }
526
527 /* demand that lst was a proper list */
528 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG1, FUNC_NAME, "list");
529
530 return ret;
531}
532#undef FUNC_NAME
533
534
535SCM_DEFINE (scm_srfi1_delete_duplicates_x, "delete-duplicates!", 1, 1, 0,
536 (SCM lst, SCM pred),
537 "Return a list containing the elements of @var{lst} but without\n"
538 "duplicates.\n"
539 "\n"
540 "When elements are equal, only the first in @var{lst} is\n"
541 "retained. Equal elements can be anywhere in @var{lst}, they\n"
542 "don't have to be adjacent. The returned list will have the\n"
543 "retained elements in the same order as they were in @var{lst}.\n"
544 "\n"
545 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
546 "given. Calls @code{(pred x y)} are made with element @var{x}\n"
547 "being before @var{y} in @var{lst}. A call is made at most once\n"
548 "for each combination, but the sequence of the calls across the\n"
549 "elements is unspecified.\n"
550 "\n"
551 "@var{lst} may be modified to construct the returned list.\n"
552 "\n"
553 "In the worst case, this is an @math{O(N^2)} algorithm because\n"
554 "it must check each element against all those preceding it. For\n"
555 "long lists it is more efficient to sort and then compare only\n"
556 "adjacent elements.")
557#define FUNC_NAME s_scm_srfi1_delete_duplicates_x
558{
559 scm_t_trampoline_2 equal_p;
560 SCM ret, endret, item, l;
561
562 /* ret is the return list, constructed from the pairs in lst. endret is
563 the last pair of ret, initially the first pair. lst is advanced as
564 elements are considered. */
565
566 /* skip to end if an empty list (or something invalid) */
567 ret = lst;
896df2d5 568 if (scm_is_pair (lst))
d0a634de
KR
569 {
570 if (SCM_UNBNDP (pred))
571 equal_p = equal_trampoline;
572 else
573 {
574 equal_p = scm_trampoline_2 (pred);
575 SCM_ASSERT (equal_p, pred, SCM_ARG2, FUNC_NAME);
576 }
577
578 endret = ret;
579
580 /* loop over lst elements starting from second */
581 for (;;)
582 {
583 lst = SCM_CDR (lst);
896df2d5 584 if (! scm_is_pair (lst))
d0a634de
KR
585 break;
586 item = SCM_CAR (lst);
587
588 /* is item equal to any element from ret to endret (inclusive)? */
589 l = ret;
590 for (;;)
591 {
00874d5f 592 if (scm_is_true (equal_p (pred, SCM_CAR (l), item)))
d0a634de
KR
593 break; /* equal, forget this element */
594
bc36d050 595 if (scm_is_eq (l, endret))
d0a634de
KR
596 {
597 /* not equal to any, so append this pair */
598 SCM_SETCDR (endret, lst);
599 endret = lst;
600 break;
601 }
602 l = SCM_CDR (l);
603 }
604 }
605
606 /* terminate, in case last element was deleted */
607 SCM_SETCDR (endret, SCM_EOL);
608 }
609
610 /* demand that lst was a proper list */
611 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG1, FUNC_NAME, "list");
612
613 return ret;
614}
615#undef FUNC_NAME
616
617
2b077051
KR
618SCM_DEFINE (scm_srfi1_drop_right, "drop-right", 2, 0, 0,
619 (SCM lst, SCM n),
620 "Return a new list containing all except the last @var{n}\n"
621 "elements of @var{lst}.")
622#define FUNC_NAME s_scm_srfi1_drop_right
623{
624 SCM tail = scm_list_tail (lst, n);
625 SCM ret = SCM_EOL;
626 SCM *rend = &ret;
627 while (scm_is_pair (tail))
628 {
629 *rend = scm_cons (SCM_CAR (lst), SCM_EOL);
630 rend = SCM_CDRLOC (*rend);
631
632 lst = SCM_CDR (lst);
633 tail = SCM_CDR (tail);
634 }
635 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P(tail), tail, SCM_ARG1, FUNC_NAME, "list");
636 return ret;
637}
638#undef FUNC_NAME
c1635946
KR
639
640
597dbd4e
KR
641SCM_DEFINE (scm_srfi1_drop_right_x, "drop-right!", 2, 0, 0,
642 (SCM lst, SCM n),
643 "Return the a list containing the @var{n} last elements of\n"
644 "@var{lst}. @var{lst} may be modified to build the return.")
645#define FUNC_NAME s_scm_srfi1_drop_right_x
646{
647 SCM tail, *p;
648
649 if (scm_is_eq (n, SCM_INUM0))
650 return lst;
651
652 tail = scm_list_tail (lst, n);
653 p = &lst;
654
655 /* p and tail work along the list, p being the cdrloc of the cell n steps
656 behind tail */
657 for ( ; scm_is_pair (tail); tail = SCM_CDR (tail))
658 p = SCM_CDRLOC (*p);
659
660 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P(tail), tail, SCM_ARG1, FUNC_NAME, "list");
661
662 *p = SCM_EOL;
663 return lst;
664}
665#undef FUNC_NAME
666
667
668SCM_DEFINE (scm_srfi1_drop_while, "drop-while", 2, 0, 0,
669 (SCM pred, SCM lst),
670 "Drop the longest initial prefix of @var{lst} whose elements all\n"
671 "satisfy the predicate @var{pred}.")
672#define FUNC_NAME s_scm_srfi1_drop_while
673{
674 scm_t_trampoline_1 pred_tramp = scm_trampoline_1 (pred);
675 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
676
677 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
678 if (scm_is_false (pred_tramp (pred, SCM_CAR (lst))))
679 goto done;
680
681 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
682 done:
683 return lst;
684}
685#undef FUNC_NAME
686
687
03731332
KR
688SCM_DEFINE (scm_srfi1_eighth, "eighth", 1, 0, 0,
689 (SCM lst),
690 "Return the eighth element of @var{lst}.")
691#define FUNC_NAME s_scm_srfi1_eighth
692{
693 return scm_list_ref (lst, SCM_I_MAKINUM (7));
694}
695#undef FUNC_NAME
696
697
698SCM_DEFINE (scm_srfi1_fifth, "fifth", 1, 0, 0,
699 (SCM lst),
700 "Return the fifth element of @var{lst}.")
701#define FUNC_NAME s_scm_srfi1_fifth
702{
703 return scm_list_ref (lst, SCM_I_MAKINUM (4));
704}
705#undef FUNC_NAME
706
707
c1635946
KR
708SCM_DEFINE (scm_srfi1_filter_map, "filter-map", 2, 0, 1,
709 (SCM proc, SCM list1, SCM rest),
710 "Apply @var{proc} to to the elements of @var{list1} @dots{} and\n"
711 "return a list of the results as per SRFI-1 @code{map}, except\n"
712 "that any @code{#f} results are omitted from the list returned.")
713#define FUNC_NAME s_scm_srfi1_filter_map
714{
715 SCM ret, *loc, elem, newcell, lst;
716 int argnum;
717
718 SCM_VALIDATE_REST_ARGUMENT (rest);
719
720 ret = SCM_EOL;
721 loc = &ret;
722
3c55f6f1 723 if (scm_is_null (rest))
c1635946
KR
724 {
725 /* one list */
726 scm_t_trampoline_1 proc_tramp = scm_trampoline_1 (proc);
727 SCM_ASSERT (proc_tramp, proc, SCM_ARG1, FUNC_NAME);
728
729 for ( ; scm_is_pair (list1); list1 = SCM_CDR (list1))
730 {
731 elem = proc_tramp (proc, SCM_CAR (list1));
732 if (scm_is_true (elem))
733 {
734 newcell = scm_cons (elem, SCM_EOL);
735 *loc = newcell;
736 loc = SCM_CDRLOC (newcell);
737 }
738 }
739
740 /* check below that list1 is a proper list, and done */
6507b831 741 end_list1:
c1635946
KR
742 lst = list1;
743 argnum = 2;
744 }
3c55f6f1 745 else if (scm_is_null (SCM_CDR (rest)))
c1635946
KR
746 {
747 /* two lists */
748 scm_t_trampoline_2 proc_tramp = scm_trampoline_2 (proc);
749 SCM list2 = SCM_CAR (rest);
750 SCM_ASSERT (proc_tramp, proc, SCM_ARG1, FUNC_NAME);
751
752 for (;;)
753 {
754 if (! scm_is_pair (list1))
6507b831 755 goto end_list1;
c1635946
KR
756 if (! scm_is_pair (list2))
757 {
758 lst = list2;
759 argnum = 3;
760 goto check_lst_and_done;
761 }
762 elem = proc_tramp (proc, SCM_CAR (list1), SCM_CAR (list2));
763 if (scm_is_true (elem))
764 {
765 newcell = scm_cons (elem, SCM_EOL);
766 *loc = newcell;
767 loc = SCM_CDRLOC (newcell);
768 }
769 list1 = SCM_CDR (list1);
770 list2 = SCM_CDR (list2);
771 }
772 }
773 else
774 {
775 /* three or more lists */
eccd308a
KR
776 SCM vec, args, a;
777 size_t len, i;
c1635946 778
eccd308a
KR
779 /* vec is the list arguments */
780 vec = scm_vector (scm_cons (list1, rest));
781 len = SCM_SIMPLE_VECTOR_LENGTH (vec);
c1635946 782
eccd308a 783 /* args is the argument list to pass to proc, same length as vec,
c1635946 784 re-used for each call */
eccd308a 785 args = scm_make_list (SCM_I_MAKINUM (len), SCM_UNDEFINED);
c1635946
KR
786
787 for (;;)
788 {
eccd308a
KR
789 /* first elem of each list in vec into args, and step those
790 vec entries onto their next element */
791 for (i = 0, a = args, argnum = 2;
792 i < len;
793 i++, a = SCM_CDR (a), argnum++)
c1635946 794 {
eccd308a 795 lst = SCM_SIMPLE_VECTOR_REF (vec, i); /* list argument */
c1635946
KR
796 if (! scm_is_pair (lst))
797 goto check_lst_and_done;
798 SCM_SETCAR (a, SCM_CAR (lst)); /* arg for proc */
eccd308a 799 SCM_SIMPLE_VECTOR_SET (vec, i, SCM_CDR (lst)); /* rest of lst */
c1635946
KR
800 }
801
802 elem = scm_apply (proc, args, SCM_EOL);
803 if (scm_is_true (elem))
804 {
805 newcell = scm_cons (elem, SCM_EOL);
806 *loc = newcell;
807 loc = SCM_CDRLOC (newcell);
808 }
809 }
810 }
811
812 check_lst_and_done:
813 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, argnum, FUNC_NAME, "list");
814 return ret;
815}
816#undef FUNC_NAME
2b077051
KR
817
818
5df2ac97
KR
819SCM_DEFINE (scm_srfi1_find, "find", 2, 0, 0,
820 (SCM pred, SCM lst),
821 "Return the first element of @var{lst} which satisfies the\n"
822 "predicate @var{pred}, or return @code{#f} if no such element is\n"
823 "found.")
824#define FUNC_NAME s_scm_srfi1_find
825{
826 scm_t_trampoline_1 pred_tramp = scm_trampoline_1 (pred);
827 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
828
829 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
830 {
831 SCM elem = SCM_CAR (lst);
832 if (scm_is_true (pred_tramp (pred, elem)))
833 return elem;
834 }
835 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
836
837 return SCM_BOOL_F;
838}
839#undef FUNC_NAME
840
841
842SCM_DEFINE (scm_srfi1_find_tail, "find-tail", 2, 0, 0,
843 (SCM pred, SCM lst),
844 "Return the first pair of @var{lst} whose @sc{car} satisfies the\n"
845 "predicate @var{pred}, or return @code{#f} if no such element is\n"
846 "found.")
847#define FUNC_NAME s_scm_srfi1_find_tail
848{
849 scm_t_trampoline_1 pred_tramp = scm_trampoline_1 (pred);
850 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
851
852 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
853 if (scm_is_true (pred_tramp (pred, SCM_CAR (lst))))
854 return lst;
855 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
856
857 return SCM_BOOL_F;
858}
859#undef FUNC_NAME
860
861
e556f8c3
KR
862SCM_DEFINE (scm_srfi1_fold, "fold", 3, 0, 1,
863 (SCM proc, SCM init, SCM list1, SCM rest),
864 "Apply @var{proc} to the elements of @var{lst1} @dots{}\n"
865 "@var{lstN} to build a result, and return that result.\n"
866 "\n"
867 "Each @var{proc} call is @code{(@var{proc} @var{elem1} @dots{}\n"
868 "@var{elemN} @var{previous})}, where @var{elem1} is from\n"
869 "@var{lst1}, through @var{elemN} from @var{lstN}.\n"
870 "@var{previous} is the return from the previous call to\n"
871 "@var{proc}, or the given @var{init} for the first call. If any\n"
872 "list is empty, just @var{init} is returned.\n"
873 "\n"
874 "@code{fold} works through the list elements from first to last.\n"
875 "The following shows a list reversal and the calls it makes,\n"
876 "\n"
877 "@example\n"
878 "(fold cons '() '(1 2 3))\n"
879 "\n"
880 "(cons 1 '())\n"
881 "(cons 2 '(1))\n"
882 "(cons 3 '(2 1)\n"
883 "@result{} (3 2 1)\n"
884 "@end example\n"
885 "\n"
886 "If @var{lst1} through @var{lstN} have different lengths,\n"
887 "@code{fold} stops when the end of the shortest is reached.\n"
888 "Ie.@: elements past the length of the shortest are ignored in\n"
889 "the other @var{lst}s. At least one @var{lst} must be\n"
890 "non-circular.\n"
891 "\n"
892 "The way @code{fold} builds a result from iterating is quite\n"
893 "general, it can do more than other iterations like say\n"
894 "@code{map} or @code{filter}. The following for example removes\n"
895 "adjacent duplicate elements from a list,\n"
896 "\n"
897 "@example\n"
898 "(define (delete-adjacent-duplicates lst)\n"
899 " (fold-right (lambda (elem ret)\n"
900 " (if (equal? elem (first ret))\n"
901 " ret\n"
902 " (cons elem ret)))\n"
903 " (list (last lst))\n"
904 " lst))\n"
905 "(delete-adjacent-duplicates '(1 2 3 3 4 4 4 5))\n"
906 "@result{} (1 2 3 4 5)\n"
907 "@end example\n"
908 "\n"
909 "Clearly the same sort of thing can be done with a\n"
910 "@code{for-each} and a variable in which to build the result,\n"
911 "but a self-contained @var{proc} can be re-used in multiple\n"
912 "contexts, where a @code{for-each} would have to be written out\n"
913 "each time.")
914#define FUNC_NAME s_scm_srfi1_fold
915{
916 SCM lst;
917 int argnum;
918 SCM_VALIDATE_REST_ARGUMENT (rest);
919
920 if (scm_is_null (rest))
921 {
922 /* one list */
923 scm_t_trampoline_2 proc_tramp = scm_trampoline_2 (proc);
924 SCM_ASSERT (proc_tramp, proc, SCM_ARG1, FUNC_NAME);
925
926 for ( ; scm_is_pair (list1); list1 = SCM_CDR (list1))
927 init = proc_tramp (proc, SCM_CAR (list1), init);
928
929 /* check below that list1 is a proper list, and done */
930 lst = list1;
931 argnum = 2;
932 }
933 else
934 {
935 /* two or more lists */
936 SCM vec, args, a;
937 size_t len, i;
938
939 /* vec is the list arguments */
940 vec = scm_vector (scm_cons (list1, rest));
941 len = SCM_SIMPLE_VECTOR_LENGTH (vec);
942
943 /* args is the argument list to pass to proc, same length as vec,
944 re-used for each call */
945 args = scm_make_list (SCM_I_MAKINUM (len+1), SCM_UNDEFINED);
946
947 for (;;)
948 {
949 /* first elem of each list in vec into args, and step those
950 vec entries onto their next element */
951 for (i = 0, a = args, argnum = 2;
952 i < len;
953 i++, a = SCM_CDR (a), argnum++)
954 {
955 lst = SCM_SIMPLE_VECTOR_REF (vec, i); /* list argument */
956 if (! scm_is_pair (lst))
957 goto check_lst_and_done;
958 SCM_SETCAR (a, SCM_CAR (lst)); /* arg for proc */
959 SCM_SIMPLE_VECTOR_SET (vec, i, SCM_CDR (lst)); /* rest of lst */
960 }
961 SCM_SETCAR (a, init);
962
963 init = scm_apply (proc, args, SCM_EOL);
964 }
965 }
966
967 check_lst_and_done:
968 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, argnum, FUNC_NAME, "list");
969 return init;
970}
971#undef FUNC_NAME
972
973
974SCM_DEFINE (scm_srfi1_last, "last", 1, 0, 0,
975 (SCM lst),
976 "Like @code{cons}, but with interchanged arguments. Useful\n"
977 "mostly when passed to higher-order procedures.")
978#define FUNC_NAME s_scm_srfi1_last
979{
980 SCM pair = scm_last_pair (lst);
981 /* scm_last_pair returns SCM_EOL for an empty list */
982 SCM_VALIDATE_CONS (SCM_ARG1, pair);
983 return SCM_CAR (pair);
984}
985#undef FUNC_NAME
986
987
de51f595
KR
988SCM_DEFINE (scm_srfi1_length_plus, "length+", 1, 0, 0,
989 (SCM lst),
990 "Return the length of @var{lst}, or @code{#f} if @var{lst} is\n"
991 "circular.")
992#define FUNC_NAME s_scm_srfi1_length_plus
993{
994 long len = scm_ilength (lst);
93ccaef0 995 return (len >= 0 ? SCM_I_MAKINUM (len) : SCM_BOOL_F);
de51f595
KR
996}
997#undef FUNC_NAME
998
999
e556f8c3
KR
1000SCM_DEFINE (scm_srfi1_list_index, "list-index", 2, 0, 1,
1001 (SCM pred, SCM list1, SCM rest),
1002 "Return the index of the first set of elements, one from each of\n"
1003 "@var{lst1}@dots{}@var{lstN}, which satisfies @var{pred}.\n"
1004 "\n"
1005 "@var{pred} is called as @code{(@var{pred} elem1 @dots{}\n"
1006 "elemN)}. Searching stops when the end of the shortest\n"
1007 "@var{lst} is reached. The return index starts from 0 for the\n"
1008 "first set of elements. If no set of elements pass then the\n"
1009 "return is @code{#f}.\n"
1010 "\n"
1011 "@example\n"
1012 "(list-index odd? '(2 4 6 9)) @result{} 3\n"
1013 "(list-index = '(1 2 3) '(3 1 2)) @result{} #f\n"
1014 "@end example")
1015#define FUNC_NAME s_scm_srfi1_list_index
1016{
1017 long n = 0;
1018 SCM lst;
1019 int argnum;
1020 SCM_VALIDATE_REST_ARGUMENT (rest);
1021
1022 if (scm_is_null (rest))
1023 {
1024 /* one list */
1025 scm_t_trampoline_1 pred_tramp = scm_trampoline_1 (pred);
1026 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
1027
1028 for ( ; scm_is_pair (list1); n++, list1 = SCM_CDR (list1))
1029 if (scm_is_true (pred_tramp (pred, SCM_CAR (list1))))
1030 return SCM_I_MAKINUM (n);
1031
1032 /* not found, check below that list1 is a proper list */
1033 end_list1:
1034 lst = list1;
1035 argnum = 2;
1036 }
1037 else if (scm_is_pair (rest) && scm_is_null (SCM_CDR (rest)))
1038 {
1039 /* two lists */
1040 SCM list2 = SCM_CAR (rest);
1041 scm_t_trampoline_2 pred_tramp = scm_trampoline_2 (pred);
1042 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
1043
1044 for ( ; ; n++)
1045 {
1046 if (! scm_is_pair (list1))
1047 goto end_list1;
1048 if (! scm_is_pair (list2))
1049 {
1050 lst = list2;
1051 argnum = 3;
1052 break;
1053 }
1054 if (scm_is_true (pred_tramp (pred,
1055 SCM_CAR (list1), SCM_CAR (list2))))
1056 return SCM_I_MAKINUM (n);
1057
1058 list1 = SCM_CDR (list1);
1059 list2 = SCM_CDR (list2);
1060 }
1061 }
1062 else
1063 {
1064 /* three or more lists */
1065 SCM vec, args, a;
1066 size_t len, i;
1067
1068 /* vec is the list arguments */
1069 vec = scm_vector (scm_cons (list1, rest));
1070 len = SCM_SIMPLE_VECTOR_LENGTH (vec);
1071
1072 /* args is the argument list to pass to pred, same length as vec,
1073 re-used for each call */
1074 args = scm_make_list (SCM_I_MAKINUM (len), SCM_UNDEFINED);
1075
1076 for ( ; ; n++)
1077 {
1078 /* first elem of each list in vec into args, and step those
1079 vec entries onto their next element */
1080 for (i = 0, a = args, argnum = 2;
1081 i < len;
1082 i++, a = SCM_CDR (a), argnum++)
1083 {
1084 lst = SCM_SIMPLE_VECTOR_REF (vec, i); /* list argument */
1085 if (! scm_is_pair (lst))
1086 goto not_found_check_lst;
1087 SCM_SETCAR (a, SCM_CAR (lst)); /* arg for pred */
1088 SCM_SIMPLE_VECTOR_SET (vec, i, SCM_CDR (lst)); /* rest of lst */
1089 }
1090
1091 if (scm_is_true (scm_apply (pred, args, SCM_EOL)))
1092 return SCM_I_MAKINUM (n);
1093 }
1094 }
1095
1096 not_found_check_lst:
1097 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, argnum, FUNC_NAME, "list");
1098 return SCM_BOOL_F;
1099}
1100#undef FUNC_NAME
1101
1102
d61261f0
KR
1103/* This routine differs from the core list-copy in allowing improper lists.
1104 Maybe the core could allow them similarly. */
1105
1106SCM_DEFINE (scm_srfi1_list_copy, "list-copy", 1, 0, 0,
1107 (SCM lst),
1108 "Return a copy of the given list @var{lst}.\n"
1109 "\n"
1110 "@var{lst} can be a proper or improper list. And if @var{lst}\n"
1111 "is not a pair then it's treated as the final tail of an\n"
1112 "improper list and simply returned.")
1113#define FUNC_NAME s_scm_srfi1_list_copy
1114{
1115 SCM newlst;
1116 SCM * fill_here;
1117 SCM from_here;
1118
1119 newlst = lst;
1120 fill_here = &newlst;
1121 from_here = lst;
1122
896df2d5 1123 while (scm_is_pair (from_here))
d61261f0
KR
1124 {
1125 SCM c;
1126 c = scm_cons (SCM_CAR (from_here), SCM_CDR (from_here));
1127 *fill_here = c;
1128 fill_here = SCM_CDRLOC (c);
1129 from_here = SCM_CDR (from_here);
1130 }
1131 return newlst;
1132}
1133#undef FUNC_NAME
1134
1135
e556f8c3
KR
1136SCM_DEFINE (scm_srfi1_list_tabulate, "list-tabulate", 2, 0, 0,
1137 (SCM n, SCM proc),
1138 "Return an @var{n}-element list, where each list element is\n"
1139 "produced by applying the procedure @var{init-proc} to the\n"
1140 "corresponding list index. The order in which @var{init-proc}\n"
1141 "is applied to the indices is not specified.")
1142#define FUNC_NAME s_scm_srfi1_list_tabulate
1143{
1144 long i, nn;
1145 scm_t_trampoline_1 proc_tramp = scm_trampoline_1 (proc);
1146 SCM ret = SCM_EOL;
1147
b730fbf1 1148 nn = scm_to_signed_integer (n, 0, LONG_MAX);
e556f8c3
KR
1149 SCM_ASSERT (proc_tramp, proc, SCM_ARG2, FUNC_NAME);
1150
1151 for (i = nn-1; i >= 0; i--)
b730fbf1 1152 ret = scm_cons (proc_tramp (proc, scm_from_long (i)), ret);
e556f8c3
KR
1153
1154 return ret;
1155}
1156#undef FUNC_NAME
1157
1158
597dbd4e
KR
1159SCM_DEFINE (scm_srfi1_lset_adjoin, "lset-adjoin", 2, 0, 1,
1160 (SCM equal, SCM lst, SCM rest),
1161 "Add to @var{list} any of the given @var{elem}s not already in\n"
1162 "the list. @var{elem}s are @code{cons}ed onto the start of\n"
1163 "@var{list} (so the return shares a common tail with\n"
1164 "@var{list}), but the order they're added is unspecified.\n"
1165 "\n"
1166 "The given @var{=} procedure is used for comparing elements,\n"
1167 "called as @code{(@var{=} listelem elem)}, ie.@: the second\n"
1168 "argument is one of the given @var{elem} parameters.\n"
1169 "\n"
1170 "@example\n"
1171 "(lset-adjoin eqv? '(1 2 3) 4 1 5) @result{} (5 4 1 2 3)\n"
1172 "@end example")
1173#define FUNC_NAME s_scm_srfi1_lset_adjoin
1174{
1175 scm_t_trampoline_2 equal_tramp;
1176 SCM l, elem;
1177
1178 equal_tramp = scm_trampoline_2 (equal);
1179 SCM_ASSERT (equal_tramp, equal, SCM_ARG1, FUNC_NAME);
1180 SCM_VALIDATE_REST_ARGUMENT (rest);
1181
1182 /* It's not clear if duplicates among the `rest' elements are meant to be
1183 cast out. The spec says `=' is called as (= list-elem rest-elem),
1184 suggesting perhaps not, but the reference implementation shows the
1185 "list" at each stage as including those "rest" elements already added.
1186 The latter corresponds to what's described for lset-union, so that's
1187 what's done here. */
1188
1189 for ( ; scm_is_pair (rest); rest = SCM_CDR (rest))
1190 {
1191 elem = SCM_CAR (rest);
1192
1193 for (l = lst; scm_is_pair (l); l = SCM_CDR (l))
1194 if (scm_is_true (equal_tramp (equal, SCM_CAR (l), elem)))
1195 goto next_elem; /* elem already in lst, don't add */
1196
1197 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P(l), lst, SCM_ARG2, FUNC_NAME, "list");
1198
1199 /* elem is not equal to anything already in lst, add it */
1200 lst = scm_cons (elem, lst);
1201
1202 next_elem:
1203 ;
1204 }
1205
1206 return lst;
1207}
1208#undef FUNC_NAME
1209
1210
ee6aac97
MD
1211/* Typechecking for multi-argument MAP and FOR-EACH.
1212
1213 Verify that each element of the vector ARGV, except for the first,
1214 is a list and return minimum length. Attribute errors to WHO,
1215 and claim that the i'th element of ARGV is WHO's i+2'th argument. */
1216static inline int
1217check_map_args (SCM argv,
1218 long len,
1219 SCM gf,
1220 SCM proc,
1221 SCM args,
1222 const char *who)
1223{
ee6aac97 1224 long i;
705f4f57 1225 SCM elt;
ee6aac97 1226
3c4ce91b 1227 for (i = SCM_SIMPLE_VECTOR_LENGTH (argv) - 1; i >= 1; i--)
ee6aac97
MD
1228 {
1229 long elt_len;
705f4f57 1230 elt = SCM_SIMPLE_VECTOR_REF (argv, i);
ee6aac97 1231
896df2d5 1232 if (!(scm_is_null (elt) || scm_is_pair (elt)))
705f4f57 1233 goto check_map_error;
ee6aac97 1234
3c4ce91b 1235 elt_len = srfi1_ilength (elt);
ee6aac97
MD
1236 if (elt_len < -1)
1237 goto check_map_error;
1238
1239 if (len < 0 || (elt_len >= 0 && elt_len < len))
1240 len = elt_len;
1241 }
705f4f57 1242
ee6aac97 1243 if (len < 0)
705f4f57
MV
1244 {
1245 /* i == 0 */
1246 elt = SCM_EOL;
1247 check_map_error:
1248 if (gf)
1249 scm_apply_generic (gf, scm_cons (proc, args));
1250 else
1251 scm_wrong_type_arg (who, i + 2, elt);
1252 }
1253
ee6aac97
MD
1254 scm_remember_upto_here_1 (argv);
1255 return len;
1256}
1257
1258
1259SCM_GPROC (s_srfi1_map, "map", 2, 0, 1, scm_srfi1_map, g_srfi1_map);
1260
1261/* Note: Currently, scm_srfi1_map applies PROC to the argument list(s)
1262 sequentially, starting with the first element(s). This is used in
1263 the Scheme procedure `map-in-order', which guarantees sequential
1264 behaviour, is implemented using scm_map. If the behaviour changes,
1265 we need to update `map-in-order'.
1266*/
1267
1268SCM
1269scm_srfi1_map (SCM proc, SCM arg1, SCM args)
1270#define FUNC_NAME s_srfi1_map
1271{
1272 long i, len;
1273 SCM res = SCM_EOL;
1274 SCM *pres = &res;
ee6aac97
MD
1275
1276 len = srfi1_ilength (arg1);
896df2d5 1277 SCM_GASSERTn ((scm_is_null (arg1) || scm_is_pair (arg1)) && len >= -1,
ee6aac97
MD
1278 g_srfi1_map,
1279 scm_cons2 (proc, arg1, args), SCM_ARG2, s_srfi1_map);
1280 SCM_VALIDATE_REST_ARGUMENT (args);
896df2d5 1281 if (scm_is_null (args))
ee6aac97
MD
1282 {
1283 scm_t_trampoline_1 call = scm_trampoline_1 (proc);
1284 SCM_GASSERT2 (call, g_srfi1_map, proc, arg1, SCM_ARG1, s_srfi1_map);
1285 SCM_GASSERT2 (len >= 0, g_srfi1_map, proc, arg1, SCM_ARG2, s_srfi1_map);
1286 while (SCM_NIMP (arg1))
1287 {
1288 *pres = scm_list_1 (call (proc, SCM_CAR (arg1)));
1289 pres = SCM_CDRLOC (*pres);
1290 arg1 = SCM_CDR (arg1);
1291 }
1292 return res;
1293 }
896df2d5 1294 if (scm_is_null (SCM_CDR (args)))
ee6aac97
MD
1295 {
1296 SCM arg2 = SCM_CAR (args);
1297 int len2 = srfi1_ilength (arg2);
1298 scm_t_trampoline_2 call = scm_trampoline_2 (proc);
1299 SCM_GASSERTn (call, g_srfi1_map,
1300 scm_cons2 (proc, arg1, args), SCM_ARG1, s_srfi1_map);
1301 if (len < 0 || (len2 >= 0 && len2 < len))
1302 len = len2;
896df2d5 1303 SCM_GASSERTn ((scm_is_null (arg2) || scm_is_pair (arg2))
ee6aac97
MD
1304 && len >= 0 && len2 >= -1,
1305 g_srfi1_map,
1306 scm_cons2 (proc, arg1, args),
f9ac1c2d 1307 len2 >= 0 ? SCM_ARG2 : SCM_ARG3,
ee6aac97
MD
1308 s_srfi1_map);
1309 while (len > 0)
1310 {
1311 *pres = scm_list_1 (call (proc, SCM_CAR (arg1), SCM_CAR (arg2)));
1312 pres = SCM_CDRLOC (*pres);
1313 arg1 = SCM_CDR (arg1);
1314 arg2 = SCM_CDR (arg2);
1315 --len;
1316 }
1317 return res;
1318 }
1319 args = scm_vector (arg1 = scm_cons (arg1, args));
ee6aac97
MD
1320 len = check_map_args (args, len, g_srfi1_map, proc, arg1, s_srfi1_map);
1321 while (len > 0)
1322 {
1323 arg1 = SCM_EOL;
3c4ce91b 1324 for (i = SCM_SIMPLE_VECTOR_LENGTH (args) - 1; i >= 0; i--)
ee6aac97 1325 {
3c4ce91b
MV
1326 SCM elt = SCM_SIMPLE_VECTOR_REF (args, i);
1327 arg1 = scm_cons (SCM_CAR (elt), arg1);
1328 SCM_SIMPLE_VECTOR_SET (args, i, SCM_CDR (elt));
ee6aac97
MD
1329 }
1330 *pres = scm_list_1 (scm_apply (proc, arg1, SCM_EOL));
1331 pres = SCM_CDRLOC (*pres);
1332 --len;
1333 }
1334 return res;
1335}
1336#undef FUNC_NAME
1337
1338SCM_REGISTER_PROC (s_srfi1_map_in_order, "map-in-order", 2, 0, 1, scm_srfi1_map);
1339
1340SCM_GPROC (s_srfi1_for_each, "for-each", 2, 0, 1, scm_srfi1_for_each, g_srfi1_for_each);
1341
1342SCM
1343scm_srfi1_for_each (SCM proc, SCM arg1, SCM args)
1344#define FUNC_NAME s_srfi1_for_each
1345{
ee6aac97
MD
1346 long i, len;
1347 len = srfi1_ilength (arg1);
896df2d5 1348 SCM_GASSERTn ((scm_is_null (arg1) || scm_is_pair (arg1)) && len >= -1,
ee6aac97
MD
1349 g_srfi1_for_each, scm_cons2 (proc, arg1, args),
1350 SCM_ARG2, s_srfi1_for_each);
1351 SCM_VALIDATE_REST_ARGUMENT (args);
896df2d5 1352 if (scm_is_null (args))
ee6aac97
MD
1353 {
1354 scm_t_trampoline_1 call = scm_trampoline_1 (proc);
1355 SCM_GASSERT2 (call, g_srfi1_for_each, proc, arg1,
1356 SCM_ARG1, s_srfi1_for_each);
1357 SCM_GASSERT2 (len >= 0, g_srfi1_for_each, proc, arg1,
1358 SCM_ARG2, s_srfi1_map);
1359 while (SCM_NIMP (arg1))
1360 {
1361 call (proc, SCM_CAR (arg1));
1362 arg1 = SCM_CDR (arg1);
1363 }
1364 return SCM_UNSPECIFIED;
1365 }
896df2d5 1366 if (scm_is_null (SCM_CDR (args)))
ee6aac97
MD
1367 {
1368 SCM arg2 = SCM_CAR (args);
1369 int len2 = srfi1_ilength (arg2);
1370 scm_t_trampoline_2 call = scm_trampoline_2 (proc);
1371 SCM_GASSERTn (call, g_srfi1_for_each,
1372 scm_cons2 (proc, arg1, args), SCM_ARG1, s_srfi1_for_each);
1373 if (len < 0 || (len2 >= 0 && len2 < len))
1374 len = len2;
896df2d5 1375 SCM_GASSERTn ((scm_is_null (arg2) || scm_is_pair (arg2))
f9ac1c2d 1376 && len >= 0 && len2 >= -1,
ee6aac97
MD
1377 g_srfi1_for_each,
1378 scm_cons2 (proc, arg1, args),
f9ac1c2d 1379 len2 >= 0 ? SCM_ARG2 : SCM_ARG3,
ee6aac97
MD
1380 s_srfi1_for_each);
1381 while (len > 0)
1382 {
1383 call (proc, SCM_CAR (arg1), SCM_CAR (arg2));
1384 arg1 = SCM_CDR (arg1);
1385 arg2 = SCM_CDR (arg2);
1386 --len;
1387 }
1388 return SCM_UNSPECIFIED;
1389 }
1390 args = scm_vector (arg1 = scm_cons (arg1, args));
ee6aac97
MD
1391 len = check_map_args (args, len, g_srfi1_for_each, proc, arg1,
1392 s_srfi1_for_each);
1393 while (len > 0)
1394 {
1395 arg1 = SCM_EOL;
3c4ce91b 1396 for (i = SCM_SIMPLE_VECTOR_LENGTH (args) - 1; i >= 0; i--)
ee6aac97 1397 {
3c4ce91b
MV
1398 SCM elt = SCM_SIMPLE_VECTOR_REF (args, i);
1399 arg1 = scm_cons (SCM_CAR (elt), arg1);
1400 SCM_SIMPLE_VECTOR_SET (args, i, SCM_CDR (elt));
ee6aac97
MD
1401 }
1402 scm_apply (proc, arg1, SCM_EOL);
1403 --len;
1404 }
1405 return SCM_UNSPECIFIED;
1406}
1407#undef FUNC_NAME
1408
1409
ee6aac97
MD
1410SCM_DEFINE (scm_srfi1_member, "member", 2, 1, 0,
1411 (SCM x, SCM lst, SCM pred),
4e3cc389
KR
1412 "Return the first sublist of @var{lst} whose @sc{car} is equal\n"
1413 "to @var{x}. If @var{x} does not appear in @var{lst}, return\n"
1414 "@code{#f}.\n"
1415 "\n"
1416 "Equality is determined by @code{equal?}, or by the equality\n"
1417 "predicate @var{=} if given. @var{=} is called @code{(= @var{x}\n"
1418 "elem)}, ie.@: with the given @var{x} first, so for example to\n"
1419 "find the first element greater than 5,\n"
1420 "\n"
1421 "@example\n"
1422 "(member 5 '(3 5 1 7 2 9) <) @result{} (7 2 9)\n"
1423 "@end example\n"
1424 "\n"
1425 "This version of @code{member} extends the core @code{member} by\n"
1426 "accepting an equality predicate.")
ee6aac97
MD
1427#define FUNC_NAME s_scm_srfi1_member
1428{
1429 scm_t_trampoline_2 equal_p;
1430 SCM_VALIDATE_LIST (2, lst);
1431 if (SCM_UNBNDP (pred))
1432 equal_p = equal_trampoline;
1433 else
1434 {
1435 equal_p = scm_trampoline_2 (pred);
1436 SCM_ASSERT (equal_p, pred, 3, FUNC_NAME);
1437 }
1438 for (; !SCM_NULL_OR_NIL_P (lst); lst = SCM_CDR (lst))
1439 {
2796304a 1440 if (scm_is_true (equal_p (pred, x, SCM_CAR (lst))))
ee6aac97
MD
1441 return lst;
1442 }
1443 return SCM_BOOL_F;
1444}
1445#undef FUNC_NAME
1446
7692d26b
MD
1447SCM_DEFINE (scm_srfi1_assoc, "assoc", 2, 1, 0,
1448 (SCM key, SCM alist, SCM pred),
1449 "Behaves like @code{assq} but uses third argument @var{pred?}\n"
1450 "for key comparison. If @var{pred?} is not supplied,\n"
1451 "@code{equal?} is used. (Extended from R5RS.)\n")
1452#define FUNC_NAME s_scm_srfi1_assoc
1453{
1454 SCM ls = alist;
1455 scm_t_trampoline_2 equal_p;
1456 if (SCM_UNBNDP (pred))
1457 equal_p = equal_trampoline;
1458 else
1459 {
1460 equal_p = scm_trampoline_2 (pred);
1461 SCM_ASSERT (equal_p, pred, 3, FUNC_NAME);
1462 }
896df2d5 1463 for(; scm_is_pair (ls); ls = SCM_CDR (ls))
7692d26b
MD
1464 {
1465 SCM tmp = SCM_CAR (ls);
896df2d5 1466 SCM_ASSERT_TYPE (scm_is_pair (tmp), alist, SCM_ARG2, FUNC_NAME,
7692d26b 1467 "association list");
00874d5f 1468 if (scm_is_true (equal_p (pred, SCM_CAR (tmp), key)))
7692d26b
MD
1469 return tmp;
1470 }
1471 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (ls), alist, SCM_ARG2, FUNC_NAME,
1472 "association list");
1473 return SCM_BOOL_F;
1474}
1475#undef FUNC_NAME
1476
03731332
KR
1477
1478SCM_DEFINE (scm_srfi1_ninth, "ninth", 1, 0, 0,
1479 (SCM lst),
1480 "Return the ninth element of @var{lst}.")
1481#define FUNC_NAME s_scm_srfi1_ninth
1482{
b730fbf1 1483 return scm_list_ref (lst, scm_from_int (8));
03731332
KR
1484}
1485#undef FUNC_NAME
1486
1487
e556f8c3
KR
1488SCM_DEFINE (scm_srfi1_not_pair_p, "not-pair?", 1, 0, 0,
1489 (SCM obj),
1490 "Return @code{#t} is @var{obj} is not a pair, @code{#f}\n"
1491 "otherwise.\n"
1492 "\n"
1493 "This is shorthand notation @code{(not (pair? @var{obj}))} and\n"
1494 "is supposed to be used for end-of-list checking in contexts\n"
1495 "where dotted lists are allowed.")
1496#define FUNC_NAME s_scm_srfi1_not_pair_p
1497{
1498 return scm_from_bool (! scm_is_pair (obj));
1499}
1500#undef FUNC_NAME
1501
1502
65978fb2
KR
1503SCM_DEFINE (scm_srfi1_partition, "partition", 2, 0, 0,
1504 (SCM pred, SCM list),
1505 "Partition the elements of @var{list} with predicate @var{pred}.\n"
1506 "Return two values: the list of elements satifying @var{pred} and\n"
1507 "the list of elements @emph{not} satisfying @var{pred}. The order\n"
1508 "of the output lists follows the order of @var{list}. @var{list}\n"
1509 "is not mutated. One of the output lists may share memory with @var{list}.\n")
1510#define FUNC_NAME s_scm_srfi1_partition
1511{
1512 /* In this implementation, the output lists don't share memory with
1513 list, because it's probably not worth the effort. */
1514 scm_t_trampoline_1 call = scm_trampoline_1(pred);
1515 SCM kept = scm_cons(SCM_EOL, SCM_EOL);
1516 SCM kept_tail = kept;
1517 SCM dropped = scm_cons(SCM_EOL, SCM_EOL);
1518 SCM dropped_tail = dropped;
1519
1520 SCM_ASSERT(call, pred, 2, FUNC_NAME);
1521
1522 for (; !SCM_NULL_OR_NIL_P (list); list = SCM_CDR(list)) {
1523 SCM elt = SCM_CAR(list);
1524 SCM new_tail = scm_cons(SCM_CAR(list), SCM_EOL);
00874d5f 1525 if (scm_is_true (call (pred, elt))) {
65978fb2
KR
1526 SCM_SETCDR(kept_tail, new_tail);
1527 kept_tail = new_tail;
1528 }
1529 else {
1530 SCM_SETCDR(dropped_tail, new_tail);
1531 dropped_tail = new_tail;
1532 }
1533 }
1534 /* re-use the initial conses for the values list */
1535 SCM_SETCAR(kept, SCM_CDR(kept));
1536 SCM_SETCDR(kept, dropped);
1537 SCM_SETCAR(dropped, SCM_CDR(dropped));
1538 SCM_SETCDR(dropped, SCM_EOL);
1539 return scm_values(kept);
1540}
1541#undef FUNC_NAME
1542
2b077051
KR
1543
1544SCM_DEFINE (scm_srfi1_partition_x, "partition!", 2, 0, 0,
1545 (SCM pred, SCM lst),
1546 "Split @var{lst} into those elements which do and don't satisfy\n"
1547 "the predicate @var{pred}.\n"
1548 "\n"
1549 "The return is two values (@pxref{Multiple Values}), the first\n"
1550 "being a list of all elements from @var{lst} which satisfy\n"
1551 "@var{pred}, the second a list of those which do not.\n"
1552 "\n"
1553 "The elements in the result lists are in the same order as in\n"
1554 "@var{lst} but the order in which the calls @code{(@var{pred}\n"
1555 "elem)} are made on the list elements is unspecified.\n"
1556 "\n"
1557 "@var{lst} may be modified to construct the return lists.")
1558#define FUNC_NAME s_scm_srfi1_partition_x
1559{
1560 SCM tlst, flst, *tp, *fp;
1561 scm_t_trampoline_1 pred_tramp;
1562
1563 pred_tramp = scm_trampoline_1 (pred);
1564 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
1565
1566 /* tlst and flst are the lists of true and false elements. tp and fp are
1567 where to store to append to them, initially &tlst and &flst, then
1568 SCM_CDRLOC of the last pair in the respective lists. */
1569
1570 tlst = SCM_EOL;
1571 flst = SCM_EOL;
1572 tp = &tlst;
1573 fp = &flst;
1574
1575 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
1576 {
1577 if (scm_is_true (pred_tramp (pred, SCM_CAR (lst))))
1578 {
1579 *tp = lst;
1580 tp = SCM_CDRLOC (lst);
1581 }
1582 else
1583 {
1584 *fp = lst;
1585 fp = SCM_CDRLOC (lst);
1586 }
1587 }
1588
1589 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
1590
1591 /* terminate whichever didn't get the last element(s) */
1592 *tp = SCM_EOL;
1593 *fp = SCM_EOL;
1594
1595 return scm_values (scm_list_2 (tlst, flst));
1596}
1597#undef FUNC_NAME
1598
1599
597dbd4e
KR
1600SCM_DEFINE (scm_srfi1_reduce, "reduce", 3, 0, 0,
1601 (SCM proc, SCM def, SCM lst),
1602 "@code{reduce} is a variant of @code{fold}, where the first call\n"
1603 "to @var{proc} is on two elements from @var{lst}, rather than\n"
1604 "one element and a given initial value.\n"
1605 "\n"
1606 "If @var{lst} is empty, @code{reduce} returns @var{def} (this is\n"
1607 "the only use for @var{def}). If @var{lst} has just one element\n"
1608 "then that's the return value. Otherwise @var{proc} is called\n"
1609 "on the elements of @var{lst}.\n"
1610 "\n"
1611 "Each @var{proc} call is @code{(@var{proc} @var{elem}\n"
1612 "@var{previous})}, where @var{elem} is from @var{lst} (the\n"
1613 "second and subsequent elements of @var{lst}), and\n"
1614 "@var{previous} is the return from the previous call to\n"
1615 "@var{proc}. The first element of @var{lst} is the\n"
1616 "@var{previous} for the first call to @var{proc}.\n"
1617 "\n"
1618 "For example, the following adds a list of numbers, the calls\n"
1619 "made to @code{+} are shown. (Of course @code{+} accepts\n"
1620 "multiple arguments and can add a list directly, with\n"
1621 "@code{apply}.)\n"
1622 "\n"
1623 "@example\n"
1624 "(reduce + 0 '(5 6 7)) @result{} 18\n"
1625 "\n"
1626 "(+ 6 5) @result{} 11\n"
1627 "(+ 7 11) @result{} 18\n"
1628 "@end example\n"
1629 "\n"
1630 "@code{reduce} can be used instead of @code{fold} where the\n"
1631 "@var{init} value is an ``identity'', meaning a value which\n"
1632 "under @var{proc} doesn't change the result, in this case 0 is\n"
1633 "an identity since @code{(+ 5 0)} is just 5. @code{reduce}\n"
1634 "avoids that unnecessary call.")
1635#define FUNC_NAME s_scm_srfi1_reduce
1636{
1637 scm_t_trampoline_2 proc_tramp = scm_trampoline_2 (proc);
1638 SCM ret;
1639
1640 SCM_ASSERT (proc_tramp, proc, SCM_ARG1, FUNC_NAME);
1641
1642 ret = def; /* if lst is empty */
1643 if (scm_is_pair (lst))
1644 {
1645 ret = SCM_CAR (lst); /* if lst has one element */
1646
1647 for (lst = SCM_CDR (lst); scm_is_pair (lst); lst = SCM_CDR (lst))
1648 ret = proc_tramp (proc, SCM_CAR (lst), ret);
1649 }
1650
1651 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG3, FUNC_NAME, "list");
1652 return ret;
1653}
1654#undef FUNC_NAME
1655
1656
1657SCM_DEFINE (scm_srfi1_reduce_right, "reduce-right", 3, 0, 0,
1658 (SCM proc, SCM def, SCM lst),
1659 "@code{reduce-right} is a variant of @code{fold-right}, where\n"
1660 "the first call to @var{proc} is on two elements from @var{lst},\n"
1661 "rather than one element and a given initial value.\n"
1662 "\n"
1663 "If @var{lst} is empty, @code{reduce-right} returns @var{def}\n"
1664 "(this is the only use for @var{def}). If @var{lst} has just\n"
1665 "one element then that's the return value. Otherwise @var{proc}\n"
1666 "is called on the elements of @var{lst}.\n"
1667 "\n"
1668 "Each @var{proc} call is @code{(@var{proc} @var{elem}\n"
1669 "@var{previous})}, where @var{elem} is from @var{lst} (the\n"
1670 "second last and then working back to the first element of\n"
1671 "@var{lst}), and @var{previous} is the return from the previous\n"
1672 "call to @var{proc}. The last element of @var{lst} is the\n"
1673 "@var{previous} for the first call to @var{proc}.\n"
1674 "\n"
1675 "For example, the following adds a list of numbers, the calls\n"
1676 "made to @code{+} are shown. (Of course @code{+} accepts\n"
1677 "multiple arguments and can add a list directly, with\n"
1678 "@code{apply}.)\n"
1679 "\n"
1680 "@example\n"
1681 "(reduce-right + 0 '(5 6 7)) @result{} 18\n"
1682 "\n"
1683 "(+ 6 7) @result{} 13\n"
1684 "(+ 5 13) @result{} 18\n"
1685 "@end example\n"
1686 "\n"
1687 "@code{reduce-right} can be used instead of @code{fold-right}\n"
1688 "where the @var{init} value is an ``identity'', meaning a value\n"
1689 "which under @var{proc} doesn't change the result, in this case\n"
1690 "0 is an identity since @code{(+ 7 0)} is just 5.\n"
1691 "@code{reduce-right} avoids that unnecessary call.\n"
1692 "\n"
1693 "@code{reduce} should be preferred over @code{reduce-right} if\n"
1694 "the order of processing doesn't matter, or can be arranged\n"
1695 "either way, since @code{reduce} is a little more efficient.")
1696#define FUNC_NAME s_scm_srfi1_reduce_right
1697{
1698 /* To work backwards across a list requires either repeatedly traversing
1699 to get each previous element, or using some memory for a reversed or
1700 random-access form. Repeated traversal might not be too terrible, but
1701 is of course quadratic complexity and hence to be avoided in case LST
1702 is long. A vector is preferred over a reversed list since it's more
1703 compact and is less work for the gc to collect. */
1704
1705 scm_t_trampoline_2 proc_tramp = scm_trampoline_2 (proc);
1706 SCM ret, vec;
1707 long len, i;
1708
1709 SCM_ASSERT (proc_tramp, proc, SCM_ARG1, FUNC_NAME);
1710
1711 if (SCM_NULL_OR_NIL_P (lst))
1712 return def;
1713
1714 vec = scm_vector (lst);
1715 len = SCM_SIMPLE_VECTOR_LENGTH (vec);
1716
1717 ret = SCM_SIMPLE_VECTOR_REF (vec, len-1);
1718 for (i = len-2; i >= 0; i--)
1719 ret = proc_tramp (proc, SCM_SIMPLE_VECTOR_REF (vec, i), ret);
1720
1721 return ret;
1722}
1723#undef FUNC_NAME
1724
1725
59747b8d
KR
1726SCM_DEFINE (scm_srfi1_remove, "remove", 2, 0, 0,
1727 (SCM pred, SCM list),
1728 "Return a list containing all elements from @var{lst} which do\n"
1729 "not satisfy the predicate @var{pred}. The elements in the\n"
1730 "result list have the same order as in @var{lst}. The order in\n"
1731 "which @var{pred} is applied to the list elements is not\n"
1732 "specified.")
1733#define FUNC_NAME s_scm_srfi1_remove
1734{
1735 scm_t_trampoline_1 call = scm_trampoline_1 (pred);
1736 SCM walk;
1737 SCM *prev;
1738 SCM res = SCM_EOL;
1739 SCM_ASSERT (call, pred, 1, FUNC_NAME);
1740 SCM_VALIDATE_LIST (2, list);
1741
1742 for (prev = &res, walk = list;
1743 scm_is_pair (walk);
1744 walk = SCM_CDR (walk))
1745 {
1746 if (scm_is_false (call (pred, SCM_CAR (walk))))
1747 {
1748 *prev = scm_cons (SCM_CAR (walk), SCM_EOL);
1749 prev = SCM_CDRLOC (*prev);
1750 }
1751 }
1752
1753 return res;
1754}
1755#undef FUNC_NAME
1756
2b077051
KR
1757
1758SCM_DEFINE (scm_srfi1_remove_x, "remove!", 2, 0, 0,
1759 (SCM pred, SCM list),
1760 "Return a list containing all elements from @var{list} which do\n"
1761 "not satisfy the predicate @var{pred}. The elements in the\n"
1762 "result list have the same order as in @var{list}. The order in\n"
1763 "which @var{pred} is applied to the list elements is not\n"
1764 "specified. @var{list} may be modified to build the return\n"
1765 "list.")
1766#define FUNC_NAME s_scm_srfi1_remove_x
1767{
1768 scm_t_trampoline_1 call = scm_trampoline_1 (pred);
1769 SCM walk;
1770 SCM *prev;
1771 SCM_ASSERT (call, pred, 1, FUNC_NAME);
1772 SCM_VALIDATE_LIST (2, list);
1773
1774 for (prev = &list, walk = list;
1775 scm_is_pair (walk);
1776 walk = SCM_CDR (walk))
1777 {
1778 if (scm_is_false (call (pred, SCM_CAR (walk))))
1779 prev = SCM_CDRLOC (walk);
1780 else
1781 *prev = SCM_CDR (walk);
1782 }
1783
1784 return list;
1785}
1786#undef FUNC_NAME
1787
1788
03731332
KR
1789SCM_DEFINE (scm_srfi1_seventh, "seventh", 1, 0, 0,
1790 (SCM lst),
1791 "Return the seventh element of @var{lst}.")
1792#define FUNC_NAME s_scm_srfi1_seventh
1793{
b730fbf1 1794 return scm_list_ref (lst, scm_from_int (6));
03731332
KR
1795}
1796#undef FUNC_NAME
1797
1798
1799SCM_DEFINE (scm_srfi1_sixth, "sixth", 1, 0, 0,
1800 (SCM lst),
1801 "Return the sixth element of @var{lst}.")
1802#define FUNC_NAME s_scm_srfi1_sixth
1803{
b730fbf1 1804 return scm_list_ref (lst, scm_from_int (5));
03731332
KR
1805}
1806#undef FUNC_NAME
1807
1808
597dbd4e
KR
1809SCM_DEFINE (scm_srfi1_span, "span", 2, 0, 0,
1810 (SCM pred, SCM lst),
1811 "Return two values, the longest initial prefix of @var{lst}\n"
1812 "whose elements all satisfy the predicate @var{pred}, and the\n"
1813 "remainder of @var{lst}.")
1814#define FUNC_NAME s_scm_srfi1_span
1815{
1816 scm_t_trampoline_1 pred_tramp;
1817 SCM ret, *p;
1818
1819 pred_tramp = scm_trampoline_1 (pred);
1820 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
1821
1822 ret = SCM_EOL;
1823 p = &ret;
1824 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
1825 {
1826 SCM elem = SCM_CAR (lst);
1827 if (scm_is_false (pred_tramp (pred, elem)))
1828 goto done;
1829
1830 /* want this elem, tack it onto the end of ret */
1831 *p = scm_cons (elem, SCM_EOL);
1832 p = SCM_CDRLOC (*p);
1833 }
1834 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
1835
1836 done:
1837 return scm_values (scm_list_2 (ret, lst));
1838}
1839#undef FUNC_NAME
1840
1841
1842SCM_DEFINE (scm_srfi1_span_x, "span!", 2, 0, 0,
1843 (SCM pred, SCM lst),
1844 "Return two values, the longest initial prefix of @var{lst}\n"
1845 "whose elements all satisfy the predicate @var{pred}, and the\n"
1846 "remainder of @var{lst}. @var{lst} may be modified to form the\n"
1847 "return.")
1848#define FUNC_NAME s_scm_srfi1_span_x
1849{
1850 SCM upto, *p;
1851 scm_t_trampoline_1 pred_tramp;
1852
1853 pred_tramp = scm_trampoline_1 (pred);
1854 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
1855
1856 p = &lst;
1857 for (upto = lst; scm_is_pair (upto); upto = SCM_CDR (upto))
1858 {
1859 if (scm_is_false (pred_tramp (pred, SCM_CAR (upto))))
1860 goto done;
1861
1862 /* want this element */
1863 p = SCM_CDRLOC (upto);
1864 }
1865 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (upto), lst, SCM_ARG2, FUNC_NAME, "list");
1866
1867 done:
1868 *p = SCM_EOL;
1869 return scm_values (scm_list_2 (lst, upto));
1870}
1871#undef FUNC_NAME
1872
1873
d2f57ee0
KR
1874SCM_DEFINE (scm_srfi1_split_at, "split-at", 2, 0, 0,
1875 (SCM lst, SCM n),
1876 "Return two values (multiple values), being a list of the\n"
1877 "elements before index @var{n} in @var{lst}, and a list of those\n"
1878 "after.")
1879#define FUNC_NAME s_scm_srfi1_split_at
1880{
1881 size_t nn;
1882 /* pre is a list of elements before the i split point, loc is the CDRLOC
1883 of the last cell, ie. where to store to append to it */
1884 SCM pre = SCM_EOL;
1885 SCM *loc = &pre;
1886
1887 for (nn = scm_to_size_t (n); nn != 0; nn--)
1888 {
1889 SCM_VALIDATE_CONS (SCM_ARG1, lst);
1890
1891 *loc = scm_cons (SCM_CAR (lst), SCM_EOL);
1892 loc = SCM_CDRLOC (*loc);
1893 lst = SCM_CDR(lst);
1894 }
1895 return scm_values (scm_list_2 (pre, lst));
1896}
1897#undef FUNC_NAME
1898
1899
1900SCM_DEFINE (scm_srfi1_split_at_x, "split-at!", 2, 0, 0,
1901 (SCM lst, SCM n),
1902 "Return two values (multiple values), being a list of the\n"
1903 "elements before index @var{n} in @var{lst}, and a list of those\n"
1904 "after. @var{lst} is modified to form those values.")
1905#define FUNC_NAME s_scm_srfi1_split_at
1906{
1907 size_t nn;
1908 SCM upto = lst;
1909 SCM *loc = &lst;
1910
1911 for (nn = scm_to_size_t (n); nn != 0; nn--)
1912 {
1913 SCM_VALIDATE_CONS (SCM_ARG1, upto);
1914
1915 loc = SCM_CDRLOC (upto);
1916 upto = SCM_CDR (upto);
1917 }
1918
1919 *loc = SCM_EOL;
1920 return scm_values (scm_list_2 (lst, upto));
1921}
1922#undef FUNC_NAME
1923
1924
597dbd4e
KR
1925SCM_DEFINE (scm_srfi1_take_x, "take!", 2, 0, 0,
1926 (SCM lst, SCM n),
1927 "Return a list containing the first @var{n} elements of\n"
1928 "@var{lst}.")
1929#define FUNC_NAME s_scm_srfi1_take_x
1930{
1931 long nn;
1932 SCM pos;
1933
b730fbf1 1934 nn = scm_to_signed_integer (n, 0, LONG_MAX);
597dbd4e
KR
1935 if (nn == 0)
1936 return SCM_EOL;
1937
b730fbf1 1938 pos = scm_list_tail (lst, scm_from_long (nn - 1));
597dbd4e
KR
1939
1940 /* Must have at least one cell left, mustn't have reached the end of an
1941 n-1 element list. SCM_VALIDATE_CONS here gives the same error as
1942 scm_list_tail does on say an n-2 element list, though perhaps a range
1943 error would make more sense (for both). */
1944 SCM_VALIDATE_CONS (SCM_ARG1, pos);
1945
1946 SCM_SETCDR (pos, SCM_EOL);
1947 return lst;
1948}
1949#undef FUNC_NAME
1950
1951
2b077051
KR
1952SCM_DEFINE (scm_srfi1_take_right, "take-right", 2, 0, 0,
1953 (SCM lst, SCM n),
1954 "Return the a list containing the @var{n} last elements of\n"
1955 "@var{lst}.")
1956#define FUNC_NAME s_scm_srfi1_take_right
1957{
1958 SCM tail = scm_list_tail (lst, n);
1959 while (scm_is_pair (tail))
1960 {
1961 lst = SCM_CDR (lst);
1962 tail = SCM_CDR (tail);
1963 }
1964 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P(tail), tail, SCM_ARG1, FUNC_NAME, "list");
1965 return lst;
1966}
1967#undef FUNC_NAME
1968
1969
597dbd4e
KR
1970SCM_DEFINE (scm_srfi1_take_while, "take-while", 2, 0, 0,
1971 (SCM pred, SCM lst),
1972 "Return a new list which is the longest initial prefix of\n"
1973 "@var{lst} whose elements all satisfy the predicate @var{pred}.")
1974#define FUNC_NAME s_scm_srfi1_take_while
1975{
1976 scm_t_trampoline_1 pred_tramp;
1977 SCM ret, *p;
1978
1979 pred_tramp = scm_trampoline_1 (pred);
1980 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
1981
1982 ret = SCM_EOL;
1983 p = &ret;
1984 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
1985 {
1986 SCM elem = SCM_CAR (lst);
1987 if (scm_is_false (pred_tramp (pred, elem)))
1988 goto done;
1989
1990 /* want this elem, tack it onto the end of ret */
1991 *p = scm_cons (elem, SCM_EOL);
1992 p = SCM_CDRLOC (*p);
1993 }
1994 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
1995
1996 done:
1997 return ret;
1998}
1999#undef FUNC_NAME
2000
2001
2002SCM_DEFINE (scm_srfi1_take_while_x, "take-while!", 2, 0, 0,
2003 (SCM pred, SCM lst),
2004 "Return the longest initial prefix of @var{lst} whose elements\n"
2005 "all satisfy the predicate @var{pred}. @var{lst} may be\n"
2006 "modified to form the return.")
2007#define FUNC_NAME s_scm_srfi1_take_while_x
2008{
2009 SCM upto, *p;
2010 scm_t_trampoline_1 pred_tramp;
2011
2012 pred_tramp = scm_trampoline_1 (pred);
2013 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
2014
2015 p = &lst;
2016 for (upto = lst; scm_is_pair (upto); upto = SCM_CDR (upto))
2017 {
2018 if (scm_is_false (pred_tramp (pred, SCM_CAR (upto))))
2019 goto done;
2020
2021 /* want this element */
2022 p = SCM_CDRLOC (upto);
2023 }
2024 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (upto), lst, SCM_ARG2, FUNC_NAME, "list");
2025
2026 done:
2027 *p = SCM_EOL;
2028 return lst;
2029}
2030#undef FUNC_NAME
2031
2032
03731332
KR
2033SCM_DEFINE (scm_srfi1_tenth, "tenth", 1, 0, 0,
2034 (SCM lst),
2035 "Return the tenth element of @var{lst}.")
2036#define FUNC_NAME s_scm_srfi1_tenth
2037{
b730fbf1 2038 return scm_list_ref (lst, scm_from_int (9));
03731332
KR
2039}
2040#undef FUNC_NAME
2041
2042
e556f8c3
KR
2043SCM_DEFINE (scm_srfi1_xcons, "xcons", 2, 0, 0,
2044 (SCM d, SCM a),
2045 "Like @code{cons}, but with interchanged arguments. Useful\n"
2046 "mostly when passed to higher-order procedures.")
2047#define FUNC_NAME s_scm_srfi1_xcons
2048{
2049 return scm_cons (a, d);
2050}
2051#undef FUNC_NAME
2052
2053
ee6aac97
MD
2054void
2055scm_init_srfi_1 (void)
2056{
a48d60b1 2057 SCM the_root_module = scm_lookup_closure_module (SCM_BOOL_F);
ee6aac97
MD
2058#ifndef SCM_MAGIC_SNARFER
2059#include "srfi/srfi-1.x"
2060#endif
a48d60b1
MD
2061 scm_c_extend_primitive_generic
2062 (SCM_VARIABLE_REF (scm_c_module_lookup (the_root_module, "map")),
2063 SCM_VARIABLE_REF (scm_c_lookup ("map")));
2064 scm_c_extend_primitive_generic
2065 (SCM_VARIABLE_REF (scm_c_module_lookup (the_root_module, "for-each")),
2066 SCM_VARIABLE_REF (scm_c_lookup ("for-each")));
ee6aac97
MD
2067}
2068
2069/* End of srfi-1.c. */