diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2019-03-13 06:48:23 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2019-03-13 06:48:23 -0700 |
commit | 7aef72ae4fd0fcbe18acbbd876fed0aaf6bf87ee (patch) | |
tree | 33c45ac37bd683030e0c58601a021203b398b52b | |
parent | 3388b5baed9b9288ccd4fcd7611f936cb6025469 (diff) | |
download | txr-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.c | 5 | ||||
-rw-r--r-- | lib.c | 17 | ||||
-rw-r--r-- | lib.h | 3 | ||||
-rw-r--r-- | txr.1 | 62 |
4 files changed, 81 insertions, 6 deletions
@@ -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)); @@ -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; @@ -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); @@ -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 ) |