summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--eval.c81
-rw-r--r--txr.161
3 files changed, 152 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 0897bd32..5fd0b7f0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
2015-02-12 Kaz Kylheku <kaz@kylheku.com>
+ New functions pad and weave.
+
+ * eval.c (pad_func, pad, weave_while, weave_gen, weavev):
+ New static functions.
+ (eval_init): Registered pad and weave intrisics.
+
+ * txr.1: Documented pad and weave.
+
+2015-02-12 Kaz Kylheku <kaz@kylheku.com>
+
* lib.c (lazy_appendv_func, lazy_appendv): Bugfix: append*
was silently ignoring lists after the first atom, instead of
throwing an error. Also, it was not detecting the case that
diff --git a/eval.c b/eval.c
index a0080ad9..645af5f2 100644
--- a/eval.c
+++ b/eval.c
@@ -3429,6 +3429,85 @@ static val repeat(val list, val count)
return make_lazy_cons(func_f1(cons(list, list), repeat_infinite_func));
}
+static val pad_func(val env, val lcons)
+{
+ cons_bind (list, item_count, env);
+ val next = cdr(list);
+
+ rplaca(lcons, car(list));
+
+ if (next && seqp(next)) {
+ rplaca(env, next);
+ rplacd(lcons, make_lazy_cons(lcons_fun(lcons)));
+ return nil;
+ } else if (!next) {
+ val count = cdr(item_count);
+ rplacd(item_count, nil);
+ rplacd(lcons, repeat(item_count, count));
+ } else {
+ uw_throwf(error_s, lit("pad: cannot pad improper list terminated by ~s"),
+ next, nao);
+ }
+
+ return nil;
+}
+
+static val pad(val list, val item_in, val count)
+{
+ val item = default_bool_arg(item_in);
+
+ switch (type(list)) {
+ case NIL:
+ return repeat(cons(item, nil), count);
+ case CONS:
+ return append2(list, repeat(cons(item, nil), count));
+ case LCONS:
+ case VEC:
+ case LIT:
+ case STR:
+ case LSTR:
+ return make_lazy_cons(func_f1(cons(list, cons(item, count)), pad_func));
+ default:
+ uw_throwf(error_s, lit("pad: cannot pad ~s, only sequences"), list, nao);
+ }
+}
+
+static val weave_while(val env)
+{
+ cons_bind (uniq, tuples, env);
+ val tuple;
+
+ if (!tuples)
+ return nil;
+
+ tuple = remq(uniq, car(tuples));
+
+ if (!tuple)
+ return nil;
+
+ rplaca(tuples, tuple);
+ return t;
+}
+
+static val weave_gen(val env)
+{
+ val tuples = cdr(env);
+ val ret = car(tuples);
+ rplacd(env, cdr(tuples));
+ return ret;
+}
+
+static val weavev(val lists)
+{
+ val uniq = cons(nil, nil);
+ val padded_lists = mapcar(curry_123_1(func_n3(pad), uniq, colon_k), lists);
+ val tuples = lazy_mapcarv(list_f, padded_lists);
+ val env = cons(uniq, tuples);
+ val whil = func_f0(env, weave_while);
+ val gen = func_f0(env, weave_gen);
+ return lazy_appendv(generate(whil, gen));
+}
+
static val force(val promise)
{
if (car(promise) != promise_s)
@@ -4196,6 +4275,8 @@ void eval_init(void)
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_n2o(repeat, 1));
+ reg_fun(intern(lit("pad"), user_package), func_n3o(pad, 1));
+ reg_fun(intern(lit("weave"), user_package), func_n0v(weavev));
reg_fun(intern(lit("force"), user_package), func_n1(force));
reg_fun(intern(lit("rperm"), user_package), func_n2(rperm));
reg_fun(intern(lit("perm"), user_package), func_n2o(perm, 1));
diff --git a/txr.1 b/txr.1
index 0be270f4..843394fa 100644
--- a/txr.1
+++ b/txr.1
@@ -15294,6 +15294,67 @@ repetitions of
.meta list
catenated together.
+.coNP Function @ pad
+.synb
+.mets (pad < sequence < object <> [ count ])
+.syne
+.desc
+The
+.code pad
+function produces a lazy list which consists of all of the
+elements of
+.meta sequence
+followed by repetitions of
+.meta object .
+
+If
+.meta count
+is omitted, then the repetition of
+.meta object
+is infinite. Otherwise the specified number of repetitions
+occur.
+
+Note that
+.meta sequence
+may be a lazy list which is infinite. In that case, the repetitions
+of
+.meta object
+will never occur.
+
+.coNP Function @ weave
+.synb
+.mets (weave >> { sequence }*)
+.syne
+The
+.code weave
+function interleaves elements from the sequences given as arguments.
+
+If called with no arguments, it returns the empty list.
+
+If called with a single sequence, it returns the elements of that sequence
+as a new lazy list.
+
+When called with two or more sequences,
+.code
+weave
+returns a lazy list which draws elements from the sequeces in a round-robin
+fashion, repeatedly scanning the sequences from left to right, and
+taking an item from each one, removing it from the sequence.
+Whenever a sequence runs out of items, it is deleted; the weaving then
+continues with the remaining sequences. The weaved sequence terminates
+when all sequences are eliminated. (If at least one of the sequences
+is an infinite lazy list, then the weaved sequence is infinite.)
+
+.TP* Examples:
+
+.cblk
+ ;; Weave negative integers with positive ones:
+ (weave (range 1) (range -1 : -1)) -> (1 -1 2 -2 3 -3 ...)
+
+ (weave "abcd" (range 1 3) '(x x x x x x x))
+ --> (#\ea 1 x #\eb 2 x #\ec 3 x #\ed x x x x)
+.cble
+
.coNP Macros @ gen and @ gun
.synb
.mets (gen < while-expression << produce-item-expression )