diff options
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | eval.c | 81 | ||||
-rw-r--r-- | txr.1 | 61 |
3 files changed, 152 insertions, 0 deletions
@@ -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 @@ -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)); @@ -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 ) |