summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-12-18 06:45:28 -0800
committerKaz Kylheku <kaz@kylheku.com>2017-12-18 06:45:28 -0800
commited96dfc8f4bee9d15bbe62dd5f97891727835db6 (patch)
treebcdc2b5f8fb5f8c585cdcbe8e98f1993e488cc7b
parent9107ce48a93c737a9bbe645e37e8cc3b01a0903d (diff)
downloadtxr-ed96dfc8f4bee9d15bbe62dd5f97891727835db6.tar.gz
txr-ed96dfc8f4bee9d15bbe62dd5f97891727835db6.tar.bz2
txr-ed96dfc8f4bee9d15bbe62dd5f97891727835db6.zip
New functions: rlist and rlist*.
These easily express discontinuous ranges. * eval.c (rlist_fun, rlist_star_fun, rlist, rlist_star): New static functions. (eval_init): Register rlist and rlist* intrinsics. * txr.1: Documented.
-rw-r--r--eval.c40
-rw-r--r--txr.195
2 files changed, 135 insertions, 0 deletions
diff --git a/eval.c b/eval.c
index b321d692..a3c79574 100644
--- a/eval.c
+++ b/eval.c
@@ -5025,6 +5025,44 @@ static val range_star(val from_in, val to_in, val step_in)
}
}
+static val rlist_fun(val item)
+{
+ if (rangep(item)) {
+ val rto = to(item);
+ return if3(rangep(rto),
+ range(from(item), from(rto), to(rto)),
+ range(from(item), rto, nil));
+ }
+
+ return cons(item, nil);
+}
+
+static val rlist_star_fun(val item)
+{
+ if (rangep(item)) {
+ val rto = to(item);
+ return if3(rangep(rto),
+ range_star(from(item), from(rto), to(rto)),
+ range_star(from(item), rto, nil));
+ }
+
+ return cons(item, nil);
+}
+
+static val rlist(struct args *items)
+{
+ args_decl_list(lists, ARGS_MIN,
+ lazy_mapcar(func_n1(rlist_fun), args_get_list(items)));
+ return lazy_appendv(lists);
+}
+
+static val rlist_star(struct args *items)
+{
+ args_decl_list(lists, ARGS_MIN,
+ lazy_mapcar(func_n1(rlist_star_fun), args_get_list(items)));
+ return lazy_appendv(lists);
+}
+
static val generate_func(val env, val lcons)
{
cons_bind (while_pred, gen_fun, env);
@@ -6340,6 +6378,8 @@ void eval_init(void)
reg_fun(intern(lit("range"), user_package), func_n3o(range, 0));
reg_fun(intern(lit("range*"), user_package), func_n3o(range_star, 0));
+ reg_fun(intern(lit("rlist"), user_package), func_n0v(rlist));
+ reg_fun(intern(lit("rlist*"), user_package), func_n0v(rlist_star));
reg_fun(generate_s, func_n2(generate));
reg_fun(intern(lit("giterate"), user_package), func_n3o(giterate, 2));
reg_fun(intern(lit("ginterate"), user_package), func_n3o(ginterate, 2));
diff --git a/txr.1 b/txr.1
index e32be45e..ec071d3d 100644
--- a/txr.1
+++ b/txr.1
@@ -20762,6 +20762,101 @@ might step over the endpoint value, and
therefore never attain it. In this situation, the sequence also stops, and the
excess value which surpasses the endpoint is excluded from the sequence.
+.coNP Functions @ rlist and @ rlist*
+.synb
+.mets (rlist << item *)
+.mets (rlist* << item *)
+.syne
+.desc
+The
+.code rlist
+("range list") function is useful for producing a list consisting of a mixture
+of discontinuous numeric or character ranges and individual items.
+
+The function returns a lazy list of elements. The items are produced
+by converting the function's successive
+.meta item
+arguments into lists, which are lazily catenated together to form the
+output list.
+
+Each
+.meta item
+is transformed into a list as follows. Any item which is
+.B not
+a range object is trivially turned into a one-element list as if by the
+.cblk
+.meti (list << item *)
+.cble
+expression.
+
+Any item which is a range object, whose
+.code to
+field
+.B isn't
+a range is turned into a lazy list as if by evaluating the
+.cblk
+.meti (range (from << item) (to << item))
+.cble
+expression. Thus for instance the argument
+.code 1..10
+turns into the (lazy) list
+.codn "(1 2 3 4 5 6 7 8 9 10)" .
+
+Any item which is a range object such that its
+.code to
+field is also a range is turned into a lazy list as if by evaluating the
+.cblk
+.meti (range (from << item) (from (to << item)) (to (to << item)))
+.cble
+expression. Thus for instance the argument expression
+.code 1..10..2
+produces an
+.meta item
+which
+.code rlist
+turns into the lazy list
+.code "(1 3 5 7 9)"
+as if by the call
+.codn "(range 1 10 2)" .
+Note that the expression
+.code 1..10..2
+stands for the expression
+.code "(range 1 (range 10 2))"
+which evaluates to
+.codn "#R(1 #R(10 2))" .
+
+The
+.code "#R(1 #R(10 2))"
+range literal syntax can be passed as an argument to
+.code rlist
+with the same result as
+.codn 1..10..2 .
+
+The
+.code rlist*
+function differs from
+.code rlist
+in one regard: under
+.codn rlist* ,
+the ranges denoted by the range notation exclude the endpoint. That is,
+the ranges are generated as if by the
+.code range*
+function rather than
+.codn range .
+
+Note: it is permissible for
+.meta item
+objects to specify infinite ranges.
+It is also permissible to apply an infinite argument list to
+.codn rlist .
+
+.TP* Examples:
+.cblk
+ (rlist 1 "two" :three) -> (1 "two" :three)
+ (rlist 10 15..16 #\ea..#\ed 2) -> (10 15 16 #\ea #\eb #\ec 2)
+ (take 7 (rlist 1 2 5..:)) -> (1 2 5 6 7 8 9)
+.cble
+
.SS* Ranges
Ranges are objects that aggregate two values, not unlike
.code cons