summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eval.c1
-rw-r--r--lib.c22
-rw-r--r--lib.h1
-rw-r--r--stdlib/doc-syms.tl1
-rw-r--r--tests/010/cons.tl14
-rw-r--r--txr.171
6 files changed, 110 insertions, 0 deletions
diff --git a/eval.c b/eval.c
index 8a9fada6..006861b1 100644
--- a/eval.c
+++ b/eval.c
@@ -6916,6 +6916,7 @@ void eval_init(void)
reg_fun(intern(lit("split*"), user_package), func_n2(split_star));
reg_fun(intern(lit("partition*"), user_package), func_n2(partition_star));
reg_fun(intern(lit("tailp"), user_package), func_n2(tailp));
+ reg_fun(intern(lit("delcons"), user_package), func_n2(delcons));
reg_fun(memq_s, func_n2(memq));
reg_fun(memql_s, func_n2(memql));
reg_fun(memqual_s, func_n2(memqual));
diff --git a/lib.c b/lib.c
index 796853ec..68a12ae6 100644
--- a/lib.c
+++ b/lib.c
@@ -2796,6 +2796,28 @@ val tailp(val obj, val list)
return t;
}
+val delcons(val cons, val list)
+{
+ val iter = list;
+
+ if (!consp(cons))
+ return list;
+
+ if (cons == iter)
+ return cdr(iter);
+
+ while (consp(iter)) {
+ val d = us_cdr(iter);
+ if (cons == d) {
+ us_rplacd(iter, us_cdr(cons));
+ break;
+ }
+ iter = d;
+ }
+
+ return list;
+}
+
val memq(val obj, val list)
{
val list_orig = list;
diff --git a/lib.h b/lib.h
index 76ad19b2..be62cf21 100644
--- a/lib.h
+++ b/lib.h
@@ -677,6 +677,7 @@ val split(val seq, val indices);
val partition_star(val seq, val indices);
val split_star(val seq, val indices);
val tailp(val obj, val list);
+val delcons(val cons, val list);
val memq(val obj, val list);
val rmemq(val obj, val list);
val memql(val obj, val list);
diff --git a/stdlib/doc-syms.tl b/stdlib/doc-syms.tl
index 0bb8b82b..a14a83d6 100644
--- a/stdlib/doc-syms.tl
+++ b/stdlib/doc-syms.tl
@@ -482,6 +482,7 @@
("del" "D-0022")
("del*" "N-0166445C")
("delay" "N-00DCE524")
+ ("delcons" "N-03A1ABA8")
("delete-package" "N-02E687F3")
("derived" "N-0151798B")
("dev-t" "N-01D716FE")
diff --git a/tests/010/cons.tl b/tests/010/cons.tl
new file mode 100644
index 00000000..de293652
--- /dev/null
+++ b/tests/010/cons.tl
@@ -0,0 +1,14 @@
+(load "../common")
+
+(let ((x (list* 1 2 3 4)))
+ (mtest
+ (set x (delcons x x)) (2 3 . 4)
+ (set x (delcons x x)) (3 . 4)
+ (set x (delcons x x)) 4
+ (set x (delcons x x)) 4))
+
+(let ((x (list* 1 2 3 4 5)))
+ (mtest
+ (delcons (cdr x) x) (1 3 4 . 5)
+ (delcons (cddr x) x) (1 3 . 5)
+ (delcons (cdr x) x) (1 . 5)))
diff --git a/txr.1 b/txr.1
index bc9f01ff..e2bb0fdc 100644
--- a/txr.1
+++ b/txr.1
@@ -22277,6 +22277,77 @@ can be expressed as:
(conses list1) ... (conses listn))
.brev
+.coNP Function @ delcons
+.synb
+.mets (delcons < cons << list )
+.syne
+.desc
+The
+.code delcons
+function destructively removes a cons cell from a list. The
+.meta list
+is searched to see whether one of its cons cells is the same object as
+.metn cons .
+If so, that cell is removed from the list.
+
+The
+.meta list
+argument may be a proper or improper list, possibly empty. It may also be an
+atom other than
+.codn nil ,
+which is regarded as being, effectively, am empty improper list terminated by
+that atom.
+
+The operation of
+.code delcons
+is divided into the following three cases. If
+.meta cons
+is the first cons cell of
+.metn list ,
+then the
+.code cdr
+of
+.meta list
+is returned. If
+.meta cons
+is the second or subsequent cons of
+.metn list ,
+then
+.meta list
+is destructively altered to remove
+.meta cons
+and then returned. This means that the
+.code cdr
+field of the predecessor of
+.meta cons
+is altered from referencing
+.meta cons
+to referencing
+.mono
+.meti (cdr << cons )
+.onom
+instead.
+The returned value is the same cons cell as
+.metn list .
+The third case occurs when
+.meta cons
+is not found in
+.metn list .
+In this situation,
+.meta list
+is returned unchanged.
+
+.TP* Examples:
+.verb
+ (let ((x (list 1 2 3)))
+ (delcons x x))
+ -> (2 3)
+
+ (let ((x (list 1 2 . 3)))
+ (delcons (cdr x) x))
+ -> (1 . 3)
+.brev
+
.SS* Association Lists
Association lists are ordinary lists formed according to a special convention.