summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2011-12-15 15:46:49 -0800
committerKaz Kylheku <kaz@kylheku.com>2011-12-15 15:46:49 -0800
commit13c9609500c02a10fbea9cd833615a4ceee7dd43 (patch)
treeb90cef4353a2a3855d98c8e2e2f6bb4272604f34
parente3390f1ed75d58f78218acf22c2a9209a88a14a2 (diff)
downloadtxr-13c9609500c02a10fbea9cd833615a4ceee7dd43.tar.gz
txr-13c9609500c02a10fbea9cd833615a4ceee7dd43.tar.bz2
txr-13c9609500c02a10fbea9cd833615a4ceee7dd43.zip
* eval.c (eval_init): not added as synonym for null.
* lib.c (copy_list): Use list_collect_append rather than list_collect_terminate. (append2, appendv): Simplified using new list_collect_append. (nappend2): Simplified using new list_collect_nconc. * lib.h (list_collect): Added check for accidental usage of list_collect after list_append, since PTAIL has different semantics. (list_collect_nconc, list_collect_append): Semantics fixed so that append collecting works more like the Common Lisp append function, allowing trailing atoms or a lone atom. The meaning of PTAIL is changed, however. Now PTAIL actually tracks the head of the most recently appended segment. Each append operation has to first traverse the previously added piece to get to the end. (list_collect_terminate): Macro removed. * match.c (v_gather): Removed useless use of list_collect_terminate. * parser.y: Some headers added that are needed by list_collect. * txr.1: Documented append, list, atom, null, not, consp, make-lazy-cons, lcons-fun, listp, proper-listp, length-list, mapcar, mappend, and apply.
-rw-r--r--ChangeLog28
-rw-r--r--eval.c1
-rw-r--r--lib.c38
-rw-r--r--lib.h22
-rw-r--r--match.c1
-rw-r--r--parser.y2
-rw-r--r--txr.1316
7 files changed, 368 insertions, 40 deletions
diff --git a/ChangeLog b/ChangeLog
index 226f38f9..18f9e17c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+2011-12-15 Kaz Kylheku <kaz@kylheku.com>
+
+ * eval.c (eval_init): not added as synonym for null.
+
+ * lib.c (copy_list): Use list_collect_append rather than
+ list_collect_terminate.
+ (append2, appendv): Simplified using new list_collect_append.
+ (nappend2): Simplified using new list_collect_nconc.
+
+ * lib.h (list_collect): Added check for accidental usage
+ of list_collect after list_append, since PTAIL has different
+ semantics.
+ (list_collect_nconc, list_collect_append): Semantics fixed so that
+ append collecting works more like the Common Lisp append function,
+ allowing trailing atoms or a lone atom. The meaning of PTAIL is
+ changed, however. Now PTAIL actually tracks the head of the most
+ recently appended segment. Each append operation has to first
+ traverse the previously added piece to get to the end.
+
+ (list_collect_terminate): Macro removed.
+
+ * match.c (v_gather): Removed useless use of list_collect_terminate.
+
+ * parser.y: Some headers added that are needed by list_collect.
+
+ * txr.1: Documented append, list, atom, null, not, consp, make-lazy-cons,
+ lcons-fun, listp, proper-listp, length-list, mapcar, mappend, and apply.
+
2011-12-14 Kaz Kylheku <kaz@kylheku.com>
@# comments are becoming obsolescent. @# comments
diff --git a/eval.c b/eval.c
index d8755fa4..e78f4051 100644
--- a/eval.c
+++ b/eval.c
@@ -1128,6 +1128,7 @@ void eval_init(void)
reg_fun(intern(lit("atom"), user_package), func_n1(atom));
reg_fun(intern(lit("null"), user_package), func_n1(nullp));
+ reg_fun(intern(lit("not"), user_package), func_n1(nullp));
reg_fun(intern(lit("consp"), user_package), func_n1(consp));
reg_fun(intern(lit("listp"), user_package), func_n1(listp));
reg_fun(intern(lit("proper-listp"), user_package), func_n1(proper_listp));
diff --git a/lib.c b/lib.c
index 8e1652e7..9c3f1e34 100644
--- a/lib.c
+++ b/lib.c
@@ -319,14 +319,14 @@ val push(val value, val *plist)
val copy_list(val list)
{
- list_collect_decl (out, tail);
+ list_collect_decl (out, ptail);
while (consp(list)) {
- list_collect(tail, car(list));
+ list_collect(ptail, car(list));
list = cdr(list);
}
- list_collect_terminate(tail, list);
+ list_collect_append(ptail, list);
return out;
}
@@ -359,14 +359,11 @@ val reverse(val in)
val append2(val list1, val list2)
{
- list_collect_decl (out, tail);
+ list_collect_decl (out, ptail);
- while (list1) {
- list_collect(tail, car(list1));
- list1 = cdr(list1);
- }
+ list_collect_append (ptail, list1);
+ list_collect_append (ptail, list2);
- list_collect_terminate(tail, list2);
return out;
}
@@ -376,14 +373,9 @@ val appendv(val lists)
for (; lists; lists = cdr(lists)) {
val item = car(lists);
- if (consp(item)) {
- list_collect_append(ptail, car(lists));
- } else {
- if (cdr(lists))
- uw_throwf(error_s, lit("append: ~s is not a list"), item, nao);
- list_collect_terminate(ptail, item);
- return out;
- }
+ if (listp(*ptail))
+ uw_throwf(error_s, lit("append: ~s is not a list"), *ptail, nao);
+ list_collect_append(ptail, item);
}
return out;
@@ -391,16 +383,12 @@ val appendv(val lists)
val nappend2(val list1, val list2)
{
- val temp, iter;
-
- if (list1 == nil)
- return list2;
+ list_collect_decl (out, ptail);
- for (iter = list1; (temp = cdr(iter)) != nil; iter = temp)
- ; /* empty */
+ list_collect_nconc (ptail, list1);
+ list_collect_nconc (ptail, list2);
- *cdr_l(iter) = list2;
- return list1;
+ return out;
}
val ldiff(val list1, val list2)
diff --git a/lib.h b/lib.h
index 30fd35c1..345c3e35 100644
--- a/lib.h
+++ b/lib.h
@@ -570,29 +570,29 @@ INLINE val eq(val a, val b) { return ((a) == (b) ? t : nil); }
#define list_collect(PTAIL, OBJ) \
do { \
+ if (*PTAIL) \
+ internal_error("mixed collect style"); \
*PTAIL = cons(OBJ, nil); \
PTAIL = cdr_l(*PTAIL); \
} while(0)
#define list_collect_nconc(PTAIL, OBJ) \
do { \
- obj_t *o_b_j = (OBJ); \
- *PTAIL = o_b_j; \
- if (o_b_j) \
- PTAIL = tail(o_b_j); \
+ if (*PTAIL) { \
+ PTAIL = tail(*PTAIL); \
+ } \
+ *PTAIL = OBJ; \
} while (0)
#define list_collect_append(PTAIL, OBJ) \
do { \
- obj_t *o_b_j = copy_list(OBJ); \
- *PTAIL = o_b_j; \
- if (o_b_j) \
- PTAIL = tail(o_b_j); \
+ if (*PTAIL) { \
+ *PTAIL = copy_list(*PTAIL); \
+ PTAIL = tail(*PTAIL); \
+ } \
+ *PTAIL = OBJ; \
} while (0)
-#define list_collect_terminate(PTAIL, OBJ) \
- do *PTAIL = (OBJ); while(0)
-
#define cons_bind(CAR, CDR, CONS) \
obj_t *c_o_n_s ## CAR ## CDR = CONS; \
obj_t *CAR = car(c_o_n_s ## CAR ## CDR); \
diff --git a/match.c b/match.c
index fdd7666a..e8cdf22a 100644
--- a/match.c
+++ b/match.c
@@ -2221,7 +2221,6 @@ static val v_gather(match_files_ctx *c)
}
}
- list_collect_terminate (ptail, nil);
specs = new_specs;
if (consp(max_data)) {
diff --git a/parser.y b/parser.y
index cc6a6dbd..08fe1c96 100644
--- a/parser.y
+++ b/parser.y
@@ -31,9 +31,11 @@
#include <limits.h>
#include <dirent.h>
#include <stdlib.h>
+#include <setjmp.h>
#include <wchar.h>
#include "config.h"
#include "lib.h"
+#include "unwind.h"
#include "regex.h"
#include "utf8.h"
#include "match.h"
diff --git a/txr.1 b/txr.1
index 80dc14dd..58805f3e 100644
--- a/txr.1
+++ b/txr.1
@@ -5138,26 +5138,336 @@ Examples:
.SS Function append
+.TP
+Syntax:
+
+(append [<list>* <cdr>])
+
+.TP
+Description:
+
+The append function creates a new list which is a catenation of the
+list arguments. All arguments are optional, such that (append) produces
+the empty list.
+
+If a single argument is specified, then append simply returns the value of that
+argument. It may be any kind of object.
+
+If N arguments are specified, where N > 1, then the first N-1 arguments must be
+proper lists. Copies of these lists are catenated together. The last argument,
+argument N, may be any kind of object. It is installed into the cdr field of
+the last cons cell of the resulting list. Thus, if argument N is also a list, it
+is catenated onto the resulting list, but without being copied. Argument N may
+be an atom other than nil; in that case append produces an improper list.
+
+.TP
+Examples:
+
+;; An atom is returned.
+(append 3) -> 3
+
+;; A list is also just returned: no copying takes place.
+;; The eq function can verify that the same object emerges
+;; from append that went in.
+(let ((list '(1 2 3)))
+ (eq (append list) list)) -> t
+
+(append '(1 2 3) '(4 5 6) 7) -> '(1 2 3 4 5 6 . 7))
+
+;; the (4 5 6) tail of the resulting list is the original
+;; (4 5 6) object, shared with that list.
+
+(append '(1 2 3) '(4 5 6)) -> '(1 2 3 4 5 6)
+
+(append nil) -> nil
+
+;; (1 2 3) is copied: it is not the last argument
+(append '(1 2 3) nil) -> (1 2 3)
+
+;; empty lists disappear
+(append nil '(1 2 3) nil '(4 5 6)) -> (1 2 3 4 5 6)
+(append nil nil nil) -> nil
+
+;; atoms and improper lists other than in the last position
+;; are erroneous
+(append '(a . b) 3 '(1 2 3)) -> **error**
+
.SS Function list
+.TP
+Syntax:
+
+(list <value>*)
+
+.TP
+Description:
+
+The list function creates a new list, whose elements are the
+argument values.
+
+.TP
+Examples:
+
+(list) -> nil
+(list 1) -> (1)
+(list 'a 'b) -> (a b)
+
.SS Function atom
+.TP
+Syntax:
+(atom <value>)
+
+.TP
+Description:
+
+The atom function tests whether a value is an atom. It returns t if this is the
+case, nil otherwise. All values which are not cons cells are atoms.
+
+(atom x) is equivalent to (not (consp x)).
+
+.TP
+Examples:
+
+(atom 3) -> t
+(atom (cons 1 2)) -> nil
+(atom "abc") -> t
+(atom '(3)) -> nil
+
+.SS Functions null and not
+
+.TP
+Syntax:
+(null <value>)
+(not <value>)
+
+.TP
+Description:
+
+The null and not functions are synonyms. They tests whether a value is the
+object nil. They returns t if this is the case, nil otherwise.
+
+.TP
+Examples:
+
+(null '()) -> t
+(null nil) -> t
+(null ()) -> t
+
+(if (null x) (format t "x is nil!"))
+
+(let ((list '(b c d)))
+ (if (not (memq 'a list))
+ (format t "list ~s does not contain the symbol a\en")))
+
.SS Function consp
+.TP
+Syntax:
+(consp <value>)
+
+.TP
+Description:
+
+The atom function tests whether a value is a cons. It returns t if this is the
+case, nil otherwise.
+
+(consp x) is equivalent to (not (atom x)).
+
+Non-empty lists test positive under consp because a list is represented
+as a reference to the first cons in a chain of one or more conses.
+
+.TP
+Examples:
+
+(consp 3) -> nil
+(consp (cons 1 2)) -> t
+(consp "abc") -> nil
+(consp '(3)) -> t
+
+
.SS Function make_lazy_cons
-.SS Function lcons_fun
+.TP
+Syntax:
+
+(make-lazy-cons <function>)
+
+.TP
+Description:
+
+The function make-lazy-cons makes a special kind of cons cell called a lazy
+cons, or lcons. Lazy conses are useful for implementing lazy lists.
+
+Lazy lists are lists which are not allocated all at once. Rather,
+their elements materialize when they are accessed, like
+magic stepping stones appearing under one's feet out of thin air.
+
+A lazy cons has "car" and "cdr" fields like a regular cons, and those
+fields are initialized to nil when the lazy cons is created. A lazy cons also
+has an update function, the one which is provided as an argument to
+make-lazy-cons.
+
+When either the car and cdr fields of a cons are accessed for the first time,
+the function is automatically invoked first. That function has the opportunity
+to initialize the car and cdr fields. Once the function is called, it is removed
+from the lazy cons: the lazy cons no longer has an update function.
+
+To continue a lazy list, the function can make another call to make-lazy-cons
+and install the resulting cons as the cdr of the lazy cons.
+
+.TP
+Example:
+
+;;; lazy list of integers between min and max
+(defun integer-range (min max)
+ (let ((counter min))
+ ;; min is greater than max; just return empty list,
+ ;; otherwise return a lazy list
+ (if (> min max)
+ nil
+ (make-lazy-cons (lambda (lcons)
+ ;; install next number into car
+ (rplaca lcons counter)
+ ;; now deal wit cdr field
+ (cond
+ ;; max reached, terminate list with nil!
+ ((eql counter max)
+ (rplacd lcons nil))
+ ;; max not reached: increment counter
+ ;; and extend with another lazy cons
+ (t
+ (inc counter)
+ (rplacd lcons (make-lazy-cons
+ (lcons-fun lcons))))))))))
+
+.SS Function lcons-fun
+
+.TP
+Syntax:
+
+(lcons-fun <lazy-cons>)
+
+.TP
+Description:
+
+The lcons-fun function retrieves the update function of a lazy cons.
+Once a lazy cons has been accessed, it no longer has an update function
+and lcons-fun returns nil. While the update function of a lazy cons is
+executing, it is still accessible. This allows the update function
+to retrieve a reference to itself and propagate itself into
+another lazy cons (as in the example under make-lazy-cons).
.SS Functions listp and proper-listp
+.TP
+Syntax:
+
+(listp <value>)
+(proper-listp <value>)
+
+.TP
+Description:
+
+The listp and proper-listp functions test, respectively, whether
+the specified value is a list, or a proper list, and return
+t or nil accordingly.
+
+The listp test is weaker, and executes without having to traverse
+the object. (listp x) is equivalent to (or (null x) (consp x)).
+The empty list is a list, and a cons cell is a list.
+
+The proper-listp function returns t only for proper lists. A proper list is
+either nil, or a cons whose cdr is a proper list. proper-listp traverses the
+list, and its execution will not terminate if the list is circular.
+
.SS Function length-list
-.SS Function mapcar
+.TP
+Syntax:
+
+(length-list <list>)
+
+.TP
+The length-list function returns the length of a proper or improper
+list. The length of a list is the number of conses in that list.
+
+.SS Functions mapcar and mappend
+
+.TP
+Syntax:
+
+(mapcar <function> <list> <list>*)
+(mappend <function> <list> <list>*)
+
+.TP
+When given three arguments, the mapcar function processes applies a function to
+the elements of a list and returns a list of the resulting values.
+Essentially, the list is filtered through the function.
+
+When additional lists are given as arguments, this filtering behavior is
+generalized in the following way: mapcar traverses the lists in parallel,
+taking a value from each list as an argument to the function. If there
+are two lists, the function is called with two arguments and so forth.
+The process is limited by the length of the shortest list.
+The return values of the function are collected into a new list which is
+returned.
+
+The mappend function works like mapcar, with the following difference.
+Rather than accumulating the values returned by the function into a list,
+mappend expects the items returned by the function to be lists which
+are catenated with append, and the resulting list is returned.
+That is to say, (mappend f a b c) is equivalent to
+(apply (fun append) (mapcar f a b c)).
+
+
+.TP
+Examples:
+
+;; multiply every element by two
+(mapcar (lambda (item) (* 2 item)) '(1 2 3)) -> (4 6 8)
+
+;; "zipper" two lists together
+(mapcar (lambda (le ri) (list le ri)) '(1 2 3) '(a b c)) '((1 a) (2 b) (3 c)))
+
+;; like append, mappend allows a lone atom or a trailing atom:
+(mappend (fun identity) 3) -> (3)
+(mappend (fun identity) '((1) 2)) -> (1 . 2)
+
+;; take just the even numbers
+(mappend (lambda (item) (if (evenp x) (list x))) '(1 2 3 4 5))
+-> (2 4)
-.SS Function mappend
.SS Function apply
+.TP
+Syntax:
+
+(apply <function> <arglist>)
+
+.TP
+Description:
+
+The apply function treats a list of values as individual arguments that
+are passed to the specified function, which is called, and its return
+value becomes the return value of apply.
+
+.TP
+Examples:
+
+;; '(1 2 3) becomes arguments to list, thus (list 1 2 3).
+(apply (fun list) '(1 2 3)) -> (1 2 3)
+
+.TP
+Dialect note:
+
+TXR Lisp apply does not take additional arguments before the list.
+In Common Lisp we can write (apply #'list 1 2 (list 3 4 5)) which
+yields (1 2 3 4 5). In TXR Lisp, this usage can be simulated using
+(apply (fun list) (list 1 2 (list 3 4 5))) or
+(apply (fun list) '(,1 ,2 ,*(list 3 4 5))) .
+
.SS Functions reduce-left and reduce-right
.SS Function copy-list