* eval.c (s_scm_copy_tree): idem.
[bpt/guile.git] / libguile / list.c
CommitLineData
71a89639 1/* Copyright (C) 1995,1996,1997,2000,2001, 2003, 2004 Free Software Foundation, Inc.
0f2d19dd 2 *
73be1d9e
MV
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
0f2d19dd 7 *
73be1d9e
MV
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
0f2d19dd 12 *
73be1d9e
MV
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
1bbd0b84 17
1bbd0b84 18
0f2d19dd 19\f
a0599745
MD
20#include "libguile/_scm.h"
21#include "libguile/eq.h"
c96d76b8 22#include "libguile/lang.h"
20e6290e 23
a0599745
MD
24#include "libguile/validate.h"
25#include "libguile/list.h"
c614a00b 26#include "libguile/eval.h"
0f2d19dd
JB
27
28#ifdef __STDC__
29#include <stdarg.h>
30#define var_start(x, y) va_start(x, y)
31#else
32#include <varargs.h>
33#define var_start(x, y) va_start(x)
34#endif
35
36\f
df13742c 37/* creating lists */
0f2d19dd 38
34d19ef6 39#define SCM_I_CONS(cell, x, y) \
1afff620 40do { \
228a24ef 41 cell = scm_cell ((scm_t_bits)x, (scm_t_bits)y); \
1afff620
KN
42} while (0)
43
44SCM
45scm_list_1 (SCM e1)
46{
47 SCM c1;
48 SCM_I_CONS (c1, e1, SCM_EOL);
49 return c1;
50}
51
52SCM
53scm_list_2 (SCM e1, SCM e2)
54{
55 SCM c1, c2;
56 SCM_I_CONS (c2, e2, SCM_EOL);
57 SCM_I_CONS (c1, e1, c2);
58 return c1;
59}
60
61SCM
62scm_list_3 (SCM e1, SCM e2, SCM e3)
63{
64 SCM c1, c2, c3;
65 SCM_I_CONS (c3, e3, SCM_EOL);
66 SCM_I_CONS (c2, e2, c3);
67 SCM_I_CONS (c1, e1, c2);
68 return c1;
69}
70
71SCM
72scm_list_4 (SCM e1, SCM e2, SCM e3, SCM e4)
73{
74 return scm_cons2 (e1, e2, scm_list_2 (e3, e4));
75}
76
77SCM
78scm_list_5 (SCM e1, SCM e2, SCM e3, SCM e4, SCM e5)
79{
80 return scm_cons2 (e1, e2, scm_list_3 (e3, e4, e5));
81}
82
0f2d19dd 83SCM
1afff620 84scm_list_n (SCM elt, ...)
0f2d19dd
JB
85{
86 va_list foo;
2de14ecd
GB
87 SCM answer = SCM_EOL;
88 SCM *pos = &answer;
0f2d19dd
JB
89
90 var_start (foo, elt);
fbd485ba 91 while (! SCM_UNBNDP (elt))
0f2d19dd 92 {
1e55d288 93#if (SCM_DEBUG_CELL_ACCESSES == 1)
eb741d98
HWN
94 if (SCM_NIMP (elt))
95 SCM_VALIDATE_CELL(elt, 0);
1e55d288 96#endif
0f2d19dd 97 *pos = scm_cons (elt, SCM_EOL);
25d8012c 98 pos = SCM_CDRLOC (*pos);
0f2d19dd
JB
99 elt = va_arg (foo, SCM);
100 }
de90ef0f 101 va_end (foo);
0f2d19dd
JB
102 return answer;
103}
104
105
3b3b36dd 106SCM_DEFINE (scm_list, "list", 0, 0, 1,
1bbd0b84 107 (SCM objs),
5352393c
MG
108 "Return a list containing @var{objs}, the arguments to\n"
109 "@code{list}.")
1bbd0b84 110#define FUNC_NAME s_scm_list
0f2d19dd
JB
111{
112 return objs;
113}
1bbd0b84 114#undef FUNC_NAME
0f2d19dd
JB
115
116
26a379b2 117SCM_DEFINE (scm_cons_star, "cons*", 1, 0, 1,
1bbd0b84 118 (SCM arg, SCM rest),
5352393c
MG
119 "Like @code{list}, but the last arg provides the tail of the\n"
120 "constructed list, returning @code{(cons @var{arg1} (cons\n"
a17bb5fd 121 "@var{arg2} (cons @dots{} @var{argn})))}. Requires at least one\n"
5352393c
MG
122 "argument. If given one argument, that argument is returned as\n"
123 "result. This function is called @code{list*} in some other\n"
124 "Schemes and in Common LISP.")
26a379b2 125#define FUNC_NAME s_scm_cons_star
a610b8d9 126{
af45e3b0
DH
127 SCM_VALIDATE_REST_ARGUMENT (rest);
128 if (!SCM_NULLP (rest))
a610b8d9
MD
129 {
130 SCM prev = arg = scm_cons (arg, rest);
9ff1720f 131 while (!SCM_NULLP (SCM_CDR (rest)))
a610b8d9
MD
132 {
133 prev = rest;
134 rest = SCM_CDR (rest);
135 }
136 SCM_SETCDR (prev, SCM_CAR (rest));
137 }
138 return arg;
139}
1bbd0b84 140#undef FUNC_NAME
a610b8d9 141
0f2d19dd
JB
142
143\f
df13742c 144/* general questions about lists --- null?, list?, length, etc. */
0f2d19dd 145
3b3b36dd 146SCM_DEFINE (scm_null_p, "null?", 1, 0, 0,
1bbd0b84 147 (SCM x),
5352393c 148 "Return @code{#t} iff @var{x} is the empty list, else @code{#f}.")
1bbd0b84 149#define FUNC_NAME s_scm_null_p
0f2d19dd 150{
c96d76b8 151 return SCM_BOOL (SCM_NULL_OR_NIL_P (x));
0f2d19dd 152}
1bbd0b84 153#undef FUNC_NAME
0f2d19dd 154
2de14ecd 155
3b3b36dd 156SCM_DEFINE (scm_list_p, "list?", 1, 0, 0,
1bbd0b84 157 (SCM x),
5352393c 158 "Return @code{#t} iff @var{x} is a proper list, else @code{#f}.")
1bbd0b84 159#define FUNC_NAME s_scm_list_p
0f2d19dd 160{
2de14ecd 161 return SCM_BOOL (scm_ilength (x) >= 0);
0f2d19dd 162}
1bbd0b84 163#undef FUNC_NAME
0f2d19dd
JB
164
165
df13742c 166/* Return the length of SX, or -1 if it's not a proper list.
448a3bc2 167 This uses the "tortoise and hare" algorithm to detect "infinitely
df13742c
JB
168 long" lists (i.e. lists with cycles in their cdrs), and returns -1
169 if it does find one. */
c014a02e
ML
170long
171scm_ilength(SCM sx)
0f2d19dd 172{
c014a02e 173 long i = 0;
e1385ffc
GB
174 SCM tortoise = sx;
175 SCM hare = sx;
df13742c 176
0f2d19dd 177 do {
c96d76b8 178 if (SCM_NULL_OR_NIL_P(hare)) return i;
1685446c 179 if (!SCM_CONSP (hare)) return -1;
df13742c 180 hare = SCM_CDR(hare);
0f2d19dd 181 i++;
c96d76b8 182 if (SCM_NULL_OR_NIL_P(hare)) return i;
1685446c 183 if (!SCM_CONSP (hare)) return -1;
df13742c 184 hare = SCM_CDR(hare);
0f2d19dd 185 i++;
448a3bc2
JB
186 /* For every two steps the hare takes, the tortoise takes one. */
187 tortoise = SCM_CDR(tortoise);
0f2d19dd 188 }
fbd485ba 189 while (! SCM_EQ_P (hare, tortoise));
df13742c 190
448a3bc2 191 /* If the tortoise ever catches the hare, then the list must contain
df13742c 192 a cycle. */
0f2d19dd
JB
193 return -1;
194}
195
2de14ecd 196
3b3b36dd 197SCM_DEFINE (scm_length, "length", 1, 0, 0,
1bbd0b84 198 (SCM lst),
5352393c 199 "Return the number of elements in list @var{lst}.")
1bbd0b84 200#define FUNC_NAME s_scm_length
0f2d19dd 201{
c014a02e 202 long i;
34d19ef6 203 SCM_VALIDATE_LIST_COPYLEN (1, lst, i);
0f2d19dd
JB
204 return SCM_MAKINUM (i);
205}
1bbd0b84 206#undef FUNC_NAME
0f2d19dd
JB
207
208
209\f
df13742c 210/* appending lists */
0f2d19dd 211
a1ec6916 212SCM_DEFINE (scm_append, "append", 0, 0, 1,
1bbd0b84 213 (SCM args),
5352393c
MG
214 "Return a list consisting of the elements the lists passed as\n"
215 "arguments.\n"
1e6808ea 216 "@lisp\n"
5352393c
MG
217 "(append '(x) '(y)) @result{} (x y)\n"
218 "(append '(a) '(b c d)) @result{} (a b c d)\n"
219 "(append '(a (b)) '((c))) @result{} (a (b) (c))\n"
1e6808ea 220 "@end lisp\n"
5352393c
MG
221 "The resulting list is always newly allocated, except that it\n"
222 "shares structure with the last list argument. The last\n"
223 "argument may actually be any object; an improper list results\n"
224 "if the last argument is not a proper list.\n"
1e6808ea 225 "@lisp\n"
5352393c
MG
226 "(append '(a b) '(c . d)) @result{} (a b c . d)\n"
227 "(append '() 'a) @result{} a\n"
1e6808ea 228 "@end lisp")
1bbd0b84 229#define FUNC_NAME s_scm_append
0f2d19dd 230{
af45e3b0
DH
231 SCM_VALIDATE_REST_ARGUMENT (args);
232 if (SCM_NULLP (args)) {
233 return SCM_EOL;
234 } else {
235 SCM res = SCM_EOL;
236 SCM *lloc = &res;
237 SCM arg = SCM_CAR (args);
4c13270f 238 int argnum = 1;
af45e3b0
DH
239 args = SCM_CDR (args);
240 while (!SCM_NULLP (args)) {
241 while (SCM_CONSP (arg)) {
242 *lloc = scm_cons (SCM_CAR (arg), SCM_EOL);
243 lloc = SCM_CDRLOC (*lloc);
244 arg = SCM_CDR (arg);
245 }
4c13270f 246 SCM_VALIDATE_NULL_OR_NIL (argnum, arg);
af45e3b0
DH
247 arg = SCM_CAR (args);
248 args = SCM_CDR (args);
4c13270f 249 argnum++;
af45e3b0
DH
250 };
251 *lloc = arg;
0f2d19dd
JB
252 return res;
253 }
0f2d19dd 254}
1bbd0b84 255#undef FUNC_NAME
0f2d19dd
JB
256
257
a1ec6916 258SCM_DEFINE (scm_append_x, "append!", 0, 0, 1,
1e6808ea
MG
259 (SCM lists),
260 "A destructive version of @code{append} (@pxref{Pairs and\n"
7a095584 261 "Lists,,,r5rs, The Revised^5 Report on Scheme}). The cdr field\n"
1e6808ea 262 "of each list's final pair is changed to point to the head of\n"
71a89639 263 "the next list, so no consing is performed. Return\n"
1e6808ea 264 "the mutated list.")
1bbd0b84 265#define FUNC_NAME s_scm_append_x
0f2d19dd 266{
1e6808ea 267 SCM_VALIDATE_REST_ARGUMENT (lists);
af45e3b0 268 while (1) {
1e6808ea 269 if (SCM_NULLP (lists)) {
af45e3b0
DH
270 return SCM_EOL;
271 } else {
1e6808ea
MG
272 SCM arg = SCM_CAR (lists);
273 lists = SCM_CDR (lists);
274 if (SCM_NULLP (lists)) {
af45e3b0 275 return arg;
c96d76b8 276 } else if (!SCM_NULL_OR_NIL_P (arg)) {
af45e3b0 277 SCM_VALIDATE_CONS (SCM_ARG1, arg);
1e6808ea 278 SCM_SETCDR (scm_last_pair (arg), scm_append_x (lists));
af45e3b0
DH
279 return arg;
280 }
281 }
282 }
0f2d19dd 283}
1bbd0b84 284#undef FUNC_NAME
0f2d19dd
JB
285
286
3b3b36dd 287SCM_DEFINE (scm_last_pair, "last-pair", 1, 0, 0,
e1385ffc 288 (SCM lst),
71a89639 289 "Return the last pair in @var{lst}, signalling an error if\n"
b380b885 290 "@var{lst} is circular.")
1bbd0b84 291#define FUNC_NAME s_scm_last_pair
df13742c 292{
e1385ffc
GB
293 SCM tortoise = lst;
294 SCM hare = lst;
0f2d19dd 295
c96d76b8
NJ
296 if (SCM_NULL_OR_NIL_P (lst))
297 return lst;
df13742c 298
e1385ffc
GB
299 SCM_VALIDATE_CONS (SCM_ARG1, lst);
300 do {
301 SCM ahead = SCM_CDR(hare);
1685446c 302 if (!SCM_CONSP (ahead)) return hare;
e1385ffc
GB
303 hare = ahead;
304 ahead = SCM_CDR(hare);
1685446c 305 if (!SCM_CONSP (ahead)) return hare;
e1385ffc
GB
306 hare = ahead;
307 tortoise = SCM_CDR(tortoise);
df13742c 308 }
fbd485ba 309 while (! SCM_EQ_P (hare, tortoise));
1afff620 310 SCM_MISC_ERROR ("Circular structure in position 1: ~S", scm_list_1 (lst));
df13742c 311}
1bbd0b84 312#undef FUNC_NAME
df13742c
JB
313
314\f
315/* reversing lists */
0f2d19dd 316
a1ec6916 317SCM_DEFINE (scm_reverse, "reverse", 1, 0, 0,
e1385ffc 318 (SCM lst),
5352393c
MG
319 "Return a new list that contains the elements of @var{lst} but\n"
320 "in reverse order.")
e1385ffc
GB
321#define FUNC_NAME s_scm_reverse
322{
323 SCM result = SCM_EOL;
324 SCM tortoise = lst;
325 SCM hare = lst;
326
327 do {
c96d76b8 328 if (SCM_NULL_OR_NIL_P(hare)) return result;
e1385ffc
GB
329 SCM_ASSERT(SCM_CONSP(hare), lst, 1, FUNC_NAME);
330 result = scm_cons (SCM_CAR (hare), result);
331 hare = SCM_CDR (hare);
c96d76b8 332 if (SCM_NULL_OR_NIL_P(hare)) return result;
e1385ffc
GB
333 SCM_ASSERT(SCM_CONSP(hare), lst, 1, FUNC_NAME);
334 result = scm_cons (SCM_CAR (hare), result);
335 hare = SCM_CDR (hare);
336 tortoise = SCM_CDR (tortoise);
337 }
fbd485ba 338 while (! SCM_EQ_P (hare, tortoise));
1afff620 339 SCM_MISC_ERROR ("Circular structure in position 1: ~S", scm_list_1 (lst));
e1385ffc
GB
340}
341#undef FUNC_NAME
342
343SCM_DEFINE (scm_reverse_x, "reverse!", 1, 1, 0,
344 (SCM lst, SCM new_tail),
7a095584
NJ
345 "A destructive version of @code{reverse} (@pxref{Pairs and Lists,,,r5rs,\n"
346 "The Revised^5 Report on Scheme}). The cdr of each cell in @var{lst} is\n"
71a89639
MV
347 "modified to point to the previous list element. Return the\n"
348 "reversed list.\n\n"
b380b885
MD
349 "Caveat: because the list is modified in place, the tail of the original\n"
350 "list now becomes its head, and the head of the original list now becomes\n"
351 "the tail. Therefore, the @var{lst} symbol to which the head of the\n"
352 "original list was bound now points to the tail. To ensure that the head\n"
353 "of the modified list is not lost, it is wise to save the return value of\n"
354 "@code{reverse!}")
1bbd0b84 355#define FUNC_NAME s_scm_reverse_x
0f2d19dd 356{
e39c3de4 357 SCM_VALIDATE_LIST (1, lst);
3946f0de
MD
358 if (SCM_UNBNDP (new_tail))
359 new_tail = SCM_EOL;
360 else
e39c3de4 361 SCM_VALIDATE_LIST (2, new_tail);
0f2d19dd 362
c96d76b8 363 while (!SCM_NULL_OR_NIL_P (lst))
3946f0de 364 {
e1385ffc
GB
365 SCM old_tail = SCM_CDR (lst);
366 SCM_SETCDR (lst, new_tail);
367 new_tail = lst;
368 lst = old_tail;
3946f0de
MD
369 }
370 return new_tail;
0f2d19dd 371}
1bbd0b84 372#undef FUNC_NAME
0f2d19dd 373
0f2d19dd 374\f
685c0d71 375
df13742c 376/* indexing lists by element number */
0f2d19dd 377
3b3b36dd 378SCM_DEFINE (scm_list_ref, "list-ref", 2, 0, 0,
685c0d71 379 (SCM list, SCM k),
5352393c 380 "Return the @var{k}th element from @var{list}.")
1bbd0b84
GB
381#define FUNC_NAME s_scm_list_ref
382{
685c0d71 383 SCM lst = list;
c014a02e 384 unsigned long int i;
34d19ef6 385 SCM_VALIDATE_INUM_MIN_COPY (2, k,0, i);
685c0d71
DH
386 while (SCM_CONSP (lst)) {
387 if (i == 0)
388 return SCM_CAR (lst);
389 else {
390 --i;
391 lst = SCM_CDR (lst);
392 }
393 };
c96d76b8 394 if (SCM_NULL_OR_NIL_P (lst))
685c0d71
DH
395 SCM_OUT_OF_RANGE (2, k);
396 else
397 SCM_WRONG_TYPE_ARG (1, list);
0f2d19dd 398}
1bbd0b84 399#undef FUNC_NAME
0f2d19dd 400
685c0d71 401
3b3b36dd 402SCM_DEFINE (scm_list_set_x, "list-set!", 3, 0, 0,
685c0d71
DH
403 (SCM list, SCM k, SCM val),
404 "Set the @var{k}th element of @var{list} to @var{val}.")
1bbd0b84
GB
405#define FUNC_NAME s_scm_list_set_x
406{
685c0d71 407 SCM lst = list;
c014a02e 408 unsigned long int i;
34d19ef6 409 SCM_VALIDATE_INUM_MIN_COPY (2, k,0, i);
685c0d71
DH
410 while (SCM_CONSP (lst)) {
411 if (i == 0) {
412 SCM_SETCAR (lst, val);
413 return val;
414 } else {
415 --i;
416 lst = SCM_CDR (lst);
417 }
418 };
c96d76b8 419 if (SCM_NULL_OR_NIL_P (lst))
685c0d71
DH
420 SCM_OUT_OF_RANGE (2, k);
421 else
422 SCM_WRONG_TYPE_ARG (1, list);
0f2d19dd 423}
1bbd0b84 424#undef FUNC_NAME
0f2d19dd
JB
425
426
1bbd0b84
GB
427SCM_REGISTER_PROC(s_list_cdr_ref, "list-cdr-ref", 2, 0, 0, scm_list_tail);
428
3b3b36dd 429SCM_DEFINE (scm_list_tail, "list-tail", 2, 0, 0,
1bbd0b84 430 (SCM lst, SCM k),
8f85c0c6 431 "@deffnx {Scheme Procedure} list-cdr-ref lst k\n"
b380b885
MD
432 "Return the \"tail\" of @var{lst} beginning with its @var{k}th element.\n"
433 "The first element of the list is considered to be element 0.\n\n"
872e0c72 434 "@code{list-tail} and @code{list-cdr-ref} are identical. It may help to\n"
b380b885
MD
435 "think of @code{list-cdr-ref} as accessing the @var{k}th cdr of the list,\n"
436 "or returning the results of cdring @var{k} times down @var{lst}.")
1bbd0b84 437#define FUNC_NAME s_scm_list_tail
df13742c 438{
c014a02e 439 register long i;
34d19ef6 440 SCM_VALIDATE_INUM_MIN_COPY (2, k,0, i);
df13742c 441 while (i-- > 0) {
34d19ef6 442 SCM_VALIDATE_CONS (1, lst);
df13742c
JB
443 lst = SCM_CDR(lst);
444 }
445 return lst;
446}
1bbd0b84 447#undef FUNC_NAME
df13742c 448
0f2d19dd 449
3b3b36dd 450SCM_DEFINE (scm_list_cdr_set_x, "list-cdr-set!", 3, 0, 0,
685c0d71
DH
451 (SCM list, SCM k, SCM val),
452 "Set the @var{k}th cdr of @var{list} to @var{val}.")
1bbd0b84
GB
453#define FUNC_NAME s_scm_list_cdr_set_x
454{
685c0d71 455 SCM lst = list;
c014a02e 456 unsigned long int i;
34d19ef6 457 SCM_VALIDATE_INUM_MIN_COPY (2, k,0, i);
685c0d71
DH
458 while (SCM_CONSP (lst)) {
459 if (i == 0) {
460 SCM_SETCDR (lst, val);
461 return val;
462 } else {
463 --i;
464 lst = SCM_CDR (lst);
465 }
466 };
c96d76b8 467 if (SCM_NULL_OR_NIL_P (lst))
685c0d71
DH
468 SCM_OUT_OF_RANGE (2, k);
469 else
470 SCM_WRONG_TYPE_ARG (1, list);
0f2d19dd 471}
1bbd0b84 472#undef FUNC_NAME
0f2d19dd
JB
473
474
475\f
df13742c 476/* copying lists, perhaps partially */
0f2d19dd 477
3b3b36dd 478SCM_DEFINE (scm_list_head, "list-head", 2, 0, 0,
1bbd0b84 479 (SCM lst, SCM k),
b380b885
MD
480 "Copy the first @var{k} elements from @var{lst} into a new list, and\n"
481 "return it.")
1bbd0b84 482#define FUNC_NAME s_scm_list_head
0f2d19dd
JB
483{
484 SCM answer;
485 SCM * pos;
c014a02e 486 register long i;
0f2d19dd 487
34d19ef6 488 SCM_VALIDATE_INUM_MIN_COPY (2, k,0, i);
0f2d19dd
JB
489 answer = SCM_EOL;
490 pos = &answer;
0f2d19dd
JB
491 while (i-- > 0)
492 {
34d19ef6 493 SCM_VALIDATE_CONS (1, lst);
0f2d19dd 494 *pos = scm_cons (SCM_CAR (lst), SCM_EOL);
25d8012c 495 pos = SCM_CDRLOC (*pos);
0f2d19dd
JB
496 lst = SCM_CDR(lst);
497 }
498 return answer;
499}
1bbd0b84 500#undef FUNC_NAME
0f2d19dd
JB
501
502
a1ec6916 503SCM_DEFINE (scm_list_copy, "list-copy", 1, 0, 0,
1bbd0b84 504 (SCM lst),
b380b885 505 "Return a (newly-created) copy of @var{lst}.")
1bbd0b84 506#define FUNC_NAME s_scm_list_copy
df13742c
JB
507{
508 SCM newlst;
509 SCM * fill_here;
510 SCM from_here;
511
5d6bb349
KN
512 SCM_VALIDATE_LIST (1, lst);
513
df13742c
JB
514 newlst = SCM_EOL;
515 fill_here = &newlst;
516 from_here = lst;
517
0c95b57d 518 while (SCM_CONSP (from_here))
df13742c
JB
519 {
520 SCM c;
521 c = scm_cons (SCM_CAR (from_here), SCM_CDR (from_here));
522 *fill_here = c;
25d8012c 523 fill_here = SCM_CDRLOC (c);
df13742c
JB
524 from_here = SCM_CDR (from_here);
525 }
526 return newlst;
527}
1bbd0b84 528#undef FUNC_NAME
df13742c 529
0f2d19dd 530\f
df13742c
JB
531/* membership tests (memq, memv, etc.) */
532
79a3dafe
DH
533/* The function scm_c_memq returns the first sublist of list whose car is
534 * 'eq?' obj, where the sublists of list are the non-empty lists returned by
535 * (list-tail list k) for k less than the length of list. If obj does not
1e6808ea 536 * occur in list, then #f (not the empty list) is returned.
79a3dafe
DH
537 * List must be a proper list, otherwise scm_c_memq may crash or loop
538 * endlessly.
539 */
540SCM
541scm_c_memq (SCM obj, SCM list)
542{
c96d76b8 543 for (; !SCM_NULL_OR_NIL_P (list); list = SCM_CDR (list))
79a3dafe
DH
544 {
545 if (SCM_EQ_P (SCM_CAR (list), obj))
546 return list;
547 }
548 return SCM_BOOL_F;
549}
550
551
3b3b36dd 552SCM_DEFINE (scm_memq, "memq", 2, 0, 0,
1bbd0b84 553 (SCM x, SCM lst),
5352393c
MG
554 "Return the first sublist of @var{lst} whose car is @code{eq?}\n"
555 "to @var{x} where the sublists of @var{lst} are the non-empty\n"
556 "lists returned by @code{(list-tail @var{lst} @var{k})} for\n"
557 "@var{k} less than the length of @var{lst}. If @var{x} does not\n"
558 "occur in @var{lst}, then @code{#f} (not the empty list) is\n"
559 "returned.")
1bbd0b84 560#define FUNC_NAME s_scm_memq
0f2d19dd 561{
daa6ba18 562 SCM_VALIDATE_LIST (2, lst);
79a3dafe 563 return scm_c_memq (x, lst);
0f2d19dd 564}
1bbd0b84 565#undef FUNC_NAME
0f2d19dd
JB
566
567
3b3b36dd 568SCM_DEFINE (scm_memv, "memv", 2, 0, 0,
1bbd0b84 569 (SCM x, SCM lst),
5352393c
MG
570 "Return the first sublist of @var{lst} whose car is @code{eqv?}\n"
571 "to @var{x} where the sublists of @var{lst} are the non-empty\n"
572 "lists returned by @code{(list-tail @var{lst} @var{k})} for\n"
573 "@var{k} less than the length of @var{lst}. If @var{x} does not\n"
574 "occur in @var{lst}, then @code{#f} (not the empty list) is\n"
575 "returned.")
1bbd0b84 576#define FUNC_NAME s_scm_memv
0f2d19dd 577{
daa6ba18 578 SCM_VALIDATE_LIST (2, lst);
c96d76b8 579 for (; !SCM_NULL_OR_NIL_P (lst); lst = SCM_CDR (lst))
daa6ba18
DH
580 {
581 if (! SCM_FALSEP (scm_eqv_p (SCM_CAR (lst), x)))
582 return lst;
583 }
584 return SCM_BOOL_F;
0f2d19dd 585}
1bbd0b84 586#undef FUNC_NAME
0f2d19dd
JB
587
588
3b3b36dd 589SCM_DEFINE (scm_member, "member", 2, 0, 0,
1bbd0b84 590 (SCM x, SCM lst),
5352393c
MG
591 "Return the first sublist of @var{lst} whose car is\n"
592 "@code{equal?} to @var{x} where the sublists of @var{lst} are\n"
593 "the non-empty lists returned by @code{(list-tail @var{lst}\n"
594 "@var{k})} for @var{k} less than the length of @var{lst}. If\n"
595 "@var{x} does not occur in @var{lst}, then @code{#f} (not the\n"
596 "empty list) is returned.")
1bbd0b84 597#define FUNC_NAME s_scm_member
0f2d19dd 598{
daa6ba18 599 SCM_VALIDATE_LIST (2, lst);
c96d76b8 600 for (; !SCM_NULL_OR_NIL_P (lst); lst = SCM_CDR (lst))
daa6ba18
DH
601 {
602 if (! SCM_FALSEP (scm_equal_p (SCM_CAR (lst), x)))
603 return lst;
604 }
605 return SCM_BOOL_F;
0f2d19dd 606}
1bbd0b84 607#undef FUNC_NAME
0f2d19dd 608
0f2d19dd 609\f
df13742c 610/* deleting elements from a list (delq, etc.) */
0f2d19dd 611
3b3b36dd 612SCM_DEFINE (scm_delq_x, "delq!", 2, 0, 0,
1bbd0b84 613 (SCM item, SCM lst),
8f85c0c6
NJ
614 "@deffnx {Scheme Procedure} delv! item lst\n"
615 "@deffnx {Scheme Procedure} delete! item lst\n"
b380b885 616 "These procedures are destructive versions of @code{delq}, @code{delv}\n"
bfefbf18 617 "and @code{delete}: they modify the existing @var{lst}\n"
b380b885
MD
618 "rather than creating a new list. Caveat evaluator: Like other\n"
619 "destructive list functions, these functions cannot modify the binding of\n"
620 "@var{lst}, and so cannot be used to delete the first element of\n"
621 "@var{lst} destructively.")
1bbd0b84 622#define FUNC_NAME s_scm_delq_x
0f2d19dd 623{
164271a1
JB
624 SCM walk;
625 SCM *prev;
0f2d19dd 626
164271a1 627 for (prev = &lst, walk = lst;
0c95b57d 628 SCM_CONSP (walk);
164271a1 629 walk = SCM_CDR (walk))
0f2d19dd 630 {
fbd485ba 631 if (SCM_EQ_P (SCM_CAR (walk), item))
164271a1
JB
632 *prev = SCM_CDR (walk);
633 else
634 prev = SCM_CDRLOC (walk);
0f2d19dd 635 }
164271a1
JB
636
637 return lst;
0f2d19dd 638}
1bbd0b84 639#undef FUNC_NAME
0f2d19dd
JB
640
641
3b3b36dd 642SCM_DEFINE (scm_delv_x, "delv!", 2, 0, 0,
5352393c
MG
643 (SCM item, SCM lst),
644 "Destructively remove all elements from @var{lst} that are\n"
645 "@code{eqv?} to @var{item}.")
1bbd0b84 646#define FUNC_NAME s_scm_delv_x
0f2d19dd 647{
164271a1
JB
648 SCM walk;
649 SCM *prev;
0f2d19dd 650
164271a1 651 for (prev = &lst, walk = lst;
0c95b57d 652 SCM_CONSP (walk);
164271a1 653 walk = SCM_CDR (walk))
0f2d19dd 654 {
fbd485ba 655 if (! SCM_FALSEP (scm_eqv_p (SCM_CAR (walk), item)))
164271a1
JB
656 *prev = SCM_CDR (walk);
657 else
658 prev = SCM_CDRLOC (walk);
0f2d19dd 659 }
164271a1
JB
660
661 return lst;
0f2d19dd 662}
1bbd0b84 663#undef FUNC_NAME
0f2d19dd
JB
664
665
666
3b3b36dd 667SCM_DEFINE (scm_delete_x, "delete!", 2, 0, 0,
5352393c
MG
668 (SCM item, SCM lst),
669 "Destructively remove all elements from @var{lst} that are\n"
670 "@code{equal?} to @var{item}.")
1bbd0b84 671#define FUNC_NAME s_scm_delete_x
0f2d19dd 672{
164271a1
JB
673 SCM walk;
674 SCM *prev;
0f2d19dd 675
164271a1 676 for (prev = &lst, walk = lst;
0c95b57d 677 SCM_CONSP (walk);
164271a1 678 walk = SCM_CDR (walk))
0f2d19dd 679 {
fbd485ba 680 if (! SCM_FALSEP (scm_equal_p (SCM_CAR (walk), item)))
164271a1
JB
681 *prev = SCM_CDR (walk);
682 else
683 prev = SCM_CDRLOC (walk);
0f2d19dd 684 }
164271a1
JB
685
686 return lst;
0f2d19dd 687}
1bbd0b84 688#undef FUNC_NAME
0f2d19dd
JB
689
690
691\f
692
0f2d19dd 693
a1ec6916 694SCM_DEFINE (scm_delq, "delq", 2, 0, 0,
1bbd0b84 695 (SCM item, SCM lst),
5352393c
MG
696 "Return a newly-created copy of @var{lst} with elements\n"
697 "@code{eq?} to @var{item} removed. This procedure mirrors\n"
698 "@code{memq}: @code{delq} compares elements of @var{lst} against\n"
699 "@var{item} with @code{eq?}.")
1bbd0b84 700#define FUNC_NAME s_scm_delq
0f2d19dd 701{
1bbd0b84 702 SCM copy = scm_list_copy (lst);
0f2d19dd
JB
703 return scm_delq_x (item, copy);
704}
1bbd0b84 705#undef FUNC_NAME
0f2d19dd 706
a1ec6916 707SCM_DEFINE (scm_delv, "delv", 2, 0, 0,
1bbd0b84 708 (SCM item, SCM lst),
5352393c
MG
709 "Return a newly-created copy of @var{lst} with elements\n"
710 "@code{eqv?} to @var{item} removed. This procedure mirrors\n"
711 "@code{memv}: @code{delv} compares elements of @var{lst} against\n"
712 "@var{item} with @code{eqv?}.")
1bbd0b84 713#define FUNC_NAME s_scm_delv
0f2d19dd 714{
1bbd0b84 715 SCM copy = scm_list_copy (lst);
0f2d19dd
JB
716 return scm_delv_x (item, copy);
717}
1bbd0b84 718#undef FUNC_NAME
0f2d19dd 719
a1ec6916 720SCM_DEFINE (scm_delete, "delete", 2, 0, 0,
1bbd0b84 721 (SCM item, SCM lst),
5352393c
MG
722 "Return a newly-created copy of @var{lst} with elements\n"
723 "@code{equal?} to @var{item} removed. This procedure mirrors\n"
724 "@code{member}: @code{delete} compares elements of @var{lst}\n"
725 "against @var{item} with @code{equal?}.")
1bbd0b84 726#define FUNC_NAME s_scm_delete
0f2d19dd 727{
1bbd0b84 728 SCM copy = scm_list_copy (lst);
0f2d19dd
JB
729 return scm_delete_x (item, copy);
730}
1bbd0b84 731#undef FUNC_NAME
0f2d19dd
JB
732
733
3b3b36dd 734SCM_DEFINE (scm_delq1_x, "delq1!", 2, 0, 0,
1bbd0b84 735 (SCM item, SCM lst),
5352393c
MG
736 "Like @code{delq!}, but only deletes the first occurrence of\n"
737 "@var{item} from @var{lst}. Tests for equality using\n"
738 "@code{eq?}. See also @code{delv1!} and @code{delete1!}.")
1bbd0b84 739#define FUNC_NAME s_scm_delq1_x
82dc9f57
MD
740{
741 SCM walk;
742 SCM *prev;
743
744 for (prev = &lst, walk = lst;
0c95b57d 745 SCM_CONSP (walk);
82dc9f57
MD
746 walk = SCM_CDR (walk))
747 {
fbd485ba 748 if (SCM_EQ_P (SCM_CAR (walk), item))
82dc9f57
MD
749 {
750 *prev = SCM_CDR (walk);
751 break;
752 }
753 else
754 prev = SCM_CDRLOC (walk);
755 }
756
757 return lst;
758}
1bbd0b84 759#undef FUNC_NAME
82dc9f57
MD
760
761
3b3b36dd 762SCM_DEFINE (scm_delv1_x, "delv1!", 2, 0, 0,
8507b88c 763 (SCM item, SCM lst),
5352393c
MG
764 "Like @code{delv!}, but only deletes the first occurrence of\n"
765 "@var{item} from @var{lst}. Tests for equality using\n"
766 "@code{eqv?}. See also @code{delq1!} and @code{delete1!}.")
1bbd0b84 767#define FUNC_NAME s_scm_delv1_x
82dc9f57
MD
768{
769 SCM walk;
770 SCM *prev;
771
772 for (prev = &lst, walk = lst;
0c95b57d 773 SCM_CONSP (walk);
82dc9f57
MD
774 walk = SCM_CDR (walk))
775 {
fbd485ba 776 if (! SCM_FALSEP (scm_eqv_p (SCM_CAR (walk), item)))
82dc9f57
MD
777 {
778 *prev = SCM_CDR (walk);
779 break;
780 }
781 else
782 prev = SCM_CDRLOC (walk);
783 }
784
785 return lst;
786}
1bbd0b84 787#undef FUNC_NAME
82dc9f57
MD
788
789
3b3b36dd 790SCM_DEFINE (scm_delete1_x, "delete1!", 2, 0, 0,
8507b88c 791 (SCM item, SCM lst),
5352393c
MG
792 "Like @code{delete!}, but only deletes the first occurrence of\n"
793 "@var{item} from @var{lst}. Tests for equality using\n"
794 "@code{equal?}. See also @code{delq1!} and @code{delv1!}.")
1bbd0b84 795#define FUNC_NAME s_scm_delete1_x
82dc9f57
MD
796{
797 SCM walk;
798 SCM *prev;
799
800 for (prev = &lst, walk = lst;
0c95b57d 801 SCM_CONSP (walk);
82dc9f57
MD
802 walk = SCM_CDR (walk))
803 {
fbd485ba 804 if (! SCM_FALSEP (scm_equal_p (SCM_CAR (walk), item)))
82dc9f57
MD
805 {
806 *prev = SCM_CDR (walk);
807 break;
808 }
809 else
810 prev = SCM_CDRLOC (walk);
811 }
812
813 return lst;
814}
1bbd0b84 815#undef FUNC_NAME
82dc9f57 816
c614a00b
MD
817SCM_DEFINE (scm_filter, "filter", 2, 0, 0,
818 (SCM pred, SCM list),
819 "Return all the elements of 2nd arg @var{list} that satisfy predicate @var{pred}.\n"
820 "The list is not disordered -- elements that appear in the result list occur\n"
821 "in the same order as they occur in the argument list. The returned list may\n"
822 "share a common tail with the argument list. The dynamic order in which the\n"
823 "various applications of pred are made is not specified.\n\n"
824 "@lisp\n"
825 "(filter even? '(0 7 8 8 43 -4)) => (0 8 8 -4)\n"
826 "@end lisp")
827#define FUNC_NAME s_scm_filter
828{
829 scm_t_trampoline_1 call = scm_trampoline_1 (pred);
830 SCM walk;
831 SCM *prev;
832 SCM res = SCM_EOL;
833 SCM_ASSERT (call, pred, 1, FUNC_NAME);
834 SCM_VALIDATE_LIST (2, list);
835
836 for (prev = &res, walk = list;
837 SCM_CONSP (walk);
838 walk = SCM_CDR (walk))
839 {
840 if (!SCM_FALSEP (call (pred, SCM_CAR (walk))))
841 {
842 *prev = scm_cons (SCM_CAR (walk), SCM_EOL);
843 prev = SCM_CDRLOC (*prev);
844 }
845 }
846
847 return res;
848}
849#undef FUNC_NAME
850
851SCM_DEFINE (scm_filter_x, "filter!", 2, 0, 0,
852 (SCM pred, SCM list),
853 "Linear-update variant of @code{filter}.")
854#define FUNC_NAME s_scm_filter_x
855{
856 scm_t_trampoline_1 call = scm_trampoline_1 (pred);
857 SCM walk;
858 SCM *prev;
859 SCM_ASSERT (call, pred, 1, FUNC_NAME);
860 SCM_VALIDATE_LIST (2, list);
861
862 for (prev = &list, walk = list;
863 SCM_CONSP (walk);
864 walk = SCM_CDR (walk))
865 {
866 if (!SCM_FALSEP (call (pred, SCM_CAR (walk))))
867 prev = SCM_CDRLOC (walk);
868 else
869 *prev = SCM_CDR (walk);
870 }
871
872 return list;
873}
874#undef FUNC_NAME
82dc9f57 875
0f2d19dd 876\f
0f2d19dd
JB
877void
878scm_init_list ()
0f2d19dd 879{
a0599745 880#include "libguile/list.x"
0f2d19dd 881}
89e00824
ML
882
883/*
884 Local Variables:
885 c-file-style: "gnu"
886 End:
887*/