diff --git a/NEWS.md b/NEWS.md index 148b5a9..efcf675 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,11 +8,19 @@ See the end of the file for license conditions. ### From 2.18.1 to 2.19.0 +#### Fixes + - Reverted a breaking change introduced in `2.18.0` that caused the threading macro `-->` to be indented differently from `->` and `->>` (#375). - Added and fixed Edebug specifications for many Dash macros (Philipp Stephani, #380, #381). + +#### New features + +- New function `-every` and its anaphoric macro counterpart `--every`. + They are like the existing `-every-p` and `--every-p`, respectively, + but return the last non-`nil` result instead of just `t`. - New macro `--partition-after-pred` which affords `-partition-after-pred` better performance (Per Weijnitz, #362). diff --git a/README.md b/README.md index 0d9f7e3..3dd2e20 100644 --- a/README.md +++ b/README.md @@ -293,6 +293,7 @@ Other list functions not fit to be classified elsewhere. * [`-table-flat`](#-table-flat-fn-rest-lists) `(fn &rest lists)` * [`-first`](#-first-pred-list) `(pred list)` * [`-some`](#-some-pred-list) `(pred list)` +* [`-every`](#-every-pred-list) `(pred list)` * [`-last`](#-last-pred-list) `(pred list)` * [`-first-item`](#-first-item-list) `(list)` * [`-second-item`](#-second-item-list) `(list)` @@ -1275,20 +1276,28 @@ Return t if (`pred` x) is non-nil for any x in `list`, else nil. Alias: `-any-p`, `-some?`, `-some-p` ```el -(-any? 'even? '(1 2 3)) ;; => t -(-any? 'even? '(1 3 5)) ;; => nil -(-any? 'null '(1 3 5)) ;; => nil +(-any? #'numberp '(nil 0 t)) ;; => t +(-any? #'numberp '(nil t t)) ;; => nil +(-any? #'null '(1 3 5)) ;; => nil ``` #### -all? `(pred list)` -Return t if (`pred` x) is non-nil for all x in `list`, else nil. +Return t if (`pred` `x`) is non-nil for all `x` in `list`, else nil. +In the latter case, stop after the first `x` for which (`pred` `x`) is +nil, without calling `pred` on any subsequent elements of `list`. -Alias: `-all-p`, `-every?`, `-every-p` +The similar function [`-every`](#-every-pred-list) is more widely useful, since it +returns the last non-nil result of `pred` instead of just t on +success. + +Alias: `-all-p`, `-every-p`, `-every?`. + +This function's anaphoric counterpart is `--all?`. ```el -(-all? 'even? '(1 2 3)) ;; => nil -(-all? 'even? '(2 4 6)) ;; => t +(-all? #'numberp '(1 2 3)) ;; => t +(-all? #'numberp '(2 t 6)) ;; => nil (--all? (= 0 (% it 2)) '(2 4 6)) ;; => t ``` @@ -2019,9 +2028,27 @@ Alias: `-any`. This function's anaphoric counterpart is `--some`. ```el -(-some (lambda (s) (string-match-p "x" s)) '("foo" "axe" "xor")) ;; => 1 -(-some (lambda (s) (string-match-p "x" s)) '("foo" "bar" "baz")) ;; => nil -(--some (member 'foo it) '((foo bar) (baz))) ;; => (foo bar) +(-some #'stringp '(1 "2" 3)) ;; => t +(--some (string-match-p "x" it) '("foo" "axe" "xor")) ;; => 1 +(--some (= it-index 3) '(0 1 2)) ;; => nil +``` + +#### -every `(pred list)` + +Return non-nil if `pred` returns non-nil for all items in `list`. +If so, return the last such result of `pred`. Otherwise, once an +item is reached for which `pred` returns nil, return nil without +calling `pred` on any further `list` elements. + +This function is like `-every-p`, but on success returns the last +non-nil result of `pred` instead of just t. + +This function's anaphoric counterpart is `--every`. + +```el +(-every #'numberp '(1 2 3)) ;; => t +(--every (string-match-p "x" it) '("axe" "xor")) ;; => 0 +(--every (= it it-index) '(0 1 3)) ;; => nil ``` #### -last `(pred list)` diff --git a/dash.el b/dash.el index 8fb08f7..d53c3bc 100644 --- a/dash.el +++ b/dash.el @@ -854,6 +854,36 @@ This function's anaphoric counterpart is `--some'." (defalias '-any '-some) (defalias '--any '--some) +(defmacro --every (form list) + "Return non-nil if FORM evals to non-nil for all items in LIST. +If so, return the last such result of FORM. Otherwise, once an +item is reached for which FORM yields nil, return nil without +evaluating FORM for any further LIST elements. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. + +This macro is like `--every-p', but on success returns the last +non-nil result of FORM instead of just t. + +This is the anaphoric counterpart to `-every'." + (declare (debug (form form))) + (let ((a (make-symbol "all"))) + `(let ((,a t)) + (--each-while ,list (setq ,a ,form)) + ,a))) + +(defun -every (pred list) + "Return non-nil if PRED returns non-nil for all items in LIST. +If so, return the last such result of PRED. Otherwise, once an +item is reached for which PRED returns nil, return nil without +calling PRED on any further LIST elements. + +This function is like `-every-p', but on success returns the last +non-nil result of PRED instead of just t. + +This function's anaphoric counterpart is `--every'." + (--every (funcall pred it) list)) + (defmacro --last (form list) "Anaphoric form of `-last'." (declare (debug (form form))) @@ -949,7 +979,7 @@ See also: `-last-item'." (defmacro --any? (form list) "Anaphoric form of `-any?'." (declare (debug (form form))) - `(---truthy? (--some ,form ,list))) + `(and (--some ,form ,list) t)) (defun -any? (pred list) "Return t if (PRED x) is non-nil for any x in LIST, else nil. @@ -965,17 +995,34 @@ Alias: `-any-p', `-some?', `-some-p'" (defalias '--some-p '--any?) (defmacro --all? (form list) - "Anaphoric form of `-all?'." + "Return t if FORM evals to non-nil for all items in LIST. +Otherwise, once an item is reached for which FORM yields nil, +return nil without evaluating FORM for any further LIST elements. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. + +The similar macro `--every' is more widely useful, since it +returns the last non-nil result of FORM instead of just t on +success. + +Alias: `--all-p', `--every-p', `--every?'. + +This is the anaphoric counterpart to `-all?'." (declare (debug (form form))) - (let ((a (make-symbol "all"))) - `(let ((,a t)) - (--each-while ,list ,a (setq ,a ,form)) - (---truthy? ,a)))) + `(and (--every ,form ,list) t)) (defun -all? (pred list) - "Return t if (PRED x) is non-nil for all x in LIST, else nil. + "Return t if (PRED X) is non-nil for all X in LIST, else nil. +In the latter case, stop after the first X for which (PRED X) is +nil, without calling PRED on any subsequent elements of LIST. + +The similar function `-every' is more widely useful, since it +returns the last non-nil result of PRED instead of just t on +success. + +Alias: `-all-p', `-every-p', `-every?'. -Alias: `-all-p', `-every?', `-every-p'" +This function's anaphoric counterpart is `--all?'." (--all? (funcall pred it) list)) (defalias '-every? '-all?) diff --git a/dash.texi b/dash.texi index 70e782a..b17166e 100644 --- a/dash.texi +++ b/dash.texi @@ -1722,15 +1722,15 @@ Alias: @code{-any-p}, @code{-some?}, @code{-some-p} @example @group -(-any? 'even? '(1 2 3)) +(-any? #'numberp '(nil 0 t)) @result{} t @end group @group -(-any? 'even? '(1 3 5)) +(-any? #'numberp '(nil t t)) @result{} nil @end group @group -(-any? 'null '(1 3 5)) +(-any? #'null '(1 3 5)) @result{} nil @end group @end example @@ -1738,18 +1738,26 @@ Alias: @code{-any-p}, @code{-some?}, @code{-some-p} @anchor{-all?} @defun -all? (pred list) -Return t if (@var{pred} x) is non-nil for all x in @var{list}, else nil. +Return t if (@var{pred} @var{x}) is non-nil for all @var{x} in @var{list}, else nil. +In the latter case, stop after the first @var{x} for which (@var{pred} @var{x}) is +nil, without calling @var{pred} on any subsequent elements of @var{list}. -Alias: @code{-all-p}, @code{-every?}, @code{-every-p} +The similar function @code{-every} (@pxref{-every}) is more widely useful, since it +returns the last non-nil result of @var{pred} instead of just t on +success. + +Alias: @code{-all-p}, @code{-every-p}, @code{-every?}. + +This function's anaphoric counterpart is @code{--all?}. @example @group -(-all? 'even? '(1 2 3)) - @result{} nil +(-all? #'numberp '(1 2 3)) + @result{} t @end group @group -(-all? 'even? '(2 4 6)) - @result{} t +(-all? #'numberp '(2 t 6)) + @result{} nil @end group @group (--all? (= 0 (% it 2)) '(2 4 6)) @@ -3015,16 +3023,44 @@ This function's anaphoric counterpart is @code{--some}. @example @group -(-some (lambda (s) (string-match-p "x" s)) '("foo" "axe" "xor")) +(-some #'stringp '(1 "2" 3)) + @result{} t +@end group +@group +(--some (string-match-p "x" it) '("foo" "axe" "xor")) @result{} 1 @end group @group -(-some (lambda (s) (string-match-p "x" s)) '("foo" "bar" "baz")) +(--some (= it-index 3) '(0 1 2)) @result{} nil @end group +@end example +@end defun + +@anchor{-every} +@defun -every (pred list) +Return non-nil if @var{pred} returns non-nil for all items in @var{list}. +If so, return the last such result of @var{pred}. Otherwise, once an +item is reached for which @var{pred} returns nil, return nil without +calling @var{pred} on any further @var{list} elements. + +This function is like @code{-every-p}, but on success returns the last +non-nil result of @var{pred} instead of just t. + +This function's anaphoric counterpart is @code{--every}. + +@example @group -(--some (member 'foo it) '((foo bar) (baz))) - @result{} (foo bar) +(-every #'numberp '(1 2 3)) + @result{} t +@end group +@group +(--every (string-match-p "x" it) '("axe" "xor")) + @result{} 0 +@end group +@group +(--every (= it it-index) '(0 1 3)) + @result{} nil @end group @end example @end defun diff --git a/dev/examples.el b/dev/examples.el index df05d34..e0da02d 100644 --- a/dev/examples.el +++ b/dev/examples.el @@ -625,16 +625,33 @@ value rather than consuming a list to produce a single value." "Reductions of one or more lists to a boolean value." (defexamples -any? - (-any? 'even? '(1 2 3)) => t - (-any? 'even? '(1 3 5)) => nil - (-any? 'null '(1 3 5)) => nil - (-any? 'null '(1 3 ())) => t - (--any? (= 0 (% it 2)) '(1 2 3)) => t) + (-any? #'numberp '(nil 0 t)) => t + (-any? #'numberp '(nil t t)) => nil + (-any? #'null '(1 3 5)) => nil + (-any? #'null '(1 3 ())) => t + (-any? #'identity '()) => nil + (-any? #'identity '(0)) => t + (-any? #'identity '(nil)) => nil + (--any? (= 0 (% it 2)) '(1 2 3)) => t + (--any? (= it it-index) '()) => nil + (--any? (= it it-index) '(0)) => t + (--any? (= it it-index) '(1)) => nil + (--any? (= it it-index) '(1 1)) => t + (--any? (= it it-index) '(1 2)) => nil) (defexamples -all? - (-all? 'even? '(1 2 3)) => nil - (-all? 'even? '(2 4 6)) => t - (--all? (= 0 (% it 2)) '(2 4 6)) => t) + (-all? #'numberp '(1 2 3)) => t + (-all? #'numberp '(2 t 6)) => nil + (--all? (= 0 (% it 2)) '(2 4 6)) => t + (-all? #'identity '()) => t + (-all? #'identity '(0)) => t + (-all? #'identity '(0 1)) => t + (-all? #'identity '(nil)) => nil + (--all? (= it it-index) '()) => t + (--all? (= it it-index) '(0)) => t + (--all? (= it it-index) '(1)) => nil + (--all? (= it it-index) '(1 1)) => nil + (--all? (= it it-index) '(0 1)) => t) (defexamples -none? (-none? 'even? '(1 2 3)) => nil @@ -1086,7 +1103,9 @@ related predicates." (-first #'identity '()) => nil) (defexamples -some - (-some (lambda (s) (string-match-p "x" s)) '("foo" "axe" "xor")) => 1 + (-some #'stringp '(1 "2" 3)) => t + (--some (string-match-p "x" it) '("foo" "axe" "xor")) => 1 + (--some (= it-index 3) '(0 1 2)) => nil (-some (lambda (s) (string-match-p "x" s)) '("foo" "bar" "baz")) => nil (--some (member 'foo it) '((foo bar) (baz))) => '(foo bar) (--some (plist-get it :bar) '((:foo 1 :bar 2) (:baz 3))) => 2 @@ -1103,6 +1122,32 @@ related predicates." (--some it '(1)) => 1 (--some it '()) => nil) + (defexamples -every + (-every #'numberp '(1 2 3)) => t + (--every (string-match-p "x" it) '("axe" "xor")) => 0 + (--every (= it it-index) '(0 1 3)) => nil + (-every #'ignore '()) => t + (-every #'ignore '(0)) => nil + (-every #'ignore '(0 1)) => nil + (--every nil '()) => t + (--every nil '(0)) => nil + (--every nil '(0 1)) => nil + (-every #'identity '()) => t + (-every #'identity '(0)) => 0 + (-every #'identity '(0 1)) => 1 + (--every it '()) => t + (--every it '(1)) => 1 + (--every it '(1 2)) => 2 + (--every it-index '()) => t + (--every it-index '(1)) => 0 + (--every it-index '(1 2)) => 1 + (let ((r 'r)) (-every (lambda (x) (setq r x)) '()) r) => 'r + (let ((r 'r)) (-every (lambda (x) (setq r x)) '(nil 1)) r) => nil + (let (r) (-every (lambda (x) (setq r x)) '(0 1)) r) => 1 + (let (i) (--every (ignore (setq i it-index)) '()) i) => nil + (let (i) (--every (ignore (setq i it-index)) '(a)) i) => 0 + (let (i) (--every (ignore (setq i it-index)) '(a b)) i) => 0) + (defexamples -last (-last 'even? '(1 2 3 4 5 6 3 3 3)) => 6 (-last 'even? '(1 3 7 5 9)) => nil