summaryrefslogtreecommitdiffstats
path: root/lib.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2014-01-27 00:47:43 -0800
committerKaz Kylheku <kaz@kylheku.com>2014-01-27 00:47:43 -0800
commit857dda93d112fdd5e776f5dce2bbfc8a51704b2a (patch)
treea0f2d19df381ecc4d7bf5c1bf144fc70e643309b /lib.c
parentbcc1770bf64c62dc5c6404596017cf73a6c9e25e (diff)
downloadtxr-857dda93d112fdd5e776f5dce2bbfc8a51704b2a.tar.gz
txr-857dda93d112fdd5e776f5dce2bbfc8a51704b2a.tar.bz2
txr-857dda93d112fdd5e776f5dce2bbfc8a51704b2a.zip
* lib.c (reduce_left, reduce_right): changing the behavior so that
the initial value is optional. this creates the possibility that the effective list of operands is empty, in which case the function must support a call with no arguments, just like in the common lisp reduce. * txr.1: rewrote reduce-left and reduce-right documentation.
Diffstat (limited to 'lib.c')
-rw-r--r--lib.c25
1 files changed, 24 insertions, 1 deletions
diff --git a/lib.c b/lib.c
index ecabd77f..c83dde14 100644
--- a/lib.c
+++ b/lib.c
@@ -3542,6 +3542,12 @@ val reduce_left(val fun, val list, val init, val key)
if (!key)
key = identity_f;
+ if (!init && list)
+ init = pop(&list);
+
+ if (!init && !list)
+ return funcall(fun);
+
for (; list; list = cdr(list))
init = funcall2(fun, init, funcall1(key, car(list)));
@@ -3553,8 +3559,25 @@ val reduce_right(val fun, val list, val init, val key)
if (!key)
key = identity_f;
- if (nullp(list))
+ if (list) {
+ if (!init) {
+ if (!rest(list))
+ return funcall1(key, first(list));
+ if (!rest(rest(list)))
+ return funcall2(fun, funcall1(key, first(list)),
+ funcall1(key, second(list)));
+ /* fall through: no init, three or more items in list */
+ } else {
+ if (!rest(list))
+ return funcall2(fun, funcall1(key, first(list)), init);
+ /* fall through: init, and two or more items in list */
+ }
+ } else if (init) {
return init;
+ } else {
+ return funcall(fun);
+ }
+
return funcall2(fun, funcall1(key, car(list)),
if3(cdr(list), reduce_right(fun, cdr(list), init, key),
init));