summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2014-07-27 09:49:51 -0700
committerKaz Kylheku <kaz@kylheku.com>2014-07-27 09:49:51 -0700
commita78684b08ea0669262156c78e9b8eb4bc68e8139 (patch)
treeaf3eeb53554fcc466f63525494e977b7a5bd8b91
parent6afe9ab25e2cda942d8e67513081fbe25c217601 (diff)
downloadtxr-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--ChangeLog7
-rw-r--r--eval.c31
-rw-r--r--txr.126
3 files changed, 62 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 5678a8c7..c6799d32 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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,
diff --git a/eval.c b/eval.c
index 0feccc5f..d2539817 100644
--- a/eval.c
+++ b/eval.c
@@ -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));
diff --git a/txr.1 b/txr.1
index 86421355..4482bdc4 100644
--- a/txr.1
+++ b/txr.1
@@ -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>*)