summaryrefslogtreecommitdiffstats
path: root/stdlib/arith-each.tl
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2022-01-12 07:04:03 -0800
committerKaz Kylheku <kaz@kylheku.com>2022-01-12 07:04:03 -0800
commita4fe85e6df2e308241984294a3d35353d7cc083a (patch)
tree51550488a40d121c489021aca4aad7fecaecf71c /stdlib/arith-each.tl
parent2e0f7c370fa5012cb54328eb0e73412cb3c59351 (diff)
downloadtxr-a4fe85e6df2e308241984294a3d35353d7cc083a.tar.gz
txr-a4fe85e6df2e308241984294a3d35353d7cc083a.tar.bz2
txr-a4fe85e6df2e308241984294a3d35353d7cc083a.zip
New macros: each-true, some-true, each-false, some-false.
* lisplib.c (arith_each_set_entries): Trigger autoload on new symbols. * stdilb/arith-each.tl (sys:arith-each): Generalize macro to handle short-circuiting logical operations. The op-iv parameter, which is a cons, is spread into two op and iv parameter. One new argument appears, short-circ. This specifies a code for short-circuiting behavior: t means iteration continues while the result is true; nil means it continues while it is nil, and + means iteration continues while the accumulator is nonzero. A new convention is in effect: the operator has to be specified as a list in order to request accumulating behavior, e.g (+) or (*). Otherwise the operator specifies a predicate that is applied to the forms, without taking into account the prior value. (sum-each, sum-each*, mul-each, mul-each*): Spread the op-iv arguments. Wrap the op argument in a list to request accumulation. In the case of mul-each and mul-each*, specify + for the short-circ argument, which means that iteration stops when the accumulator becomes zerop. sum-each and sum-each* specify : for the short-circ argument which is unrecognized, and so ther is no short-circuiting behavior. (each-true, some-true, each-false, some-false): New macros. * tests/016/arith.tl: New tests. * txr.1: Documented new macros and added note about possible short-circuiting in mul-each and mul-each*. * stdlib/doc-syms.tl: Updated.
Diffstat (limited to 'stdlib/arith-each.tl')
-rw-r--r--stdlib/arith-each.tl50
1 files changed, 40 insertions, 10 deletions
diff --git a/stdlib/arith-each.tl b/stdlib/arith-each.tl
index ba8c8c8a..b2904dee 100644
--- a/stdlib/arith-each.tl
+++ b/stdlib/arith-each.tl
@@ -31,43 +31,73 @@
(whenlet ((bad (find-if [notf consp] vars)))
(compile-error form "~s isn't a var-initform pair" bad)))
-(defmacro sys:arith-each (:form f op-iv vars . body)
+(defmacro sys:arith-each (:form f fn iv short-circ vars . body)
(let* ((gens (mapcar (ret (gensym)) vars))
(syms [mapcar car vars])
- (accum (gensym))
- (op (car op-iv))
- (iv (cdr op-iv)))
+ (accum (gensym)))
(if (null vars)
iv
^(let* (,*(mapcar (ret ^(,@1 (iter-begin ,@2))) gens syms)
(,accum ,iv))
(block nil
(sys:for-op ()
- ((and ,*(mapcar (op list 'iter-more) gens)) ,accum)
+ ((and ,*(mapcar (op list 'iter-more) gens)
+ ,*(cond
+ ((eq t short-circ) ^(,accum))
+ ((null short-circ) ^((null ,accum)))
+ ((eq '+ short-circ) ^((nzerop ,accum)))))
+ ,accum)
(,*(mapcar (ret ^(sys:setq ,@1 (iter-step ,@1))) gens))
,*(mapcar (ret ^(sys:setq ,@1 (iter-item ,@2))) syms gens)
- (set ,accum (,op ,accum (progn ,*body)))))))))
+ (set ,accum ,(cond
+ ((consp fn) ^(,(car fn) ,accum (progn ,*body)))
+ (fn ^(,fn (progn ,*body)))
+ (t ^(progn ,*body))))))))))
(defmacro sum-each (:form f vars . body)
(sys:vars-check f vars)
^(let ,vars
(block nil
- (sys:arith-each (+ . 0) ,vars ,*body))))
+ (sys:arith-each (+) 0 : ,vars ,*body))))
(defmacro sum-each* (:form f vars . body)
(sys:vars-check f vars)
^(let* ,vars
(block nil
- (sys:arith-each (+ . 0) ,vars ,*body))))
+ (sys:arith-each (+) 0 : ,vars ,*body))))
(defmacro mul-each (:form f vars . body)
(sys:vars-check f vars)
^(let ,vars
(block nil
- (sys:arith-each (* . 1) ,vars ,*body))))
+ (sys:arith-each (*) 1 + ,vars ,*body))))
(defmacro mul-each* (:form f vars . body)
(sys:vars-check f vars)
^(let* ,vars
(block nil
- (sys:arith-each (* . 1) ,vars ,*body))))
+ (sys:arith-each (*) 1 + ,vars ,*body))))
+
+(defmacro each-true (:form f vars . body)
+ (sys:vars-check f vars)
+ ^(let* ,vars
+ (block nil
+ (sys:arith-each nil t t ,vars ,*body))))
+
+(defmacro some-true (:form f vars . body)
+ (sys:vars-check f vars)
+ ^(let* ,vars
+ (block nil
+ (sys:arith-each nil nil nil ,vars ,*body))))
+
+(defmacro each-false (:form f vars . body)
+ (sys:vars-check f vars)
+ ^(let* ,vars
+ (block nil
+ (sys:arith-each not t t ,vars ,*body))))
+
+(defmacro some-false (:form f vars . body)
+ (sys:vars-check f vars)
+ ^(let* ,vars
+ (block nil
+ (sys:arith-each not nil nil ,vars ,*body))))