(drop-right!, drop-while,
[bpt/guile.git] / srfi / srfi-1.c
1 /* srfi-1.c --- SRFI-1 procedures for Guile
2 *
3 * Copyright (C) 1995, 1996, 1997, 2000, 2001, 2002, 2003 Free Software
4 * Foundation, Inc.
5 *
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.
10 *
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.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
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
33 static long
34 srfi1_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;
42 if (!scm_is_pair (hare)) return -2;
43 hare = SCM_CDR(hare);
44 i++;
45 if (SCM_NULL_OR_NIL_P(hare)) return i;
46 if (!scm_is_pair (hare)) return -2;
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 }
52 while (! scm_is_eq (hare, tortoise));
53
54 /* If the tortoise ever catches the hare, then the list must contain
55 a cycle. */
56 return -1;
57 }
58
59 static SCM
60 equal_trampoline (SCM proc, SCM arg1, SCM arg2)
61 {
62 return scm_equal_p (arg1, arg2);
63 }
64
65
66 SCM_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
100 SCM_DEFINE (scm_srfi1_concatenate, "concatenate", 1, 0, 0,
101 (SCM lstlst),
102 "Construct a list by appending all lists in @var{lstlst}.\n"
103 "\n"
104 "@code{concatenate} is the same as @code{(apply append\n"
105 "@var{lstlst})}. It exists because some Scheme implementations\n"
106 "have a limit on the number of arguments a function takes, which\n"
107 "the @code{apply} might exceed. In Guile there is no such\n"
108 "limit.")
109 #define FUNC_NAME s_scm_srfi1_concatenate
110 {
111 SCM_VALIDATE_LIST (SCM_ARG1, lstlst);
112 return scm_append (lstlst);
113 }
114 #undef FUNC_NAME
115
116
117 SCM_DEFINE (scm_srfi1_concatenate_x, "concatenate!", 1, 0, 0,
118 (SCM lstlst),
119 "Construct a list by appending all lists in @var{lstlst}. Those\n"
120 "lists may be modified to produce the result.\n"
121 "\n"
122 "@code{concatenate!} is the same as @code{(apply append!\n"
123 "@var{lstlst})}. It exists because some Scheme implementations\n"
124 "have a limit on the number of arguments a function takes, which\n"
125 "the @code{apply} might exceed. In Guile there is no such\n"
126 "limit.")
127 #define FUNC_NAME s_scm_srfi1_concatenate
128 {
129 SCM_VALIDATE_LIST (SCM_ARG1, lstlst);
130 return scm_append_x (lstlst);
131 }
132 #undef FUNC_NAME
133
134
135 SCM_DEFINE (scm_srfi1_count, "count", 2, 0, 1,
136 (SCM pred, SCM list1, SCM rest),
137 "Return a count of the number of times @var{pred} returns true\n"
138 "when called on elements from the given lists.\n"
139 "\n"
140 "@var{pred} is called with @var{N} parameters @code{(@var{pred}\n"
141 "@var{elem1} @dots{} @var{elemN})}, each element being from the\n"
142 "corresponding @var{list1} @dots{} @var{lstN}. The first call is\n"
143 "with the first element of each list, the second with the second\n"
144 "element from each, and so on.\n"
145 "\n"
146 "Counting stops when the end of the shortest list is reached.\n"
147 "At least one list must be non-circular.")
148 #define FUNC_NAME s_scm_srfi1_count
149 {
150 long count;
151 SCM lst;
152 int argnum;
153 SCM_VALIDATE_REST_ARGUMENT (rest);
154
155 count = 0;
156
157 if (scm_is_null (rest))
158 {
159 /* one list */
160 scm_t_trampoline_1 pred_tramp;
161 pred_tramp = scm_trampoline_1 (pred);
162 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
163
164 for ( ; scm_is_pair (list1); list1 = SCM_CDR (list1))
165 count += scm_is_true (pred_tramp (pred, SCM_CAR (list1)));
166
167 /* check below that list1 is a proper list, and done */
168 end_list1:
169 lst = list1;
170 argnum = 2;
171 }
172 else if (scm_is_pair (rest) && scm_is_null (SCM_CDR (rest)))
173 {
174 /* two lists */
175 scm_t_trampoline_2 pred_tramp;
176 SCM list2;
177
178 pred_tramp = scm_trampoline_2 (pred);
179 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
180
181 list2 = SCM_CAR (rest);
182 for (;;)
183 {
184 if (! scm_is_pair (list1))
185 goto end_list1;
186 if (! scm_is_pair (list2))
187 {
188 lst = list2;
189 argnum = 3;
190 break;
191 }
192 count += scm_is_true (pred_tramp
193 (pred, SCM_CAR (list1), SCM_CAR (list2)));
194 list1 = SCM_CDR (list1);
195 list2 = SCM_CDR (list2);
196 }
197 }
198 else
199 {
200 /* three or more lists */
201 SCM vec, args, a;
202 size_t len, i;
203
204 /* vec is the list arguments */
205 vec = scm_vector (scm_cons (list1, rest));
206 len = SCM_SIMPLE_VECTOR_LENGTH (vec);
207
208 /* args is the argument list to pass to pred, same length as vec,
209 re-used for each call */
210 args = scm_make_list (SCM_I_MAKINUM (len), SCM_UNDEFINED);
211
212 for (;;)
213 {
214 /* first elem of each list in vec into args, and step those
215 vec entries onto their next element */
216 for (i = 0, a = args, argnum = 2;
217 i < len;
218 i++, a = SCM_CDR (a), argnum++)
219 {
220 lst = SCM_SIMPLE_VECTOR_REF (vec, i); /* list argument */
221 if (! scm_is_pair (lst))
222 goto check_lst_and_done;
223 SCM_SETCAR (a, SCM_CAR (lst)); /* arg for pred */
224 SCM_SIMPLE_VECTOR_SET (vec, i, SCM_CDR (lst)); /* rest of lst */
225 }
226
227 count += scm_is_true (scm_apply (pred, args, SCM_EOL));
228 }
229 }
230
231 check_lst_and_done:
232 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, argnum, FUNC_NAME, "list");
233 return scm_from_long (count);
234 }
235 #undef FUNC_NAME
236
237
238 SCM_DEFINE (scm_srfi1_delete, "delete", 2, 1, 0,
239 (SCM x, SCM lst, SCM pred),
240 "Return a list containing the elements of @var{lst} but with\n"
241 "those equal to @var{x} deleted. The returned elements will be\n"
242 "in the same order as they were in @var{lst}.\n"
243 "\n"
244 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
245 "given. An equality call is made just once for each element,\n"
246 "but the order in which the calls are made on the elements is\n"
247 "unspecified.\n"
248 "\n"
249 "The equality calls are always @code{(pred x elem)}, ie.@: the\n"
250 "given @var{x} is first. This means for instance elements\n"
251 "greater than 5 can be deleted with @code{(delete 5 lst <)}.\n"
252 "\n"
253 "@var{lst} is not modified, but the returned list might share a\n"
254 "common tail with @var{lst}.")
255 #define FUNC_NAME s_scm_srfi1_delete
256 {
257 scm_t_trampoline_2 equal_p;
258 SCM ret, *p, keeplst;
259
260 if (SCM_UNBNDP (pred))
261 return scm_delete (x, lst);
262
263 equal_p = scm_trampoline_2 (pred);
264 SCM_ASSERT (equal_p, pred, SCM_ARG3, FUNC_NAME);
265
266 /* ret is the return list being constructed. p is where to append to it,
267 initially &ret then SCM_CDRLOC of the last pair. lst progresses as
268 elements are considered.
269
270 Elements to be retained are not immediately copied, instead keeplst is
271 the last pair in lst which is to be retained but not yet copied. When
272 there's no more deletions, *p can be set to keeplst to share the
273 remainder of the original lst. (The entire original lst if there's no
274 deletions at all.) */
275
276 keeplst = lst;
277 ret = SCM_EOL;
278 p = &ret;
279
280 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
281 {
282 if (scm_is_true (equal_p (pred, x, SCM_CAR (lst))))
283 {
284 /* delete this element, so copy from keeplst (inclusive) to lst
285 (exclusive) onto ret */
286 while (! scm_is_eq (keeplst, lst))
287 {
288 SCM c = scm_cons (SCM_CAR (keeplst), SCM_EOL);
289 *p = c;
290 p = SCM_CDRLOC (c);
291 keeplst = SCM_CDR (keeplst);
292 }
293
294 keeplst = SCM_CDR (lst);
295 }
296 }
297
298 /* final retained elements */
299 *p = keeplst;
300
301 /* demand that lst was a proper list */
302 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
303
304 return ret;
305 }
306 #undef FUNC_NAME
307
308
309 SCM_DEFINE (scm_srfi1_delete_x, "delete!", 2, 1, 0,
310 (SCM x, SCM lst, SCM pred),
311 "Return a list containing the elements of @var{lst} but with\n"
312 "those equal to @var{x} deleted. The returned elements will be\n"
313 "in the same order as they were in @var{lst}.\n"
314 "\n"
315 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
316 "given. An equality call is made just once for each element,\n"
317 "but the order in which the calls are made on the elements is\n"
318 "unspecified.\n"
319 "\n"
320 "The equality calls are always @code{(pred x elem)}, ie.@: the\n"
321 "given @var{x} is first. This means for instance elements\n"
322 "greater than 5 can be deleted with @code{(delete 5 lst <)}.\n"
323 "\n"
324 "@var{lst} may be modified to construct the returned list.")
325 #define FUNC_NAME s_scm_srfi1_delete_x
326 {
327 scm_t_trampoline_2 equal_p;
328 SCM walk;
329 SCM *prev;
330
331 if (SCM_UNBNDP (pred))
332 return scm_delete_x (x, lst);
333
334 equal_p = scm_trampoline_2 (pred);
335 SCM_ASSERT (equal_p, pred, SCM_ARG3, FUNC_NAME);
336
337 for (prev = &lst, walk = lst;
338 scm_is_pair (walk);
339 walk = SCM_CDR (walk))
340 {
341 if (scm_is_true (equal_p (pred, x, SCM_CAR (walk))))
342 *prev = SCM_CDR (walk);
343 else
344 prev = SCM_CDRLOC (walk);
345 }
346
347 /* demand the input was a proper list */
348 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (walk), walk, SCM_ARG2, FUNC_NAME,"list");
349 return lst;
350 }
351 #undef FUNC_NAME
352
353
354 SCM_DEFINE (scm_srfi1_delete_duplicates, "delete-duplicates", 1, 1, 0,
355 (SCM lst, SCM pred),
356 "Return a list containing the elements of @var{lst} but without\n"
357 "duplicates.\n"
358 "\n"
359 "When elements are equal, only the first in @var{lst} is\n"
360 "retained. Equal elements can be anywhere in @var{lst}, they\n"
361 "don't have to be adjacent. The returned list will have the\n"
362 "retained elements in the same order as they were in @var{lst}.\n"
363 "\n"
364 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
365 "given. Calls @code{(pred x y)} are made with element @var{x}\n"
366 "being before @var{y} in @var{lst}. A call is made at most once\n"
367 "for each combination, but the sequence of the calls across the\n"
368 "elements is unspecified.\n"
369 "\n"
370 "@var{lst} is not modified, but the return might share a common\n"
371 "tail with @var{lst}.\n"
372 "\n"
373 "In the worst case, this is an @math{O(N^2)} algorithm because\n"
374 "it must check each element against all those preceding it. For\n"
375 "long lists it is more efficient to sort and then compare only\n"
376 "adjacent elements.")
377 #define FUNC_NAME s_scm_srfi1_delete_duplicates
378 {
379 scm_t_trampoline_2 equal_p;
380 SCM ret, *p, keeplst, item, l;
381
382 /* ret is the new list constructed. p is where to append, initially &ret
383 then SCM_CDRLOC of the last pair. lst is advanced as each element is
384 considered.
385
386 Elements retained are not immediately appended to ret, instead keeplst
387 is the last pair in lst which is to be kept but is not yet copied.
388 Initially this is the first pair of lst, since the first element is
389 always retained.
390
391 *p is kept set to keeplst, so ret (inclusive) to lst (exclusive) is all
392 the elements retained, making the equality search loop easy.
393
394 If an item must be deleted, elements from keeplst (inclusive) to lst
395 (exclusive) must be copied and appended to ret. When there's no more
396 deletions, *p is left set to keeplst, so ret shares structure with the
397 original lst. (ret will be the entire original lst if there are no
398 deletions.) */
399
400 /* skip to end if an empty list (or something invalid) */
401 ret = lst;
402 if (scm_is_pair (lst))
403 {
404 if (SCM_UNBNDP (pred))
405 equal_p = equal_trampoline;
406 else
407 {
408 equal_p = scm_trampoline_2 (pred);
409 SCM_ASSERT (equal_p, pred, SCM_ARG2, FUNC_NAME);
410 }
411
412 keeplst = lst;
413 p = &ret;
414
415 /* loop over lst elements starting from second */
416 for (;;)
417 {
418 lst = SCM_CDR (lst);
419 if (! scm_is_pair (lst))
420 break;
421 item = SCM_CAR (lst);
422
423 /* loop searching ret upto lst */
424 for (l = ret; ! scm_is_eq (l, lst); l = SCM_CDR (l))
425 {
426 if (scm_is_true (equal_p (pred, SCM_CAR (l), item)))
427 {
428 /* duplicate, don't want this element, so copy keeplst
429 (inclusive) to lst (exclusive) onto ret */
430 while (! scm_is_eq (keeplst, lst))
431 {
432 SCM c = scm_cons (SCM_CAR (keeplst), SCM_EOL);
433 *p = c;
434 p = SCM_CDRLOC (c);
435 keeplst = SCM_CDR (keeplst);
436 }
437
438 keeplst = SCM_CDR (lst); /* elem after the one deleted */
439 *p = keeplst;
440 break;
441 }
442 }
443 }
444 }
445
446 /* demand that lst was a proper list */
447 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG1, FUNC_NAME, "list");
448
449 return ret;
450 }
451 #undef FUNC_NAME
452
453
454 SCM_DEFINE (scm_srfi1_delete_duplicates_x, "delete-duplicates!", 1, 1, 0,
455 (SCM lst, SCM pred),
456 "Return a list containing the elements of @var{lst} but without\n"
457 "duplicates.\n"
458 "\n"
459 "When elements are equal, only the first in @var{lst} is\n"
460 "retained. Equal elements can be anywhere in @var{lst}, they\n"
461 "don't have to be adjacent. The returned list will have the\n"
462 "retained elements in the same order as they were in @var{lst}.\n"
463 "\n"
464 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
465 "given. Calls @code{(pred x y)} are made with element @var{x}\n"
466 "being before @var{y} in @var{lst}. A call is made at most once\n"
467 "for each combination, but the sequence of the calls across the\n"
468 "elements is unspecified.\n"
469 "\n"
470 "@var{lst} may be modified to construct the returned list.\n"
471 "\n"
472 "In the worst case, this is an @math{O(N^2)} algorithm because\n"
473 "it must check each element against all those preceding it. For\n"
474 "long lists it is more efficient to sort and then compare only\n"
475 "adjacent elements.")
476 #define FUNC_NAME s_scm_srfi1_delete_duplicates_x
477 {
478 scm_t_trampoline_2 equal_p;
479 SCM ret, endret, item, l;
480
481 /* ret is the return list, constructed from the pairs in lst. endret is
482 the last pair of ret, initially the first pair. lst is advanced as
483 elements are considered. */
484
485 /* skip to end if an empty list (or something invalid) */
486 ret = lst;
487 if (scm_is_pair (lst))
488 {
489 if (SCM_UNBNDP (pred))
490 equal_p = equal_trampoline;
491 else
492 {
493 equal_p = scm_trampoline_2 (pred);
494 SCM_ASSERT (equal_p, pred, SCM_ARG2, FUNC_NAME);
495 }
496
497 endret = ret;
498
499 /* loop over lst elements starting from second */
500 for (;;)
501 {
502 lst = SCM_CDR (lst);
503 if (! scm_is_pair (lst))
504 break;
505 item = SCM_CAR (lst);
506
507 /* is item equal to any element from ret to endret (inclusive)? */
508 l = ret;
509 for (;;)
510 {
511 if (scm_is_true (equal_p (pred, SCM_CAR (l), item)))
512 break; /* equal, forget this element */
513
514 if (scm_is_eq (l, endret))
515 {
516 /* not equal to any, so append this pair */
517 SCM_SETCDR (endret, lst);
518 endret = lst;
519 break;
520 }
521 l = SCM_CDR (l);
522 }
523 }
524
525 /* terminate, in case last element was deleted */
526 SCM_SETCDR (endret, SCM_EOL);
527 }
528
529 /* demand that lst was a proper list */
530 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG1, FUNC_NAME, "list");
531
532 return ret;
533 }
534 #undef FUNC_NAME
535
536
537 SCM_DEFINE (scm_srfi1_drop_right, "drop-right", 2, 0, 0,
538 (SCM lst, SCM n),
539 "Return a new list containing all except the last @var{n}\n"
540 "elements of @var{lst}.")
541 #define FUNC_NAME s_scm_srfi1_drop_right
542 {
543 SCM tail = scm_list_tail (lst, n);
544 SCM ret = SCM_EOL;
545 SCM *rend = &ret;
546 while (scm_is_pair (tail))
547 {
548 *rend = scm_cons (SCM_CAR (lst), SCM_EOL);
549 rend = SCM_CDRLOC (*rend);
550
551 lst = SCM_CDR (lst);
552 tail = SCM_CDR (tail);
553 }
554 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P(tail), tail, SCM_ARG1, FUNC_NAME, "list");
555 return ret;
556 }
557 #undef FUNC_NAME
558
559
560 SCM_DEFINE (scm_srfi1_drop_right_x, "drop-right!", 2, 0, 0,
561 (SCM lst, SCM n),
562 "Return the a list containing the @var{n} last elements of\n"
563 "@var{lst}. @var{lst} may be modified to build the return.")
564 #define FUNC_NAME s_scm_srfi1_drop_right_x
565 {
566 SCM tail, *p;
567
568 if (scm_is_eq (n, SCM_INUM0))
569 return lst;
570
571 tail = scm_list_tail (lst, n);
572 p = &lst;
573
574 /* p and tail work along the list, p being the cdrloc of the cell n steps
575 behind tail */
576 for ( ; scm_is_pair (tail); tail = SCM_CDR (tail))
577 p = SCM_CDRLOC (*p);
578
579 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P(tail), tail, SCM_ARG1, FUNC_NAME, "list");
580
581 *p = SCM_EOL;
582 return lst;
583 }
584 #undef FUNC_NAME
585
586
587 SCM_DEFINE (scm_srfi1_drop_while, "drop-while", 2, 0, 0,
588 (SCM pred, SCM lst),
589 "Drop the longest initial prefix of @var{lst} whose elements all\n"
590 "satisfy the predicate @var{pred}.")
591 #define FUNC_NAME s_scm_srfi1_drop_while
592 {
593 scm_t_trampoline_1 pred_tramp = scm_trampoline_1 (pred);
594 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
595
596 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
597 if (scm_is_false (pred_tramp (pred, SCM_CAR (lst))))
598 goto done;
599
600 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
601 done:
602 return lst;
603 }
604 #undef FUNC_NAME
605
606
607 SCM_DEFINE (scm_srfi1_filter_map, "filter-map", 2, 0, 1,
608 (SCM proc, SCM list1, SCM rest),
609 "Apply @var{proc} to to the elements of @var{list1} @dots{} and\n"
610 "return a list of the results as per SRFI-1 @code{map}, except\n"
611 "that any @code{#f} results are omitted from the list returned.")
612 #define FUNC_NAME s_scm_srfi1_filter_map
613 {
614 SCM ret, *loc, elem, newcell, lst;
615 int argnum;
616
617 SCM_VALIDATE_REST_ARGUMENT (rest);
618
619 ret = SCM_EOL;
620 loc = &ret;
621
622 if (SCM_NULLP (rest))
623 {
624 /* one list */
625 scm_t_trampoline_1 proc_tramp = scm_trampoline_1 (proc);
626 SCM_ASSERT (proc_tramp, proc, SCM_ARG1, FUNC_NAME);
627
628 for ( ; scm_is_pair (list1); list1 = SCM_CDR (list1))
629 {
630 elem = proc_tramp (proc, SCM_CAR (list1));
631 if (scm_is_true (elem))
632 {
633 newcell = scm_cons (elem, SCM_EOL);
634 *loc = newcell;
635 loc = SCM_CDRLOC (newcell);
636 }
637 }
638
639 /* check below that list1 is a proper list, and done */
640 end_list1:
641 lst = list1;
642 argnum = 2;
643 }
644 else if (SCM_NULLP (SCM_CDR (rest)))
645 {
646 /* two lists */
647 scm_t_trampoline_2 proc_tramp = scm_trampoline_2 (proc);
648 SCM list2 = SCM_CAR (rest);
649 SCM_ASSERT (proc_tramp, proc, SCM_ARG1, FUNC_NAME);
650
651 for (;;)
652 {
653 if (! scm_is_pair (list1))
654 goto end_list1;
655 if (! scm_is_pair (list2))
656 {
657 lst = list2;
658 argnum = 3;
659 goto check_lst_and_done;
660 }
661 elem = proc_tramp (proc, SCM_CAR (list1), SCM_CAR (list2));
662 if (scm_is_true (elem))
663 {
664 newcell = scm_cons (elem, SCM_EOL);
665 *loc = newcell;
666 loc = SCM_CDRLOC (newcell);
667 }
668 list1 = SCM_CDR (list1);
669 list2 = SCM_CDR (list2);
670 }
671 }
672 else
673 {
674 /* three or more lists */
675 SCM vec, args, a;
676 size_t len, i;
677
678 /* vec is the list arguments */
679 vec = scm_vector (scm_cons (list1, rest));
680 len = SCM_SIMPLE_VECTOR_LENGTH (vec);
681
682 /* args is the argument list to pass to proc, same length as vec,
683 re-used for each call */
684 args = scm_make_list (SCM_I_MAKINUM (len), SCM_UNDEFINED);
685
686 for (;;)
687 {
688 /* first elem of each list in vec into args, and step those
689 vec entries onto their next element */
690 for (i = 0, a = args, argnum = 2;
691 i < len;
692 i++, a = SCM_CDR (a), argnum++)
693 {
694 lst = SCM_SIMPLE_VECTOR_REF (vec, i); /* list argument */
695 if (! scm_is_pair (lst))
696 goto check_lst_and_done;
697 SCM_SETCAR (a, SCM_CAR (lst)); /* arg for proc */
698 SCM_SIMPLE_VECTOR_SET (vec, i, SCM_CDR (lst)); /* rest of lst */
699 }
700
701 elem = scm_apply (proc, args, SCM_EOL);
702 if (scm_is_true (elem))
703 {
704 newcell = scm_cons (elem, SCM_EOL);
705 *loc = newcell;
706 loc = SCM_CDRLOC (newcell);
707 }
708 }
709 }
710
711 check_lst_and_done:
712 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, argnum, FUNC_NAME, "list");
713 return ret;
714 }
715 #undef FUNC_NAME
716
717
718 SCM_DEFINE (scm_srfi1_find, "find", 2, 0, 0,
719 (SCM pred, SCM lst),
720 "Return the first element of @var{lst} which satisfies the\n"
721 "predicate @var{pred}, or return @code{#f} if no such element is\n"
722 "found.")
723 #define FUNC_NAME s_scm_srfi1_find
724 {
725 scm_t_trampoline_1 pred_tramp = scm_trampoline_1 (pred);
726 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
727
728 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
729 {
730 SCM elem = SCM_CAR (lst);
731 if (scm_is_true (pred_tramp (pred, elem)))
732 return elem;
733 }
734 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
735
736 return SCM_BOOL_F;
737 }
738 #undef FUNC_NAME
739
740
741 SCM_DEFINE (scm_srfi1_find_tail, "find-tail", 2, 0, 0,
742 (SCM pred, SCM lst),
743 "Return the first pair of @var{lst} whose @sc{car} satisfies the\n"
744 "predicate @var{pred}, or return @code{#f} if no such element is\n"
745 "found.")
746 #define FUNC_NAME s_scm_srfi1_find_tail
747 {
748 scm_t_trampoline_1 pred_tramp = scm_trampoline_1 (pred);
749 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
750
751 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
752 if (scm_is_true (pred_tramp (pred, SCM_CAR (lst))))
753 return lst;
754 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
755
756 return SCM_BOOL_F;
757 }
758 #undef FUNC_NAME
759
760
761 SCM_DEFINE (scm_srfi1_length_plus, "length+", 1, 0, 0,
762 (SCM lst),
763 "Return the length of @var{lst}, or @code{#f} if @var{lst} is\n"
764 "circular.")
765 #define FUNC_NAME s_scm_srfi1_length_plus
766 {
767 long len = scm_ilength (lst);
768 return (len >= 0 ? SCM_I_MAKINUM (len) : SCM_BOOL_F);
769 }
770 #undef FUNC_NAME
771
772
773 /* This routine differs from the core list-copy in allowing improper lists.
774 Maybe the core could allow them similarly. */
775
776 SCM_DEFINE (scm_srfi1_list_copy, "list-copy", 1, 0, 0,
777 (SCM lst),
778 "Return a copy of the given list @var{lst}.\n"
779 "\n"
780 "@var{lst} can be a proper or improper list. And if @var{lst}\n"
781 "is not a pair then it's treated as the final tail of an\n"
782 "improper list and simply returned.")
783 #define FUNC_NAME s_scm_srfi1_list_copy
784 {
785 SCM newlst;
786 SCM * fill_here;
787 SCM from_here;
788
789 newlst = lst;
790 fill_here = &newlst;
791 from_here = lst;
792
793 while (scm_is_pair (from_here))
794 {
795 SCM c;
796 c = scm_cons (SCM_CAR (from_here), SCM_CDR (from_here));
797 *fill_here = c;
798 fill_here = SCM_CDRLOC (c);
799 from_here = SCM_CDR (from_here);
800 }
801 return newlst;
802 }
803 #undef FUNC_NAME
804
805
806 SCM_DEFINE (scm_srfi1_lset_adjoin, "lset-adjoin", 2, 0, 1,
807 (SCM equal, SCM lst, SCM rest),
808 "Add to @var{list} any of the given @var{elem}s not already in\n"
809 "the list. @var{elem}s are @code{cons}ed onto the start of\n"
810 "@var{list} (so the return shares a common tail with\n"
811 "@var{list}), but the order they're added is unspecified.\n"
812 "\n"
813 "The given @var{=} procedure is used for comparing elements,\n"
814 "called as @code{(@var{=} listelem elem)}, ie.@: the second\n"
815 "argument is one of the given @var{elem} parameters.\n"
816 "\n"
817 "@example\n"
818 "(lset-adjoin eqv? '(1 2 3) 4 1 5) @result{} (5 4 1 2 3)\n"
819 "@end example")
820 #define FUNC_NAME s_scm_srfi1_lset_adjoin
821 {
822 scm_t_trampoline_2 equal_tramp;
823 SCM l, elem;
824
825 equal_tramp = scm_trampoline_2 (equal);
826 SCM_ASSERT (equal_tramp, equal, SCM_ARG1, FUNC_NAME);
827 SCM_VALIDATE_REST_ARGUMENT (rest);
828
829 /* It's not clear if duplicates among the `rest' elements are meant to be
830 cast out. The spec says `=' is called as (= list-elem rest-elem),
831 suggesting perhaps not, but the reference implementation shows the
832 "list" at each stage as including those "rest" elements already added.
833 The latter corresponds to what's described for lset-union, so that's
834 what's done here. */
835
836 for ( ; scm_is_pair (rest); rest = SCM_CDR (rest))
837 {
838 elem = SCM_CAR (rest);
839
840 for (l = lst; scm_is_pair (l); l = SCM_CDR (l))
841 if (scm_is_true (equal_tramp (equal, SCM_CAR (l), elem)))
842 goto next_elem; /* elem already in lst, don't add */
843
844 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P(l), lst, SCM_ARG2, FUNC_NAME, "list");
845
846 /* elem is not equal to anything already in lst, add it */
847 lst = scm_cons (elem, lst);
848
849 next_elem:
850 ;
851 }
852
853 return lst;
854 }
855 #undef FUNC_NAME
856
857
858 /* Typechecking for multi-argument MAP and FOR-EACH.
859
860 Verify that each element of the vector ARGV, except for the first,
861 is a list and return minimum length. Attribute errors to WHO,
862 and claim that the i'th element of ARGV is WHO's i+2'th argument. */
863 static inline int
864 check_map_args (SCM argv,
865 long len,
866 SCM gf,
867 SCM proc,
868 SCM args,
869 const char *who)
870 {
871 long i;
872
873 for (i = SCM_SIMPLE_VECTOR_LENGTH (argv) - 1; i >= 1; i--)
874 {
875 SCM elt = SCM_SIMPLE_VECTOR_REF (argv, i);
876 long elt_len;
877
878 if (!(scm_is_null (elt) || scm_is_pair (elt)))
879 {
880 check_map_error:
881 if (gf)
882 scm_apply_generic (gf, scm_cons (proc, args));
883 else
884 scm_wrong_type_arg (who, i + 2, elt);
885 }
886
887 elt_len = srfi1_ilength (elt);
888 if (elt_len < -1)
889 goto check_map_error;
890
891 if (len < 0 || (elt_len >= 0 && elt_len < len))
892 len = elt_len;
893 }
894 if (len < 0)
895 /* i == 0 */
896 goto check_map_error;
897
898 scm_remember_upto_here_1 (argv);
899 return len;
900 }
901
902
903 SCM_GPROC (s_srfi1_map, "map", 2, 0, 1, scm_srfi1_map, g_srfi1_map);
904
905 /* Note: Currently, scm_srfi1_map applies PROC to the argument list(s)
906 sequentially, starting with the first element(s). This is used in
907 the Scheme procedure `map-in-order', which guarantees sequential
908 behaviour, is implemented using scm_map. If the behaviour changes,
909 we need to update `map-in-order'.
910 */
911
912 SCM
913 scm_srfi1_map (SCM proc, SCM arg1, SCM args)
914 #define FUNC_NAME s_srfi1_map
915 {
916 long i, len;
917 SCM res = SCM_EOL;
918 SCM *pres = &res;
919
920 len = srfi1_ilength (arg1);
921 SCM_GASSERTn ((scm_is_null (arg1) || scm_is_pair (arg1)) && len >= -1,
922 g_srfi1_map,
923 scm_cons2 (proc, arg1, args), SCM_ARG2, s_srfi1_map);
924 SCM_VALIDATE_REST_ARGUMENT (args);
925 if (scm_is_null (args))
926 {
927 scm_t_trampoline_1 call = scm_trampoline_1 (proc);
928 SCM_GASSERT2 (call, g_srfi1_map, proc, arg1, SCM_ARG1, s_srfi1_map);
929 SCM_GASSERT2 (len >= 0, g_srfi1_map, proc, arg1, SCM_ARG2, s_srfi1_map);
930 while (SCM_NIMP (arg1))
931 {
932 *pres = scm_list_1 (call (proc, SCM_CAR (arg1)));
933 pres = SCM_CDRLOC (*pres);
934 arg1 = SCM_CDR (arg1);
935 }
936 return res;
937 }
938 if (scm_is_null (SCM_CDR (args)))
939 {
940 SCM arg2 = SCM_CAR (args);
941 int len2 = srfi1_ilength (arg2);
942 scm_t_trampoline_2 call = scm_trampoline_2 (proc);
943 SCM_GASSERTn (call, g_srfi1_map,
944 scm_cons2 (proc, arg1, args), SCM_ARG1, s_srfi1_map);
945 if (len < 0 || (len2 >= 0 && len2 < len))
946 len = len2;
947 SCM_GASSERTn ((scm_is_null (arg2) || scm_is_pair (arg2))
948 && len >= 0 && len2 >= -1,
949 g_srfi1_map,
950 scm_cons2 (proc, arg1, args),
951 len2 >= 0 ? SCM_ARG2 : SCM_ARG3,
952 s_srfi1_map);
953 while (len > 0)
954 {
955 *pres = scm_list_1 (call (proc, SCM_CAR (arg1), SCM_CAR (arg2)));
956 pres = SCM_CDRLOC (*pres);
957 arg1 = SCM_CDR (arg1);
958 arg2 = SCM_CDR (arg2);
959 --len;
960 }
961 return res;
962 }
963 args = scm_vector (arg1 = scm_cons (arg1, args));
964 len = check_map_args (args, len, g_srfi1_map, proc, arg1, s_srfi1_map);
965 while (len > 0)
966 {
967 arg1 = SCM_EOL;
968 for (i = SCM_SIMPLE_VECTOR_LENGTH (args) - 1; i >= 0; i--)
969 {
970 SCM elt = SCM_SIMPLE_VECTOR_REF (args, i);
971 arg1 = scm_cons (SCM_CAR (elt), arg1);
972 SCM_SIMPLE_VECTOR_SET (args, i, SCM_CDR (elt));
973 }
974 *pres = scm_list_1 (scm_apply (proc, arg1, SCM_EOL));
975 pres = SCM_CDRLOC (*pres);
976 --len;
977 }
978 return res;
979 }
980 #undef FUNC_NAME
981
982 SCM_REGISTER_PROC (s_srfi1_map_in_order, "map-in-order", 2, 0, 1, scm_srfi1_map);
983
984 SCM_GPROC (s_srfi1_for_each, "for-each", 2, 0, 1, scm_srfi1_for_each, g_srfi1_for_each);
985
986 SCM
987 scm_srfi1_for_each (SCM proc, SCM arg1, SCM args)
988 #define FUNC_NAME s_srfi1_for_each
989 {
990 long i, len;
991 len = srfi1_ilength (arg1);
992 SCM_GASSERTn ((scm_is_null (arg1) || scm_is_pair (arg1)) && len >= -1,
993 g_srfi1_for_each, scm_cons2 (proc, arg1, args),
994 SCM_ARG2, s_srfi1_for_each);
995 SCM_VALIDATE_REST_ARGUMENT (args);
996 if (scm_is_null (args))
997 {
998 scm_t_trampoline_1 call = scm_trampoline_1 (proc);
999 SCM_GASSERT2 (call, g_srfi1_for_each, proc, arg1,
1000 SCM_ARG1, s_srfi1_for_each);
1001 SCM_GASSERT2 (len >= 0, g_srfi1_for_each, proc, arg1,
1002 SCM_ARG2, s_srfi1_map);
1003 while (SCM_NIMP (arg1))
1004 {
1005 call (proc, SCM_CAR (arg1));
1006 arg1 = SCM_CDR (arg1);
1007 }
1008 return SCM_UNSPECIFIED;
1009 }
1010 if (scm_is_null (SCM_CDR (args)))
1011 {
1012 SCM arg2 = SCM_CAR (args);
1013 int len2 = srfi1_ilength (arg2);
1014 scm_t_trampoline_2 call = scm_trampoline_2 (proc);
1015 SCM_GASSERTn (call, g_srfi1_for_each,
1016 scm_cons2 (proc, arg1, args), SCM_ARG1, s_srfi1_for_each);
1017 if (len < 0 || (len2 >= 0 && len2 < len))
1018 len = len2;
1019 SCM_GASSERTn ((scm_is_null (arg2) || scm_is_pair (arg2))
1020 && len >= 0 && len2 >= -1,
1021 g_srfi1_for_each,
1022 scm_cons2 (proc, arg1, args),
1023 len2 >= 0 ? SCM_ARG2 : SCM_ARG3,
1024 s_srfi1_for_each);
1025 while (len > 0)
1026 {
1027 call (proc, SCM_CAR (arg1), SCM_CAR (arg2));
1028 arg1 = SCM_CDR (arg1);
1029 arg2 = SCM_CDR (arg2);
1030 --len;
1031 }
1032 return SCM_UNSPECIFIED;
1033 }
1034 args = scm_vector (arg1 = scm_cons (arg1, args));
1035 len = check_map_args (args, len, g_srfi1_for_each, proc, arg1,
1036 s_srfi1_for_each);
1037 while (len > 0)
1038 {
1039 arg1 = SCM_EOL;
1040 for (i = SCM_SIMPLE_VECTOR_LENGTH (args) - 1; i >= 0; i--)
1041 {
1042 SCM elt = SCM_SIMPLE_VECTOR_REF (args, i);
1043 arg1 = scm_cons (SCM_CAR (elt), arg1);
1044 SCM_SIMPLE_VECTOR_SET (args, i, SCM_CDR (elt));
1045 }
1046 scm_apply (proc, arg1, SCM_EOL);
1047 --len;
1048 }
1049 return SCM_UNSPECIFIED;
1050 }
1051 #undef FUNC_NAME
1052
1053
1054 SCM_DEFINE (scm_srfi1_member, "member", 2, 1, 0,
1055 (SCM x, SCM lst, SCM pred),
1056 "Return the first sublist of @var{lst} whose @sc{car} is equal\n"
1057 "to @var{x}. If @var{x} does not appear in @var{lst}, return\n"
1058 "@code{#f}.\n"
1059 "\n"
1060 "Equality is determined by @code{equal?}, or by the equality\n"
1061 "predicate @var{=} if given. @var{=} is called @code{(= @var{x}\n"
1062 "elem)}, ie.@: with the given @var{x} first, so for example to\n"
1063 "find the first element greater than 5,\n"
1064 "\n"
1065 "@example\n"
1066 "(member 5 '(3 5 1 7 2 9) <) @result{} (7 2 9)\n"
1067 "@end example\n"
1068 "\n"
1069 "This version of @code{member} extends the core @code{member} by\n"
1070 "accepting an equality predicate.")
1071 #define FUNC_NAME s_scm_srfi1_member
1072 {
1073 scm_t_trampoline_2 equal_p;
1074 SCM_VALIDATE_LIST (2, lst);
1075 if (SCM_UNBNDP (pred))
1076 equal_p = equal_trampoline;
1077 else
1078 {
1079 equal_p = scm_trampoline_2 (pred);
1080 SCM_ASSERT (equal_p, pred, 3, FUNC_NAME);
1081 }
1082 for (; !SCM_NULL_OR_NIL_P (lst); lst = SCM_CDR (lst))
1083 {
1084 if (scm_is_true (equal_p (pred, x, SCM_CAR (lst))))
1085 return lst;
1086 }
1087 return SCM_BOOL_F;
1088 }
1089 #undef FUNC_NAME
1090
1091 SCM_DEFINE (scm_srfi1_assoc, "assoc", 2, 1, 0,
1092 (SCM key, SCM alist, SCM pred),
1093 "Behaves like @code{assq} but uses third argument @var{pred?}\n"
1094 "for key comparison. If @var{pred?} is not supplied,\n"
1095 "@code{equal?} is used. (Extended from R5RS.)\n")
1096 #define FUNC_NAME s_scm_srfi1_assoc
1097 {
1098 SCM ls = alist;
1099 scm_t_trampoline_2 equal_p;
1100 if (SCM_UNBNDP (pred))
1101 equal_p = equal_trampoline;
1102 else
1103 {
1104 equal_p = scm_trampoline_2 (pred);
1105 SCM_ASSERT (equal_p, pred, 3, FUNC_NAME);
1106 }
1107 for(; scm_is_pair (ls); ls = SCM_CDR (ls))
1108 {
1109 SCM tmp = SCM_CAR (ls);
1110 SCM_ASSERT_TYPE (scm_is_pair (tmp), alist, SCM_ARG2, FUNC_NAME,
1111 "association list");
1112 if (scm_is_true (equal_p (pred, SCM_CAR (tmp), key)))
1113 return tmp;
1114 }
1115 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (ls), alist, SCM_ARG2, FUNC_NAME,
1116 "association list");
1117 return SCM_BOOL_F;
1118 }
1119 #undef FUNC_NAME
1120
1121 SCM_DEFINE (scm_srfi1_partition, "partition", 2, 0, 0,
1122 (SCM pred, SCM list),
1123 "Partition the elements of @var{list} with predicate @var{pred}.\n"
1124 "Return two values: the list of elements satifying @var{pred} and\n"
1125 "the list of elements @emph{not} satisfying @var{pred}. The order\n"
1126 "of the output lists follows the order of @var{list}. @var{list}\n"
1127 "is not mutated. One of the output lists may share memory with @var{list}.\n")
1128 #define FUNC_NAME s_scm_srfi1_partition
1129 {
1130 /* In this implementation, the output lists don't share memory with
1131 list, because it's probably not worth the effort. */
1132 scm_t_trampoline_1 call = scm_trampoline_1(pred);
1133 SCM kept = scm_cons(SCM_EOL, SCM_EOL);
1134 SCM kept_tail = kept;
1135 SCM dropped = scm_cons(SCM_EOL, SCM_EOL);
1136 SCM dropped_tail = dropped;
1137
1138 SCM_ASSERT(call, pred, 2, FUNC_NAME);
1139
1140 for (; !SCM_NULL_OR_NIL_P (list); list = SCM_CDR(list)) {
1141 SCM elt = SCM_CAR(list);
1142 SCM new_tail = scm_cons(SCM_CAR(list), SCM_EOL);
1143 if (scm_is_true (call (pred, elt))) {
1144 SCM_SETCDR(kept_tail, new_tail);
1145 kept_tail = new_tail;
1146 }
1147 else {
1148 SCM_SETCDR(dropped_tail, new_tail);
1149 dropped_tail = new_tail;
1150 }
1151 }
1152 /* re-use the initial conses for the values list */
1153 SCM_SETCAR(kept, SCM_CDR(kept));
1154 SCM_SETCDR(kept, dropped);
1155 SCM_SETCAR(dropped, SCM_CDR(dropped));
1156 SCM_SETCDR(dropped, SCM_EOL);
1157 return scm_values(kept);
1158 }
1159 #undef FUNC_NAME
1160
1161
1162 SCM_DEFINE (scm_srfi1_partition_x, "partition!", 2, 0, 0,
1163 (SCM pred, SCM lst),
1164 "Split @var{lst} into those elements which do and don't satisfy\n"
1165 "the predicate @var{pred}.\n"
1166 "\n"
1167 "The return is two values (@pxref{Multiple Values}), the first\n"
1168 "being a list of all elements from @var{lst} which satisfy\n"
1169 "@var{pred}, the second a list of those which do not.\n"
1170 "\n"
1171 "The elements in the result lists are in the same order as in\n"
1172 "@var{lst} but the order in which the calls @code{(@var{pred}\n"
1173 "elem)} are made on the list elements is unspecified.\n"
1174 "\n"
1175 "@var{lst} may be modified to construct the return lists.")
1176 #define FUNC_NAME s_scm_srfi1_partition_x
1177 {
1178 SCM tlst, flst, *tp, *fp;
1179 scm_t_trampoline_1 pred_tramp;
1180
1181 pred_tramp = scm_trampoline_1 (pred);
1182 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
1183
1184 /* tlst and flst are the lists of true and false elements. tp and fp are
1185 where to store to append to them, initially &tlst and &flst, then
1186 SCM_CDRLOC of the last pair in the respective lists. */
1187
1188 tlst = SCM_EOL;
1189 flst = SCM_EOL;
1190 tp = &tlst;
1191 fp = &flst;
1192
1193 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
1194 {
1195 if (scm_is_true (pred_tramp (pred, SCM_CAR (lst))))
1196 {
1197 *tp = lst;
1198 tp = SCM_CDRLOC (lst);
1199 }
1200 else
1201 {
1202 *fp = lst;
1203 fp = SCM_CDRLOC (lst);
1204 }
1205 }
1206
1207 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
1208
1209 /* terminate whichever didn't get the last element(s) */
1210 *tp = SCM_EOL;
1211 *fp = SCM_EOL;
1212
1213 return scm_values (scm_list_2 (tlst, flst));
1214 }
1215 #undef FUNC_NAME
1216
1217
1218 SCM_DEFINE (scm_srfi1_reduce, "reduce", 3, 0, 0,
1219 (SCM proc, SCM def, SCM lst),
1220 "@code{reduce} is a variant of @code{fold}, where the first call\n"
1221 "to @var{proc} is on two elements from @var{lst}, rather than\n"
1222 "one element and a given initial value.\n"
1223 "\n"
1224 "If @var{lst} is empty, @code{reduce} returns @var{def} (this is\n"
1225 "the only use for @var{def}). If @var{lst} has just one element\n"
1226 "then that's the return value. Otherwise @var{proc} is called\n"
1227 "on the elements of @var{lst}.\n"
1228 "\n"
1229 "Each @var{proc} call is @code{(@var{proc} @var{elem}\n"
1230 "@var{previous})}, where @var{elem} is from @var{lst} (the\n"
1231 "second and subsequent elements of @var{lst}), and\n"
1232 "@var{previous} is the return from the previous call to\n"
1233 "@var{proc}. The first element of @var{lst} is the\n"
1234 "@var{previous} for the first call to @var{proc}.\n"
1235 "\n"
1236 "For example, the following adds a list of numbers, the calls\n"
1237 "made to @code{+} are shown. (Of course @code{+} accepts\n"
1238 "multiple arguments and can add a list directly, with\n"
1239 "@code{apply}.)\n"
1240 "\n"
1241 "@example\n"
1242 "(reduce + 0 '(5 6 7)) @result{} 18\n"
1243 "\n"
1244 "(+ 6 5) @result{} 11\n"
1245 "(+ 7 11) @result{} 18\n"
1246 "@end example\n"
1247 "\n"
1248 "@code{reduce} can be used instead of @code{fold} where the\n"
1249 "@var{init} value is an ``identity'', meaning a value which\n"
1250 "under @var{proc} doesn't change the result, in this case 0 is\n"
1251 "an identity since @code{(+ 5 0)} is just 5. @code{reduce}\n"
1252 "avoids that unnecessary call.")
1253 #define FUNC_NAME s_scm_srfi1_reduce
1254 {
1255 scm_t_trampoline_2 proc_tramp = scm_trampoline_2 (proc);
1256 SCM ret;
1257
1258 SCM_ASSERT (proc_tramp, proc, SCM_ARG1, FUNC_NAME);
1259
1260 ret = def; /* if lst is empty */
1261 if (scm_is_pair (lst))
1262 {
1263 ret = SCM_CAR (lst); /* if lst has one element */
1264
1265 for (lst = SCM_CDR (lst); scm_is_pair (lst); lst = SCM_CDR (lst))
1266 ret = proc_tramp (proc, SCM_CAR (lst), ret);
1267 }
1268
1269 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG3, FUNC_NAME, "list");
1270 return ret;
1271 }
1272 #undef FUNC_NAME
1273
1274
1275 SCM_DEFINE (scm_srfi1_reduce_right, "reduce-right", 3, 0, 0,
1276 (SCM proc, SCM def, SCM lst),
1277 "@code{reduce-right} is a variant of @code{fold-right}, where\n"
1278 "the first call to @var{proc} is on two elements from @var{lst},\n"
1279 "rather than one element and a given initial value.\n"
1280 "\n"
1281 "If @var{lst} is empty, @code{reduce-right} returns @var{def}\n"
1282 "(this is the only use for @var{def}). If @var{lst} has just\n"
1283 "one element then that's the return value. Otherwise @var{proc}\n"
1284 "is called on the elements of @var{lst}.\n"
1285 "\n"
1286 "Each @var{proc} call is @code{(@var{proc} @var{elem}\n"
1287 "@var{previous})}, where @var{elem} is from @var{lst} (the\n"
1288 "second last and then working back to the first element of\n"
1289 "@var{lst}), and @var{previous} is the return from the previous\n"
1290 "call to @var{proc}. The last element of @var{lst} is the\n"
1291 "@var{previous} for the first call to @var{proc}.\n"
1292 "\n"
1293 "For example, the following adds a list of numbers, the calls\n"
1294 "made to @code{+} are shown. (Of course @code{+} accepts\n"
1295 "multiple arguments and can add a list directly, with\n"
1296 "@code{apply}.)\n"
1297 "\n"
1298 "@example\n"
1299 "(reduce-right + 0 '(5 6 7)) @result{} 18\n"
1300 "\n"
1301 "(+ 6 7) @result{} 13\n"
1302 "(+ 5 13) @result{} 18\n"
1303 "@end example\n"
1304 "\n"
1305 "@code{reduce-right} can be used instead of @code{fold-right}\n"
1306 "where the @var{init} value is an ``identity'', meaning a value\n"
1307 "which under @var{proc} doesn't change the result, in this case\n"
1308 "0 is an identity since @code{(+ 7 0)} is just 5.\n"
1309 "@code{reduce-right} avoids that unnecessary call.\n"
1310 "\n"
1311 "@code{reduce} should be preferred over @code{reduce-right} if\n"
1312 "the order of processing doesn't matter, or can be arranged\n"
1313 "either way, since @code{reduce} is a little more efficient.")
1314 #define FUNC_NAME s_scm_srfi1_reduce_right
1315 {
1316 /* To work backwards across a list requires either repeatedly traversing
1317 to get each previous element, or using some memory for a reversed or
1318 random-access form. Repeated traversal might not be too terrible, but
1319 is of course quadratic complexity and hence to be avoided in case LST
1320 is long. A vector is preferred over a reversed list since it's more
1321 compact and is less work for the gc to collect. */
1322
1323 scm_t_trampoline_2 proc_tramp = scm_trampoline_2 (proc);
1324 SCM ret, vec;
1325 long len, i;
1326
1327 SCM_ASSERT (proc_tramp, proc, SCM_ARG1, FUNC_NAME);
1328
1329 if (SCM_NULL_OR_NIL_P (lst))
1330 return def;
1331
1332 vec = scm_vector (lst);
1333 len = SCM_SIMPLE_VECTOR_LENGTH (vec);
1334
1335 ret = SCM_SIMPLE_VECTOR_REF (vec, len-1);
1336 for (i = len-2; i >= 0; i--)
1337 ret = proc_tramp (proc, SCM_SIMPLE_VECTOR_REF (vec, i), ret);
1338
1339 return ret;
1340 }
1341 #undef FUNC_NAME
1342
1343
1344 SCM_DEFINE (scm_srfi1_remove, "remove", 2, 0, 0,
1345 (SCM pred, SCM list),
1346 "Return a list containing all elements from @var{lst} which do\n"
1347 "not satisfy the predicate @var{pred}. The elements in the\n"
1348 "result list have the same order as in @var{lst}. The order in\n"
1349 "which @var{pred} is applied to the list elements is not\n"
1350 "specified.")
1351 #define FUNC_NAME s_scm_srfi1_remove
1352 {
1353 scm_t_trampoline_1 call = scm_trampoline_1 (pred);
1354 SCM walk;
1355 SCM *prev;
1356 SCM res = SCM_EOL;
1357 SCM_ASSERT (call, pred, 1, FUNC_NAME);
1358 SCM_VALIDATE_LIST (2, list);
1359
1360 for (prev = &res, walk = list;
1361 scm_is_pair (walk);
1362 walk = SCM_CDR (walk))
1363 {
1364 if (scm_is_false (call (pred, SCM_CAR (walk))))
1365 {
1366 *prev = scm_cons (SCM_CAR (walk), SCM_EOL);
1367 prev = SCM_CDRLOC (*prev);
1368 }
1369 }
1370
1371 return res;
1372 }
1373 #undef FUNC_NAME
1374
1375
1376 SCM_DEFINE (scm_srfi1_remove_x, "remove!", 2, 0, 0,
1377 (SCM pred, SCM list),
1378 "Return a list containing all elements from @var{list} which do\n"
1379 "not satisfy the predicate @var{pred}. The elements in the\n"
1380 "result list have the same order as in @var{list}. The order in\n"
1381 "which @var{pred} is applied to the list elements is not\n"
1382 "specified. @var{list} may be modified to build the return\n"
1383 "list.")
1384 #define FUNC_NAME s_scm_srfi1_remove_x
1385 {
1386 scm_t_trampoline_1 call = scm_trampoline_1 (pred);
1387 SCM walk;
1388 SCM *prev;
1389 SCM_ASSERT (call, pred, 1, FUNC_NAME);
1390 SCM_VALIDATE_LIST (2, list);
1391
1392 for (prev = &list, walk = list;
1393 scm_is_pair (walk);
1394 walk = SCM_CDR (walk))
1395 {
1396 if (scm_is_false (call (pred, SCM_CAR (walk))))
1397 prev = SCM_CDRLOC (walk);
1398 else
1399 *prev = SCM_CDR (walk);
1400 }
1401
1402 return list;
1403 }
1404 #undef FUNC_NAME
1405
1406
1407 SCM_DEFINE (scm_srfi1_span, "span", 2, 0, 0,
1408 (SCM pred, SCM lst),
1409 "Return two values, the longest initial prefix of @var{lst}\n"
1410 "whose elements all satisfy the predicate @var{pred}, and the\n"
1411 "remainder of @var{lst}.")
1412 #define FUNC_NAME s_scm_srfi1_span
1413 {
1414 scm_t_trampoline_1 pred_tramp;
1415 SCM ret, *p;
1416
1417 pred_tramp = scm_trampoline_1 (pred);
1418 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
1419
1420 ret = SCM_EOL;
1421 p = &ret;
1422 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
1423 {
1424 SCM elem = SCM_CAR (lst);
1425 if (scm_is_false (pred_tramp (pred, elem)))
1426 goto done;
1427
1428 /* want this elem, tack it onto the end of ret */
1429 *p = scm_cons (elem, SCM_EOL);
1430 p = SCM_CDRLOC (*p);
1431 }
1432 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
1433
1434 done:
1435 return scm_values (scm_list_2 (ret, lst));
1436 }
1437 #undef FUNC_NAME
1438
1439
1440 SCM_DEFINE (scm_srfi1_span_x, "span!", 2, 0, 0,
1441 (SCM pred, SCM lst),
1442 "Return two values, the longest initial prefix of @var{lst}\n"
1443 "whose elements all satisfy the predicate @var{pred}, and the\n"
1444 "remainder of @var{lst}. @var{lst} may be modified to form the\n"
1445 "return.")
1446 #define FUNC_NAME s_scm_srfi1_span_x
1447 {
1448 SCM upto, *p;
1449 scm_t_trampoline_1 pred_tramp;
1450
1451 pred_tramp = scm_trampoline_1 (pred);
1452 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
1453
1454 p = &lst;
1455 for (upto = lst; scm_is_pair (upto); upto = SCM_CDR (upto))
1456 {
1457 if (scm_is_false (pred_tramp (pred, SCM_CAR (upto))))
1458 goto done;
1459
1460 /* want this element */
1461 p = SCM_CDRLOC (upto);
1462 }
1463 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (upto), lst, SCM_ARG2, FUNC_NAME, "list");
1464
1465 done:
1466 *p = SCM_EOL;
1467 return scm_values (scm_list_2 (lst, upto));
1468 }
1469 #undef FUNC_NAME
1470
1471
1472 SCM_DEFINE (scm_srfi1_split_at, "split-at", 2, 0, 0,
1473 (SCM lst, SCM n),
1474 "Return two values (multiple values), being a list of the\n"
1475 "elements before index @var{n} in @var{lst}, and a list of those\n"
1476 "after.")
1477 #define FUNC_NAME s_scm_srfi1_split_at
1478 {
1479 size_t nn;
1480 /* pre is a list of elements before the i split point, loc is the CDRLOC
1481 of the last cell, ie. where to store to append to it */
1482 SCM pre = SCM_EOL;
1483 SCM *loc = &pre;
1484
1485 for (nn = scm_to_size_t (n); nn != 0; nn--)
1486 {
1487 SCM_VALIDATE_CONS (SCM_ARG1, lst);
1488
1489 *loc = scm_cons (SCM_CAR (lst), SCM_EOL);
1490 loc = SCM_CDRLOC (*loc);
1491 lst = SCM_CDR(lst);
1492 }
1493 return scm_values (scm_list_2 (pre, lst));
1494 }
1495 #undef FUNC_NAME
1496
1497
1498 SCM_DEFINE (scm_srfi1_split_at_x, "split-at!", 2, 0, 0,
1499 (SCM lst, SCM n),
1500 "Return two values (multiple values), being a list of the\n"
1501 "elements before index @var{n} in @var{lst}, and a list of those\n"
1502 "after. @var{lst} is modified to form those values.")
1503 #define FUNC_NAME s_scm_srfi1_split_at
1504 {
1505 size_t nn;
1506 SCM upto = lst;
1507 SCM *loc = &lst;
1508
1509 for (nn = scm_to_size_t (n); nn != 0; nn--)
1510 {
1511 SCM_VALIDATE_CONS (SCM_ARG1, upto);
1512
1513 loc = SCM_CDRLOC (upto);
1514 upto = SCM_CDR (upto);
1515 }
1516
1517 *loc = SCM_EOL;
1518 return scm_values (scm_list_2 (lst, upto));
1519 }
1520 #undef FUNC_NAME
1521
1522
1523 SCM_DEFINE (scm_srfi1_take_x, "take!", 2, 0, 0,
1524 (SCM lst, SCM n),
1525 "Return a list containing the first @var{n} elements of\n"
1526 "@var{lst}.")
1527 #define FUNC_NAME s_scm_srfi1_take_x
1528 {
1529 long nn;
1530 SCM pos;
1531
1532 SCM_VALIDATE_INUM_MIN_COPY (SCM_ARG2, n, 0, nn);
1533
1534 if (nn == 0)
1535 return SCM_EOL;
1536
1537 pos = scm_list_tail (lst, SCM_I_MAKINUM (nn - 1));
1538
1539 /* Must have at least one cell left, mustn't have reached the end of an
1540 n-1 element list. SCM_VALIDATE_CONS here gives the same error as
1541 scm_list_tail does on say an n-2 element list, though perhaps a range
1542 error would make more sense (for both). */
1543 SCM_VALIDATE_CONS (SCM_ARG1, pos);
1544
1545 SCM_SETCDR (pos, SCM_EOL);
1546 return lst;
1547 }
1548 #undef FUNC_NAME
1549
1550
1551 SCM_DEFINE (scm_srfi1_take_right, "take-right", 2, 0, 0,
1552 (SCM lst, SCM n),
1553 "Return the a list containing the @var{n} last elements of\n"
1554 "@var{lst}.")
1555 #define FUNC_NAME s_scm_srfi1_take_right
1556 {
1557 SCM tail = scm_list_tail (lst, n);
1558 while (scm_is_pair (tail))
1559 {
1560 lst = SCM_CDR (lst);
1561 tail = SCM_CDR (tail);
1562 }
1563 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P(tail), tail, SCM_ARG1, FUNC_NAME, "list");
1564 return lst;
1565 }
1566 #undef FUNC_NAME
1567
1568
1569 SCM_DEFINE (scm_srfi1_take_while, "take-while", 2, 0, 0,
1570 (SCM pred, SCM lst),
1571 "Return a new list which is the longest initial prefix of\n"
1572 "@var{lst} whose elements all satisfy the predicate @var{pred}.")
1573 #define FUNC_NAME s_scm_srfi1_take_while
1574 {
1575 scm_t_trampoline_1 pred_tramp;
1576 SCM ret, *p;
1577
1578 pred_tramp = scm_trampoline_1 (pred);
1579 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
1580
1581 ret = SCM_EOL;
1582 p = &ret;
1583 for ( ; scm_is_pair (lst); lst = SCM_CDR (lst))
1584 {
1585 SCM elem = SCM_CAR (lst);
1586 if (scm_is_false (pred_tramp (pred, elem)))
1587 goto done;
1588
1589 /* want this elem, tack it onto the end of ret */
1590 *p = scm_cons (elem, SCM_EOL);
1591 p = SCM_CDRLOC (*p);
1592 }
1593 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
1594
1595 done:
1596 return ret;
1597 }
1598 #undef FUNC_NAME
1599
1600
1601 SCM_DEFINE (scm_srfi1_take_while_x, "take-while!", 2, 0, 0,
1602 (SCM pred, SCM lst),
1603 "Return the longest initial prefix of @var{lst} whose elements\n"
1604 "all satisfy the predicate @var{pred}. @var{lst} may be\n"
1605 "modified to form the return.")
1606 #define FUNC_NAME s_scm_srfi1_take_while_x
1607 {
1608 SCM upto, *p;
1609 scm_t_trampoline_1 pred_tramp;
1610
1611 pred_tramp = scm_trampoline_1 (pred);
1612 SCM_ASSERT (pred_tramp, pred, SCM_ARG1, FUNC_NAME);
1613
1614 p = &lst;
1615 for (upto = lst; scm_is_pair (upto); upto = SCM_CDR (upto))
1616 {
1617 if (scm_is_false (pred_tramp (pred, SCM_CAR (upto))))
1618 goto done;
1619
1620 /* want this element */
1621 p = SCM_CDRLOC (upto);
1622 }
1623 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (upto), lst, SCM_ARG2, FUNC_NAME, "list");
1624
1625 done:
1626 *p = SCM_EOL;
1627 return lst;
1628 }
1629 #undef FUNC_NAME
1630
1631
1632 void
1633 scm_init_srfi_1 (void)
1634 {
1635 SCM the_root_module = scm_lookup_closure_module (SCM_BOOL_F);
1636 #ifndef SCM_MAGIC_SNARFER
1637 #include "srfi/srfi-1.x"
1638 #endif
1639 scm_c_extend_primitive_generic
1640 (SCM_VARIABLE_REF (scm_c_module_lookup (the_root_module, "map")),
1641 SCM_VARIABLE_REF (scm_c_lookup ("map")));
1642 scm_c_extend_primitive_generic
1643 (SCM_VARIABLE_REF (scm_c_module_lookup (the_root_module, "for-each")),
1644 SCM_VARIABLE_REF (scm_c_lookup ("for-each")));
1645 }
1646
1647 /* End of srfi-1.c. */