summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2019-03-13 06:48:23 -0700
committerKaz Kylheku <kaz@kylheku.com>2019-03-13 06:48:23 -0700
commit7aef72ae4fd0fcbe18acbbd876fed0aaf6bf87ee (patch)
tree33c45ac37bd683030e0c58601a021203b398b52b
parent3388b5baed9b9288ccd4fcd7611f936cb6025469 (diff)
downloadtxr-7aef72ae4fd0fcbe18acbbd876fed0aaf6bf87ee.tar.gz
txr-7aef72ae4fd0fcbe18acbbd876fed0aaf6bf87ee.tar.bz2
txr-7aef72ae4fd0fcbe18acbbd876fed0aaf6bf87ee.zip
lazy conses: support state in car and cdr.
Here we allow application code to take advantage of a trick already used internally. When a lazy cons cell is created, we can temporarily put state information into its car and cdr fields. When these fields are accessed normally, by the car and cdr function, the lazy cons' update function will be invoked, which will populate these fields. If we have a way for that function to retrieve the existing values of those fields, then the function can treat those fields as state information: it can retrieve the values into temporary local variables, overwrite the original values, and then propagate the state information into the car and cdr into the next lazy cons cell being added. Thus lazy list generation that needs two cells of state or less does not require the allocation of a context object. * eval.c (eval_init): make-lazy-cons becomes a three-argument function with two optional parameters. New functions lcons-car and lcons-cdr are registered. * lib.c (make_lazy_cons_pub): New function, wrapping make_lazy_cons_car_cdr with argument defaulting. (lcons_car, lcons_cdr): New functions. * lib.h (make_lazy_cons_pu, lcons_car, lcons_cdr): Declared. * txr.1: Updated doc of make-lazy-cons regarding new arguments. Documented lcons-car and lcons-cdr.
-rw-r--r--eval.c5
-rw-r--r--lib.c17
-rw-r--r--lib.h3
-rw-r--r--txr.162
4 files changed, 81 insertions, 6 deletions
diff --git a/eval.c b/eval.c
index 89e3d18c..a5f823a7 100644
--- a/eval.c
+++ b/eval.c
@@ -6343,8 +6343,11 @@ void eval_init(void)
reg_mac(intern(lit("load-for"), user_package), func_n2(me_load_for));
reg_fun(cons_s, func_n2(cons));
- reg_fun(intern(lit("make-lazy-cons"), user_package), func_n1(make_lazy_cons));
+ reg_fun(intern(lit("make-lazy-cons"), user_package),
+ func_n3o(make_lazy_cons_pub, 1));
reg_fun(intern(lit("lcons-fun"), user_package), func_n1(lcons_fun));
+ reg_fun(intern(lit("lcons-car"), user_package), func_n1(lcons_car));
+ reg_fun(intern(lit("lcons-cdr"), user_package), func_n1(lcons_cdr));
reg_fun(car_s, car_f);
reg_fun(cdr_s, cdr_f);
reg_fun(rplaca_s, func_n2(rplaca));
diff --git a/lib.c b/lib.c
index 1ca81fc8..06cd37c1 100644
--- a/lib.c
+++ b/lib.c
@@ -3022,6 +3022,23 @@ val make_lazy_cons_car_cdr(val func, val car, val cdr)
return obj;
}
+val make_lazy_cons_pub(val func, val car, val cdr)
+{
+ return make_lazy_cons_car_cdr(func, default_null_arg(car), default_null_arg(cdr));
+}
+
+val lcons_car(val lcons)
+{
+ type_check(lit("lcons-car"), lcons, LCONS);
+ return lcons->lc.car;
+}
+
+val lcons_cdr(val lcons)
+{
+ type_check(lit("lcons-cdr"), lcons, LCONS);
+ return lcons->lc.cdr;
+}
+
void rcyc_cons(val cons)
{
cons->c.cdr = recycled_conses;
diff --git a/lib.h b/lib.h
index 1bbbfe35..6b8c0b0a 100644
--- a/lib.h
+++ b/lib.h
@@ -665,6 +665,9 @@ val cons(val car, val cdr);
val make_lazy_cons(val func);
val make_lazy_cons_car(val func, val car);
val make_lazy_cons_car_cdr(val func, val car, val cdr);
+val make_lazy_cons_pub(val func, val car, val cdr);
+val lcons_car(val lcons);
+val lcons_cdr(val lcons);
void rcyc_cons(val cons);
void rcyc_list(val list);
void rcyc_empty(void);
diff --git a/txr.1 b/txr.1
index fffd41b2..f8da8350 100644
--- a/txr.1
+++ b/txr.1
@@ -20137,7 +20137,7 @@ functions than less functions, the excess key functions are ignored.
.SS* Lazy Lists and Lazy Evaluation
.coNP Function @ make-lazy-cons
.synb
-.mets (make-lazy-cons << function )
+.mets (make-lazy-cons < function >> [ car <> [ cdr ]])
.syne
.desc
The function
@@ -20155,9 +20155,15 @@ A lazy cons has
and
.code cdr
fields like a regular cons, and those
-fields are initialized to
-.code nil
-when the lazy cons is created. A lazy cons also
+fields are initialized to the values of the
+.meta car
+and
+.meta cdr
+arguments of
+.code make-lazy-cons
+when the lazy cons is created. These arguments default to
+.meta nil
+if omitted. A lazy cons also
has an update function, which is specified by the
.meta function
argument to
@@ -20182,13 +20188,20 @@ and
.code cdr
fields. Once the function is called, it is removed
from the lazy cons: the lazy cons no longer has an update function.
-If the function attempts to retrieve the value of the
+If the update function itself attempts to retrieve the value of the
lazy cons cell's
.code car
or
.code cdr
field, it will be recursively invoked.
+The functions
+.code lcons-car
+and
+.code lcons-cdr
+may be used to access the fields of a lazy cons without
+triggering the update function.
+
Storing a value into either the
.code car
or
@@ -20271,6 +20284,45 @@ to retrieve a reference to itself and propagate itself into
another lazy cons (as in the example under
.codn make-lazy-cons ).
+.coNP Functions @ lcons-car and @ lcons-cdr
+.synb
+.mets (lcons-car << lazy-cons )
+.mets (lcons-cdr << lazy-cons )
+.syne
+.desc
+The functions
+.code lcons-car
+and
+.code lcons-cdr
+retrieve the
+.code car
+and
+.code cdr
+fields of
+.metn lazy-cons ,
+without triggering the invocation of its associated update function.
+
+The
+.meta lazy-cons
+argument must be an object of type
+.codn lcons .
+Unlike the functions
+.code car
+and
+.codn cdr ,
+These functions cannot be applied to any other type of object.
+
+Note: these functions may be used by the update function to retrieve
+the values which were stored into
+.meta lazy-cons
+by the
+.code make-lazy-cons
+constructor, without triggering recursion. The function may then
+overwrite either or both of these values. This allows the fields of the lazy
+cons to store state information necessary for the propagation of a lazy list.
+If that state information consists of no more than two values, then
+no additional context object need be allocated.
+
.coNP Macro @ lcons
.synb
.mets (lcons < car-expression << cdr-expression )