diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2014-07-27 09:49:51 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2014-07-27 09:49:51 -0700 |
commit | a78684b08ea0669262156c78e9b8eb4bc68e8139 (patch) | |
tree | af3eeb53554fcc466f63525494e977b7a5bd8b91 | |
parent | 6afe9ab25e2cda942d8e67513081fbe25c217601 (diff) | |
download | txr-a78684b08ea0669262156c78e9b8eb4bc68e8139.tar.gz txr-a78684b08ea0669262156c78e9b8eb4bc68e8139.tar.bz2 txr-a78684b08ea0669262156c78e9b8eb4bc68e8139.zip |
* eval.c (giterate_func, giterate): New static functions.
(eval_init): Registered giterate as intrinsic.
* txr.1: Documented giterate.
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | eval.c | 31 | ||||
-rw-r--r-- | txr.1 | 26 |
3 files changed, 62 insertions, 2 deletions
@@ -1,3 +1,10 @@ +2014-07-27 Kaz Kylheku <kaz@kylheku.com> + + * eval.c (giterate_func, giterate): New static functions. + (eval_init): Registered giterate as intrinsic. + + * txr.1: Documented giterate. + 2014-07-26 Kaz Kylheku <kaz@kylheku.com> * unwind.h (uw_block_begin): Get rid of the unused typedef trick, @@ -3157,6 +3157,36 @@ val generate(val while_pred, val gen_fun) } } +static val giterate_func(val env, val lcons) +{ + cons_bind (while_pred, gen_fun, env); + val value = lcons->lc.car; + + if (!funcall1(while_pred, value)) { + rplacd(lcons, nil); + } else { + val next_item = funcall1(gen_fun, value); + val lcons_next = make_lazy_cons(lcons_fun(lcons)); + rplacd(lcons, lcons_next); + rplaca(lcons_next, next_item); + } + return nil; +} + +static val giterate(val while_pred, val gen_fun, val init_val) +{ + init_val = default_bool_arg(init_val); + + if (!funcall1(while_pred, init_val)) { + return nil; + } else { + val first_item = funcall1(gen_fun, init_val); + val lc = make_lazy_cons(func_f1(cons(while_pred, gen_fun), giterate_func)); + rplaca(lc, first_item); + return lc; + } +} + static val repeat_infinite_func(val env, val lcons) { if (!car(env)) @@ -3942,6 +3972,7 @@ void eval_init(void) reg_fun(intern(lit("range"), user_package), func_n0v(rangev)); reg_fun(intern(lit("range*"), user_package), func_n0v(range_star_v)); reg_fun(generate_s, func_n2(generate)); + reg_fun(intern(lit("giterate"), user_package), func_n3o(giterate, 2)); reg_fun(intern(lit("repeat"), user_package), func_n1v(repeatv)); reg_fun(intern(lit("force"), user_package), func_n1(force)); reg_fun(intern(lit("rperm"), user_package), func_n2(rperm)); @@ -8999,12 +8999,13 @@ the same promise, the cached value is retrieved. .SH LAZY SEQUENCES, RANGES, PERMUTATIONS AND COMBINATIONS -.SS Function generate +.SS Functions generate and giterate .TP Syntax: (generate <while-fun> <gen-fun>) + (giterate <while-fun> <gen-fun> [<value>]) .TP Description: @@ -9027,9 +9028,30 @@ If while-fun yields nil, then generate returns the empty list nil instead of a lazy list. Otherwise, it instantiates a lazy list, and invokes the gen-func to populate it with the first item. +The giterate function is similar to generate, except that <while-fun> +and <gen-fun> are functions of one argument rather than functions of +no arguments. The optional <value> argument defaults to nil and +is threaded through the function calls. Prior to producing the first item, +the lazy list returned by giterate invokes <while-fun> on <value>. +If the call yields true, then <gen-fun> is invoked on <value> and the +resulting value is added to the sequence. That resulting value also becomes the +value for the next iteration: when <while-fun> is invoked again, that +value is used, rather than the original value. + +Note: the giterate function could be written in terms of generate +like this: + + (defun giterate (w g v) + (generate (lambda () [w v]) (lambda () (set v [g v])))) + +.SS +Example: + + (giterate (op > 5) (op + 1) 0) -> (1 2 3 4 5) + .SS Function repeat -.TP + Syntax: (repeat <list1> <list>*) |