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