(scm_odd_p, scm_even_p): Bugfix: Treat result of
[bpt/guile.git] / srfi / srfi-1.c
CommitLineData
ee6aac97
MD
1/* srfi-1.c --- SRFI-1 procedures for Guile
2 *
d0a634de
KR
3 * Copyright (C) 1995, 1996, 1997, 2000, 2001, 2002, 2003 Free Software
4 * Foundation, Inc.
ee6aac97 5 *
73be1d9e
MV
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
ee6aac97 10 *
73be1d9e
MV
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
ee6aac97 15 *
73be1d9e
MV
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
ee6aac97
MD
20
21#include <libguile.h>
22#include <libguile/lang.h>
23
24#include "srfi-1.h"
25
26/* The intent of this file is to gradually replace those Scheme
27 * procedures in srfi-1.scm which extends core primitive procedures,
28 * so that using srfi-1 won't have performance penalties.
29 *
30 * Please feel free to contribute any new replacements!
31 */
32
33static long
34srfi1_ilength (SCM sx)
35{
36 long i = 0;
37 SCM tortoise = sx;
38 SCM hare = sx;
39
40 do {
41 if (SCM_NULL_OR_NIL_P(hare)) return i;
1685446c 42 if (!SCM_CONSP (hare)) return -2;
ee6aac97
MD
43 hare = SCM_CDR(hare);
44 i++;
45 if (SCM_NULL_OR_NIL_P(hare)) return i;
1685446c 46 if (!SCM_CONSP (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 }
52 while (! SCM_EQ_P (hare, tortoise));
53
54 /* If the tortoise ever catches the hare, then the list must contain
55 a cycle. */
56 return -1;
57}
58
d0a634de
KR
59static SCM
60equal_trampoline (SCM proc, SCM arg1, SCM arg2)
61{
62 return scm_equal_p (arg1, arg2);
63}
64
65
66SCM_DEFINE (scm_srfi1_delete, "delete", 2, 1, 0,
67 (SCM x, SCM lst, SCM pred),
68 "Return a list containing the elements of @var{lst} but with\n"
69 "those equal to @var{x} deleted. The returned elements will be\n"
70 "in the same order as they were in @var{lst}.\n"
71 "\n"
72 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
73 "given. An equality call is made just once for each element,\n"
74 "but the order in which the calls are made on the elements is\n"
75 "unspecified.\n"
76 "\n"
77 "The equality calls are always @code{(pred x elem)}, ie.@: the\n"
78 "given @var{x} is first. This means for instance elements\n"
79 "greater than 5 can be deleted with @code{(delete 5 lst <)}.\n"
80 "\n"
81 "@var{lst} is not modified, but the returned list might share a\n"
82 "common tail with @var{lst}.")
83#define FUNC_NAME s_scm_srfi1_delete
84{
85 scm_t_trampoline_2 equal_p;
86 SCM ret, *p, keeplst;
87
88 if (SCM_UNBNDP (pred))
89 return scm_delete (x, lst);
90
91 equal_p = scm_trampoline_2 (pred);
92 SCM_ASSERT (equal_p, pred, SCM_ARG3, FUNC_NAME);
93
94 /* ret is the return list being constructed. p is where to append to it,
95 initially &ret then SCM_CDRLOC of the last pair. lst progresses as
96 elements are considered.
97
98 Elements to be retained are not immediately copied, instead keeplst is
99 the last pair in lst which is to be retained but not yet copied. When
100 there's no more deletions, *p can be set to keeplst to share the
101 remainder of the original lst. (The entire original lst if there's no
102 deletions at all.) */
103
104 keeplst = lst;
105 ret = SCM_EOL;
106 p = &ret;
107
108 for ( ; SCM_CONSP (lst); lst = SCM_CDR (lst))
109 {
110 if (! SCM_FALSEP (equal_p (pred, x, SCM_CAR (lst))))
111 {
112 /* delete this element, so copy from keeplst (inclusive) to lst
113 (exclusive) onto ret */
114 while (! SCM_EQ_P (keeplst, lst))
115 {
116 SCM c = scm_cons (SCM_CAR (keeplst), SCM_EOL);
117 *p = c;
118 p = SCM_CDRLOC (c);
119 keeplst = SCM_CDR (keeplst);
120 }
121
122 keeplst = SCM_CDR (lst);
123 }
124 }
125
126 /* final retained elements */
127 *p = keeplst;
128
129 /* demand that lst was a proper list */
130 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG2, FUNC_NAME, "list");
131
132 return ret;
133}
134#undef FUNC_NAME
135
136
137SCM_DEFINE (scm_srfi1_delete_x, "delete!", 2, 1, 0,
138 (SCM x, SCM lst, SCM pred),
139 "Return a list containing the elements of @var{lst} but with\n"
140 "those equal to @var{x} deleted. The returned elements will be\n"
141 "in the same order as they were in @var{lst}.\n"
142 "\n"
143 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
144 "given. An equality call is made just once for each element,\n"
145 "but the order in which the calls are made on the elements is\n"
146 "unspecified.\n"
147 "\n"
148 "The equality calls are always @code{(pred x elem)}, ie.@: the\n"
149 "given @var{x} is first. This means for instance elements\n"
150 "greater than 5 can be deleted with @code{(delete 5 lst <)}.\n"
151 "\n"
152 "@var{lst} may be modified to construct the returned list.")
153#define FUNC_NAME s_scm_srfi1_delete_x
154{
155 scm_t_trampoline_2 equal_p;
156 SCM walk;
157 SCM *prev;
158
159 if (SCM_UNBNDP (pred))
160 return scm_delete_x (x, lst);
161
162 equal_p = scm_trampoline_2 (pred);
163 SCM_ASSERT (equal_p, pred, SCM_ARG3, FUNC_NAME);
164
165 for (prev = &lst, walk = lst;
166 SCM_CONSP (walk);
167 walk = SCM_CDR (walk))
168 {
169 if (! SCM_FALSEP (equal_p (pred, x, SCM_CAR (walk))))
170 *prev = SCM_CDR (walk);
171 else
172 prev = SCM_CDRLOC (walk);
173 }
174
175 /* demand the input was a proper list */
176 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (walk), walk, SCM_ARG2, FUNC_NAME,"list");
177 return lst;
178}
179#undef FUNC_NAME
180
181
182SCM_DEFINE (scm_srfi1_delete_duplicates, "delete-duplicates", 1, 1, 0,
183 (SCM lst, SCM pred),
184 "Return a list containing the elements of @var{lst} but without\n"
185 "duplicates.\n"
186 "\n"
187 "When elements are equal, only the first in @var{lst} is\n"
188 "retained. Equal elements can be anywhere in @var{lst}, they\n"
189 "don't have to be adjacent. The returned list will have the\n"
190 "retained elements in the same order as they were in @var{lst}.\n"
191 "\n"
192 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
193 "given. Calls @code{(pred x y)} are made with element @var{x}\n"
194 "being before @var{y} in @var{lst}. A call is made at most once\n"
195 "for each combination, but the sequence of the calls across the\n"
196 "elements is unspecified.\n"
197 "\n"
198 "@var{lst} is not modified, but the return might share a common\n"
199 "tail with @var{lst}.\n"
200 "\n"
201 "In the worst case, this is an @math{O(N^2)} algorithm because\n"
202 "it must check each element against all those preceding it. For\n"
203 "long lists it is more efficient to sort and then compare only\n"
204 "adjacent elements.")
205#define FUNC_NAME s_scm_srfi1_delete_duplicates
206{
207 scm_t_trampoline_2 equal_p;
208 SCM ret, *p, keeplst, item, l;
209
210 /* ret is the new list constructed. p is where to append, initially &ret
211 then SCM_CDRLOC of the last pair. lst is advanced as each element is
212 considered.
213
214 Elements retained are not immediately appended to ret, instead keeplst
215 is the last pair in lst which is to be kept but is not yet copied.
216 Initially this is the first pair of lst, since the first element is
217 always retained.
218
219 *p is kept set to keeplst, so ret (inclusive) to lst (exclusive) is all
220 the elements retained, making the equality search loop easy.
221
222 If an item must be deleted, elements from keeplst (inclusive) to lst
223 (exclusive) must be copied and appended to ret. When there's no more
224 deletions, *p is left set to keeplst, so ret shares structure with the
225 original lst. (ret will be the entire original lst if there are no
226 deletions.) */
227
228 /* skip to end if an empty list (or something invalid) */
229 ret = lst;
230 if (SCM_CONSP (lst))
231 {
232 if (SCM_UNBNDP (pred))
233 equal_p = equal_trampoline;
234 else
235 {
236 equal_p = scm_trampoline_2 (pred);
237 SCM_ASSERT (equal_p, pred, SCM_ARG2, FUNC_NAME);
238 }
239
240 keeplst = lst;
241 p = &ret;
242
243 /* loop over lst elements starting from second */
244 for (;;)
245 {
246 lst = SCM_CDR (lst);
247 if (! SCM_CONSP (lst))
248 break;
249 item = SCM_CAR (lst);
250
251 /* loop searching ret upto lst */
252 for (l = ret; ! SCM_EQ_P (l, lst); l = SCM_CDR (l))
253 {
254 if (! SCM_FALSEP (equal_p (pred, SCM_CAR (l), item)))
255 {
256 /* duplicate, don't want this element, so copy keeplst
257 (inclusive) to lst (exclusive) onto ret */
258 while (! SCM_EQ_P (keeplst, lst))
259 {
260 SCM c = scm_cons (SCM_CAR (keeplst), SCM_EOL);
261 *p = c;
262 p = SCM_CDRLOC (c);
263 keeplst = SCM_CDR (keeplst);
264 }
265
266 keeplst = SCM_CDR (lst); /* elem after the one deleted */
267 *p = keeplst;
268 break;
269 }
270 }
271 }
272 }
273
274 /* demand that lst was a proper list */
275 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG1, FUNC_NAME, "list");
276
277 return ret;
278}
279#undef FUNC_NAME
280
281
282SCM_DEFINE (scm_srfi1_delete_duplicates_x, "delete-duplicates!", 1, 1, 0,
283 (SCM lst, SCM pred),
284 "Return a list containing the elements of @var{lst} but without\n"
285 "duplicates.\n"
286 "\n"
287 "When elements are equal, only the first in @var{lst} is\n"
288 "retained. Equal elements can be anywhere in @var{lst}, they\n"
289 "don't have to be adjacent. The returned list will have the\n"
290 "retained elements in the same order as they were in @var{lst}.\n"
291 "\n"
292 "Equality is determined by @var{pred}, or @code{equal?} if not\n"
293 "given. Calls @code{(pred x y)} are made with element @var{x}\n"
294 "being before @var{y} in @var{lst}. A call is made at most once\n"
295 "for each combination, but the sequence of the calls across the\n"
296 "elements is unspecified.\n"
297 "\n"
298 "@var{lst} may be modified to construct the returned list.\n"
299 "\n"
300 "In the worst case, this is an @math{O(N^2)} algorithm because\n"
301 "it must check each element against all those preceding it. For\n"
302 "long lists it is more efficient to sort and then compare only\n"
303 "adjacent elements.")
304#define FUNC_NAME s_scm_srfi1_delete_duplicates_x
305{
306 scm_t_trampoline_2 equal_p;
307 SCM ret, endret, item, l;
308
309 /* ret is the return list, constructed from the pairs in lst. endret is
310 the last pair of ret, initially the first pair. lst is advanced as
311 elements are considered. */
312
313 /* skip to end if an empty list (or something invalid) */
314 ret = lst;
315 if (SCM_CONSP (lst))
316 {
317 if (SCM_UNBNDP (pred))
318 equal_p = equal_trampoline;
319 else
320 {
321 equal_p = scm_trampoline_2 (pred);
322 SCM_ASSERT (equal_p, pred, SCM_ARG2, FUNC_NAME);
323 }
324
325 endret = ret;
326
327 /* loop over lst elements starting from second */
328 for (;;)
329 {
330 lst = SCM_CDR (lst);
331 if (! SCM_CONSP (lst))
332 break;
333 item = SCM_CAR (lst);
334
335 /* is item equal to any element from ret to endret (inclusive)? */
336 l = ret;
337 for (;;)
338 {
339 if (! SCM_FALSEP (equal_p (pred, SCM_CAR (l), item)))
340 break; /* equal, forget this element */
341
342 if (SCM_EQ_P (l, endret))
343 {
344 /* not equal to any, so append this pair */
345 SCM_SETCDR (endret, lst);
346 endret = lst;
347 break;
348 }
349 l = SCM_CDR (l);
350 }
351 }
352
353 /* terminate, in case last element was deleted */
354 SCM_SETCDR (endret, SCM_EOL);
355 }
356
357 /* demand that lst was a proper list */
358 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (lst), lst, SCM_ARG1, FUNC_NAME, "list");
359
360 return ret;
361}
362#undef FUNC_NAME
363
364
ee6aac97
MD
365/* Typechecking for multi-argument MAP and FOR-EACH.
366
367 Verify that each element of the vector ARGV, except for the first,
368 is a list and return minimum length. Attribute errors to WHO,
369 and claim that the i'th element of ARGV is WHO's i+2'th argument. */
370static inline int
371check_map_args (SCM argv,
372 long len,
373 SCM gf,
374 SCM proc,
375 SCM args,
376 const char *who)
377{
378 SCM const *ve = SCM_VELTS (argv);
379 long i;
380
381 for (i = SCM_VECTOR_LENGTH (argv) - 1; i >= 1; i--)
382 {
383 long elt_len;
384
385 if (!(SCM_NULLP (ve[i]) || SCM_CONSP (ve[i])))
386 {
387 check_map_error:
388 if (gf)
389 scm_apply_generic (gf, scm_cons (proc, args));
390 else
391 scm_wrong_type_arg (who, i + 2, ve[i]);
392 }
393
394 elt_len = srfi1_ilength (ve[i]);
395 if (elt_len < -1)
396 goto check_map_error;
397
398 if (len < 0 || (elt_len >= 0 && elt_len < len))
399 len = elt_len;
400 }
401 if (len < 0)
402 /* i == 0 */
403 goto check_map_error;
404
405 scm_remember_upto_here_1 (argv);
406 return len;
407}
408
409
410SCM_GPROC (s_srfi1_map, "map", 2, 0, 1, scm_srfi1_map, g_srfi1_map);
411
412/* Note: Currently, scm_srfi1_map applies PROC to the argument list(s)
413 sequentially, starting with the first element(s). This is used in
414 the Scheme procedure `map-in-order', which guarantees sequential
415 behaviour, is implemented using scm_map. If the behaviour changes,
416 we need to update `map-in-order'.
417*/
418
419SCM
420scm_srfi1_map (SCM proc, SCM arg1, SCM args)
421#define FUNC_NAME s_srfi1_map
422{
423 long i, len;
424 SCM res = SCM_EOL;
425 SCM *pres = &res;
426 SCM const *ve = &args; /* Keep args from being optimized away. */
427
428 len = srfi1_ilength (arg1);
429 SCM_GASSERTn ((SCM_NULLP (arg1) || SCM_CONSP (arg1)) && len >= -1,
430 g_srfi1_map,
431 scm_cons2 (proc, arg1, args), SCM_ARG2, s_srfi1_map);
432 SCM_VALIDATE_REST_ARGUMENT (args);
433 if (SCM_NULLP (args))
434 {
435 scm_t_trampoline_1 call = scm_trampoline_1 (proc);
436 SCM_GASSERT2 (call, g_srfi1_map, proc, arg1, SCM_ARG1, s_srfi1_map);
437 SCM_GASSERT2 (len >= 0, g_srfi1_map, proc, arg1, SCM_ARG2, s_srfi1_map);
438 while (SCM_NIMP (arg1))
439 {
440 *pres = scm_list_1 (call (proc, SCM_CAR (arg1)));
441 pres = SCM_CDRLOC (*pres);
442 arg1 = SCM_CDR (arg1);
443 }
444 return res;
445 }
446 if (SCM_NULLP (SCM_CDR (args)))
447 {
448 SCM arg2 = SCM_CAR (args);
449 int len2 = srfi1_ilength (arg2);
450 scm_t_trampoline_2 call = scm_trampoline_2 (proc);
451 SCM_GASSERTn (call, g_srfi1_map,
452 scm_cons2 (proc, arg1, args), SCM_ARG1, s_srfi1_map);
453 if (len < 0 || (len2 >= 0 && len2 < len))
454 len = len2;
455 SCM_GASSERTn ((SCM_NULLP (arg2) || SCM_CONSP (arg2))
456 && len >= 0 && len2 >= -1,
457 g_srfi1_map,
458 scm_cons2 (proc, arg1, args),
f9ac1c2d 459 len2 >= 0 ? SCM_ARG2 : SCM_ARG3,
ee6aac97
MD
460 s_srfi1_map);
461 while (len > 0)
462 {
463 *pres = scm_list_1 (call (proc, SCM_CAR (arg1), SCM_CAR (arg2)));
464 pres = SCM_CDRLOC (*pres);
465 arg1 = SCM_CDR (arg1);
466 arg2 = SCM_CDR (arg2);
467 --len;
468 }
469 return res;
470 }
471 args = scm_vector (arg1 = scm_cons (arg1, args));
472 ve = SCM_VELTS (args);
473 len = check_map_args (args, len, g_srfi1_map, proc, arg1, s_srfi1_map);
474 while (len > 0)
475 {
476 arg1 = SCM_EOL;
477 for (i = SCM_VECTOR_LENGTH (args) - 1; i >= 0; i--)
478 {
479 arg1 = scm_cons (SCM_CAR (ve[i]), arg1);
480 SCM_VECTOR_SET (args, i, SCM_CDR (ve[i]));
481 }
482 *pres = scm_list_1 (scm_apply (proc, arg1, SCM_EOL));
483 pres = SCM_CDRLOC (*pres);
484 --len;
485 }
486 return res;
487}
488#undef FUNC_NAME
489
490SCM_REGISTER_PROC (s_srfi1_map_in_order, "map-in-order", 2, 0, 1, scm_srfi1_map);
491
492SCM_GPROC (s_srfi1_for_each, "for-each", 2, 0, 1, scm_srfi1_for_each, g_srfi1_for_each);
493
494SCM
495scm_srfi1_for_each (SCM proc, SCM arg1, SCM args)
496#define FUNC_NAME s_srfi1_for_each
497{
498 SCM const *ve = &args; /* Keep args from being optimized away. */
499 long i, len;
500 len = srfi1_ilength (arg1);
501 SCM_GASSERTn ((SCM_NULLP (arg1) || SCM_CONSP (arg1)) && len >= -1,
502 g_srfi1_for_each, scm_cons2 (proc, arg1, args),
503 SCM_ARG2, s_srfi1_for_each);
504 SCM_VALIDATE_REST_ARGUMENT (args);
505 if (SCM_NULLP (args))
506 {
507 scm_t_trampoline_1 call = scm_trampoline_1 (proc);
508 SCM_GASSERT2 (call, g_srfi1_for_each, proc, arg1,
509 SCM_ARG1, s_srfi1_for_each);
510 SCM_GASSERT2 (len >= 0, g_srfi1_for_each, proc, arg1,
511 SCM_ARG2, s_srfi1_map);
512 while (SCM_NIMP (arg1))
513 {
514 call (proc, SCM_CAR (arg1));
515 arg1 = SCM_CDR (arg1);
516 }
517 return SCM_UNSPECIFIED;
518 }
519 if (SCM_NULLP (SCM_CDR (args)))
520 {
521 SCM arg2 = SCM_CAR (args);
522 int len2 = srfi1_ilength (arg2);
523 scm_t_trampoline_2 call = scm_trampoline_2 (proc);
524 SCM_GASSERTn (call, g_srfi1_for_each,
525 scm_cons2 (proc, arg1, args), SCM_ARG1, s_srfi1_for_each);
526 if (len < 0 || (len2 >= 0 && len2 < len))
527 len = len2;
528 SCM_GASSERTn ((SCM_NULLP (arg2) || SCM_CONSP (arg2))
f9ac1c2d 529 && len >= 0 && len2 >= -1,
ee6aac97
MD
530 g_srfi1_for_each,
531 scm_cons2 (proc, arg1, args),
f9ac1c2d 532 len2 >= 0 ? SCM_ARG2 : SCM_ARG3,
ee6aac97
MD
533 s_srfi1_for_each);
534 while (len > 0)
535 {
536 call (proc, SCM_CAR (arg1), SCM_CAR (arg2));
537 arg1 = SCM_CDR (arg1);
538 arg2 = SCM_CDR (arg2);
539 --len;
540 }
541 return SCM_UNSPECIFIED;
542 }
543 args = scm_vector (arg1 = scm_cons (arg1, args));
544 ve = SCM_VELTS (args);
545 len = check_map_args (args, len, g_srfi1_for_each, proc, arg1,
546 s_srfi1_for_each);
547 while (len > 0)
548 {
549 arg1 = SCM_EOL;
550 for (i = SCM_VECTOR_LENGTH (args) - 1; i >= 0; i--)
551 {
552 arg1 = scm_cons (SCM_CAR (ve[i]), arg1);
553 SCM_VECTOR_SET (args, i, SCM_CDR (ve[i]));
554 }
555 scm_apply (proc, arg1, SCM_EOL);
556 --len;
557 }
558 return SCM_UNSPECIFIED;
559}
560#undef FUNC_NAME
561
562
ee6aac97
MD
563SCM_DEFINE (scm_srfi1_member, "member", 2, 1, 0,
564 (SCM x, SCM lst, SCM pred),
565 "Return the first sublist of @var{lst} whose car is\n"
7692d26b 566 "@var{equal?} to @var{x} where the sublists of @var{lst} are\n"
ee6aac97
MD
567 "the non-empty lists returned by @code{(list-tail @var{lst}\n"
568 "@var{k})} for @var{k} less than the length of @var{lst}. If\n"
569 "@var{x} does not occur in @var{lst}, then @code{#f} (not the\n"
7692d26b
MD
570 "empty list) is returned. If optional third argument @var{equal?}\n"
571 "isn't given, @code{equal?} is used for comparison.\n"
572 "(Extended from R5RS.)\n")
ee6aac97
MD
573#define FUNC_NAME s_scm_srfi1_member
574{
575 scm_t_trampoline_2 equal_p;
576 SCM_VALIDATE_LIST (2, lst);
577 if (SCM_UNBNDP (pred))
578 equal_p = equal_trampoline;
579 else
580 {
581 equal_p = scm_trampoline_2 (pred);
582 SCM_ASSERT (equal_p, pred, 3, FUNC_NAME);
583 }
584 for (; !SCM_NULL_OR_NIL_P (lst); lst = SCM_CDR (lst))
585 {
586 if (!SCM_FALSEP (equal_p (pred, SCM_CAR (lst), x)))
587 return lst;
588 }
589 return SCM_BOOL_F;
590}
591#undef FUNC_NAME
592
7692d26b
MD
593SCM_DEFINE (scm_srfi1_assoc, "assoc", 2, 1, 0,
594 (SCM key, SCM alist, SCM pred),
595 "Behaves like @code{assq} but uses third argument @var{pred?}\n"
596 "for key comparison. If @var{pred?} is not supplied,\n"
597 "@code{equal?} is used. (Extended from R5RS.)\n")
598#define FUNC_NAME s_scm_srfi1_assoc
599{
600 SCM ls = alist;
601 scm_t_trampoline_2 equal_p;
602 if (SCM_UNBNDP (pred))
603 equal_p = equal_trampoline;
604 else
605 {
606 equal_p = scm_trampoline_2 (pred);
607 SCM_ASSERT (equal_p, pred, 3, FUNC_NAME);
608 }
609 for(; SCM_CONSP (ls); ls = SCM_CDR (ls))
610 {
611 SCM tmp = SCM_CAR (ls);
612 SCM_ASSERT_TYPE (SCM_CONSP (tmp), alist, SCM_ARG2, FUNC_NAME,
613 "association list");
614 if (SCM_NFALSEP (equal_p (pred, SCM_CAR (tmp), key)))
615 return tmp;
616 }
617 SCM_ASSERT_TYPE (SCM_NULL_OR_NIL_P (ls), alist, SCM_ARG2, FUNC_NAME,
618 "association list");
619 return SCM_BOOL_F;
620}
621#undef FUNC_NAME
622
ee6aac97
MD
623void
624scm_init_srfi_1 (void)
625{
a48d60b1 626 SCM the_root_module = scm_lookup_closure_module (SCM_BOOL_F);
ee6aac97
MD
627#ifndef SCM_MAGIC_SNARFER
628#include "srfi/srfi-1.x"
629#endif
a48d60b1
MD
630 scm_c_extend_primitive_generic
631 (SCM_VARIABLE_REF (scm_c_module_lookup (the_root_module, "map")),
632 SCM_VARIABLE_REF (scm_c_lookup ("map")));
633 scm_c_extend_primitive_generic
634 (SCM_VARIABLE_REF (scm_c_module_lookup (the_root_module, "for-each")),
635 SCM_VARIABLE_REF (scm_c_lookup ("for-each")));
ee6aac97
MD
636}
637
638/* End of srfi-1.c. */