From dd108fe76bf8c124ec7d68ed0a346c54c01ad182 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Tue, 21 Jan 2014 06:18:34 -0800 Subject: * lib.c (car, cdr, ldiff): Extend to handle vectors and strings. Thereby, numerous previously list-only operations in TXR Lisp now magically handle strings and vectors. * txr.1: Documented. --- ChangeLog | 8 ++++++++ lib.c | 36 +++++++++++++++++++++++++++++++++--- txr.1 | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index be0057a5..c2547c5e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2014-01-21 Kaz Kylheku + + * lib.c (car, cdr, ldiff): Extend to handle vectors and strings. + Thereby, numerous previously list-only operations in TXR Lisp + now magically handle strings and vectors. + + * txr.1: Documented. + 2014-01-20 Kaz Kylheku * lib.c (broken_down_time_list): New static function. diff --git a/lib.c b/lib.c index cbc50869..6e162c22 100644 --- a/lib.c +++ b/lib.c @@ -203,6 +203,16 @@ val car(val cons) cons->lc.func = nil; return cons->lc.car; } + case VEC: + if (zerop(cons->v.vec[vec_length])) + return nil; + return cons->v.vec[0]; + case STR: + case LIT: + case LSTR: + if (zerop(length_str(cons))) + return nil; + return chr_str(cons, zero); default: type_mismatch(lit("~s is not a cons"), cons, nao); } @@ -223,6 +233,13 @@ val cdr(val cons) cons->lc.func = nil; return cons->lc.cdr; } + case VEC: + case STR: + case LIT: + case LSTR: + if (le(length(cons), one)) + return nil; + return sub(cons, one, t); default: type_mismatch(lit("~s is not a cons"), cons, nao); } @@ -611,9 +628,22 @@ val ldiff(val list1, val list2) { list_collect_decl (out, ptail); - while (list1 && list1 != list2) { - list_collect (ptail, car(list1)); - list1 = cdr(list1); + switch (type(list2)) { + case STR: + case LIT: + case LSTR: + case VEC: + while (list1 && !equal(list1, list2)) { + list_collect (ptail, car(list1)); + list1 = cdr(list1); + } + break; + default: + while (list1 && list1 != list2) { + list_collect (ptail, car(list1)); + list1 = cdr(list1); + } + break; } return out; diff --git a/txr.1 b/txr.1 index 22c6615a..2e499bef 100644 --- a/txr.1 +++ b/txr.1 @@ -5003,6 +5003,40 @@ In TXR Lisp, the / character can occur in symbol names, and the / token is a symbol. Therefore the /regex/ syntax is absent, replaced with the #/regex/ syntax. +.SS Generalization of List Accessors car and cdr + +In ancient Lisp in the 1960's, it was not possible to apply the operations +car and cdr to the nil symbol (empty list), because it is not a cons cell. In +the InterLisp dialect, this restriction was lifted: these operations were +extended to accept nil (and return nil). The convention was adopted in +other Lisp dialects and in Common Lisp. Thus there exists an object which +is not a cons, yet which takes car and cdr. + +In TXR Lisp, this concept is extended further. For the sake of convenience, +the operations car and cdr, are extended to work with strings and vectors: + + (cdr "") -> nil + (car "") -> nil + + (car "abc") -> #\ea + (cdr "abc") -> "bc" + + (cdr #(1 2 3)) -> #(2 3) + (car #(1 2 3)) -> 1 + +The ldiff function is also extended in a special way. When the right parameter +is a string or vector, then it uses the equal equality test rather than eq +for detecting the tail of the list. + + (ldiff "abcd" "cd") -> (#\ea #\eb) + +The ldiff operation starts with "abcd" and repeatedly applies cdr to produce +"bcd" and "cd", until the suffix is equal to the second argument: (equal "cd" +"cd") yields true. + +Operations based on car, cdr and ldiff, such as keep-if and remq extend to +strings and vectors. + .SH CONTROL FLOW AND SEQUENCING When the first element of a compound expression is an operator symbol, -- cgit v1.2.3