emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/dash 11a6296 1/2: Prefer n-ary over unary/binary combin


From: ELPA Syncer
Subject: [elpa] externals/dash 11a6296 1/2: Prefer n-ary over unary/binary combinators
Date: Thu, 8 Jul 2021 12:57:11 -0400 (EDT)

branch: externals/dash
commit 11a629639111cb919ca6d2942270fb1999d540de
Author: Basil L. Contovounesios <contovob@tcd.ie>
Commit: Basil L. Contovounesios <contovob@tcd.ie>

    Prefer n-ary over unary/binary combinators
    
    This is a rewrite and extension of PR #72 to address issue #306.
    For discussion, especially wrt performance, see PRs #72 and #308.
    
    * dash.el (-on, -flip, -not, -orfn, -andfn): Return a variadic
    function.  Declare as pure and side-effect-free.
    (-rotate-args): New combinator suggested by @vapniks in PR #72.
    (-const): Declare as pure and side-effect-free.
    
    * NEWS.md (2.19.0): Announce -rotate-args and variadic combinators.
    
    * dev/examples.el (-partition-after-pred): Fix oddp bug waiting to
    happen with negative dividends.
    (-cons*): Check that &rest args are safe to mutate.
    (-on, -flip, -const, -not, -orfn, -andfn): Extend tests.
    (-rotate-args): New test.
    
    * README.md:
    * dash.texi: Regenerate docs.
---
 NEWS.md         |   4 ++
 README.md       | 113 ++++++++++++++++++++++++++--------------
 dash.el         | 126 ++++++++++++++++++++++++++++++++++----------
 dash.texi       | 138 +++++++++++++++++++++++++++++++++---------------
 dev/examples.el | 159 ++++++++++++++++++++++++++++++++++++++++++++------------
 5 files changed, 399 insertions(+), 141 deletions(-)

diff --git a/NEWS.md b/NEWS.md
index efcf675..bd9700e 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -18,6 +18,10 @@ See the end of the file for license conditions.
 
 #### New features
 
+- The combinators `-on`, `-flip`, `-not`, `-andfn`, and `-orfn` now
+  return variadic functions that take any number of arguments (#308).
+- New combinator `-rotate-args` similar to `-flip`, but for arbitrary
+  arglist rotations (suggested by @vapniks, #72).
 - 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`.
diff --git a/README.md b/README.md
index c738bf9..00fc4d7 100644
--- a/README.md
+++ b/README.md
@@ -373,8 +373,9 @@ Functions that manipulate and compose other functions.
 * [`-juxt`](#-juxt-rest-fns) `(&rest fns)`
 * [`-compose`](#-compose-rest-fns) `(&rest fns)`
 * [`-applify`](#-applify-fn) `(fn)`
-* [`-on`](#-on-operator-transformer) `(operator transformer)`
-* [`-flip`](#-flip-func) `(func)`
+* [`-on`](#-on-op-trans) `(op trans)`
+* [`-flip`](#-flip-fn) `(fn)`
+* [`-rotate-args`](#-rotate-args-n-fn) `(n fn)`
 * [`-const`](#-const-c) `(c)`
 * [`-cut`](#-cut-rest-params) `(&rest params)`
 * [`-not`](#-not-pred) `(pred)`
@@ -1193,7 +1194,7 @@ Return the smallest value from `list` of numbers or 
markers.
 Take a comparison function `comparator` and a `list` and return
 the least element of the list by the comparison function.
 
-See also combinator [`-on`](#-on-operator-transformer) which can transform the 
values before
+See also combinator [`-on`](#-on-op-trans) which can transform the values 
before
 comparing them.
 
 ```el
@@ -1217,7 +1218,7 @@ Return the largest value from `list` of numbers or 
markers.
 Take a comparison function `comparator` and a `list` and return
 the greatest element of the list by the comparison function.
 
-See also combinator [`-on`](#-on-operator-transformer) which can transform the 
values before
+See also combinator [`-on`](#-on-op-trans) which can transform the values 
before
 comparing them.
 
 ```el
@@ -2892,30 +2893,56 @@ taking 1 argument which is a list of `n` arguments.
 (funcall (-applify #'<) '(3 6)) ;; => t
 ```
 
-#### -on `(operator transformer)`
+#### -on `(op trans)`
 
-Return a function of two arguments that first applies
-`transformer` to each of them and then applies `operator` on the
-results (in the same order).
+Return a function that calls `trans` on each arg and `op` on the results.
+The returned function takes a variable number of arguments, calls
+the function `trans` on each one in turn, and then passes those
+results as the list of arguments to `op`, in the same order.
 
-In types: (b -> b -> c) -> (a -> b) -> a -> a -> c
+For example, the following pairs of expressions are morally
+equivalent:
+
+    (funcall (-on #'+ #'1+) 1 2 3) = (+ (1+ 1) (1+ 2) (1+ 3))
+    (funcall (-on #'+ #'1+))       = (+)
 
 ```el
-(-sort (-on '< 'length) '((1 2 3) (1) (1 2))) ;; => ((1) (1 2) (1 2 3))
-(-min-by (-on '> 'length) '((1 2 3) (4) (1 2))) ;; => (4)
-(-min-by (-on 'string-lessp 'number-to-string) '(2 100 22)) ;; => 22
+(-sort (-on #'< #'length) '((1 2 3) (1) (1 2))) ;; => ((1) (1 2) (1 2 3))
+(funcall (-on #'min #'string-to-number) "22" "2" "1" "12") ;; => 1
+(-min-by (-on #'> #'length) '((1 2 3) (4) (1 2))) ;; => (4)
 ```
 
-#### -flip `(func)`
+#### -flip `(fn)`
+
+Return a function that calls `fn` with its arguments reversed.
+The returned function takes the same number of arguments as `fn`.
+
+For example, the following two expressions are morally
+equivalent:
 
-Swap the order of arguments for binary function `func`.
+    (funcall (-flip #'-) 1 2) = (- 2 1)
 
-In types: (a -> b -> c) -> b -> a -> c
+See also: [`-rotate-args`](#-rotate-args-n-fn).
 
 ```el
-(funcall (-flip '<) 2 1) ;; => t
-(funcall (-flip '-) 3 8) ;; => 5
-(-sort (-flip '<) '(4 3 6 1)) ;; => (6 4 3 1)
+(-sort (-flip #'<) '(4 3 6 1)) ;; => (6 4 3 1)
+(funcall (-flip #'-) 3 2 1 10) ;; => 4
+(funcall (-flip #'1+) 1) ;; => 2
+```
+
+#### -rotate-args `(n fn)`
+
+Return a function that calls `fn` with args rotated `n` places to the right.
+The returned function takes the same number of arguments as `fn`,
+rotates the list of arguments `n` places to the right (left if `n` is
+negative) just like [`-rotate`](#-rotate-n-list), and applies `fn` to the 
result.
+
+See also: [`-flip`](#-flip-fn).
+
+```el
+(funcall (-rotate-args -1 #'list) 1 2 3 4) ;; => (2 3 4 1)
+(funcall (-rotate-args 1 #'-) 1 10 100) ;; => 89
+(funcall (-rotate-args 2 #'list) 3 4 5 1 2) ;; => (1 2 3 4 5)
 ```
 
 #### -const `(c)`
@@ -2926,8 +2953,8 @@ In types: a -> b -> a
 
 ```el
 (funcall (-const 2) 1 3 "foo") ;; => 2
-(-map (-const 1) '("a" "b" "c" "d")) ;; => (1 1 1 1)
-(-sum (-map (-const 1) '("a" "b" "c" "d"))) ;; => 4
+(mapcar (-const 1) '("a" "b" "c" "d")) ;; => (1 1 1 1)
+(-sum (mapcar (-const 1) '("a" "b" "c" "d"))) ;; => 4
 ```
 
 #### -cut `(&rest params)`
@@ -2945,40 +2972,50 @@ See `srfi-26` for detailed description.
 
 #### -not `(pred)`
 
-Take a unary predicate `pred` and return a unary predicate
-that returns t if `pred` returns nil and nil if `pred` returns
-non-nil.
+Return a predicate that negates the result of `pred`.
+The returned predicate passes its arguments to `pred`.  If `pred`
+returns nil, the result is non-nil; otherwise the result is nil.
+
+See also: [`-andfn`](#-andfn-rest-preds) and [`-orfn`](#-orfn-rest-preds).
 
 ```el
-(funcall (-not 'even?) 5) ;; => t
-(-filter (-not (-partial '< 4)) '(1 2 3 4 5 6 7 8)) ;; => (1 2 3 4)
+(funcall (-not #'numberp) "5") ;; => t
+(-sort (-not #'<) '(5 2 1 0 6)) ;; => (6 5 2 1 0)
+(-filter (-not (-partial #'< 4)) '(1 2 3 4 5 6 7 8)) ;; => (1 2 3 4)
 ```
 
 #### -orfn `(&rest preds)`
 
-Take list of unary predicates `preds` and return a unary
-predicate with argument x that returns non-nil if at least one of
-the `preds` returns non-nil on x.
+Return a predicate that returns the first non-nil result of `preds`.
+The returned predicate takes a variable number of arguments,
+passes them to each predicate in `preds` in turn until one of them
+returns non-nil, and returns that non-nil result without calling
+the remaining `preds`.  If all `preds` return nil, or if no `preds` are
+given, the returned predicate returns nil.
 
-In types: [a -> Bool] -> a -> Bool
+See also: [`-andfn`](#-andfn-rest-preds) and [`-not`](#-not-pred).
 
 ```el
-(-filter (-orfn 'even? (-partial (-flip '<) 5)) '(1 2 3 4 5 6 7 8 9 10)) ;; => 
(1 2 3 4 6 8 10)
-(funcall (-orfn 'stringp 'even?) "foo") ;; => t
+(-filter (-orfn #'natnump #'booleanp) '(1 nil "a" -4 b c t)) ;; => (1 nil t)
+(funcall (-orfn #'symbolp (-cut string-match-p "x" <>)) "axe") ;; => 1
+(funcall (-orfn #'= #'+) 1 1) ;; => t
 ```
 
 #### -andfn `(&rest preds)`
 
-Take list of unary predicates `preds` and return a unary
-predicate with argument x that returns non-nil if all of the
-`preds` returns non-nil on x.
+Return a predicate that returns non-nil if all `preds` do so.
+The returned predicate `p` takes a variable number of arguments and
+passes them to each predicate in `preds` in turn.  If any one of
+`preds` returns nil, `p` also returns nil without calling the
+remaining `preds`.  If all `preds` return non-nil, `p` returns the last
+such value.  If no `preds` are given, `p` always returns non-nil.
 
-In types: [a -> Bool] -> a -> Bool
+See also: [`-orfn`](#-orfn-rest-preds) and [`-not`](#-not-pred).
 
 ```el
-(funcall (-andfn (-cut < <> 10) 'even?) 6) ;; => t
-(funcall (-andfn (-cut < <> 10) 'even?) 12) ;; => nil
-(-filter (-andfn (-not 'even?) (-cut >= 5 <>)) '(1 2 3 4 5 6 7 8 9 10)) ;; => 
(1 3 5)
+(-filter (-andfn #'numberp (-cut < <> 5)) '(a 1 b 6 c 2)) ;; => (1 2)
+(mapcar (-andfn #'numberp #'1+) '(a 1 b 6)) ;; => (nil 2 nil 7)
+(funcall (-andfn #'= #'+) 1 1) ;; => 2
 ```
 
 #### -iteratefn `(fn n)`
diff --git a/dash.el b/dash.el
index 6f97aca..a0be8f6 100644
--- a/dash.el
+++ b/dash.el
@@ -3113,24 +3113,73 @@ taking 1 argument which is a list of N arguments."
   (declare (pure t) (side-effect-free t))
   (lambda (args) (apply fn args)))
 
-(defun -on (operator transformer)
-  "Return a function of two arguments that first applies
-TRANSFORMER to each of them and then applies OPERATOR on the
-results (in the same order).
+(defun -on (op trans)
+  "Return a function that calls TRANS on each arg and OP on the results.
+The returned function takes a variable number of arguments, calls
+the function TRANS on each one in turn, and then passes those
+results as the list of arguments to OP, in the same order.
 
-In types: (b -> b -> c) -> (a -> b) -> a -> a -> c"
-  (lambda (x y) (funcall operator (funcall transformer x) (funcall transformer 
y))))
+For example, the following pairs of expressions are morally
+equivalent:
 
-(defun -flip (func)
-  "Swap the order of arguments for binary function FUNC.
-
-In types: (a -> b -> c) -> b -> a -> c"
-  (lambda (x y) (funcall func y x)))
+  (funcall (-on #\\='+ #\\='1+) 1 2 3) = (+ (1+ 1) (1+ 2) (1+ 3))
+  (funcall (-on #\\='+ #\\='1+))       = (+)"
+  (declare (pure t) (side-effect-free t))
+  (lambda (&rest args)
+    ;; This unrolling seems to be a relatively cheap way to keep the
+    ;; overhead of `mapcar' + `apply' in check.
+    (cond ((cddr args)
+           (apply op (mapcar trans args)))
+          ((cdr args)
+           (funcall op (funcall trans (car args)) (funcall trans (cadr args))))
+          (args
+           (funcall op (funcall trans (car args))))
+          ((funcall op)))))
+
+(defun -flip (fn)
+  "Return a function that calls FN with its arguments reversed.
+The returned function takes the same number of arguments as FN.
+
+For example, the following two expressions are morally
+equivalent:
+
+  (funcall (-flip #\\='-) 1 2) = (- 2 1)
+
+See also: `-rotate-args'."
+  (declare (pure t) (side-effect-free t))
+  (lambda (&rest args) ;; Open-code for speed.
+    (cond ((cddr args) (apply fn (nreverse args)))
+          ((cdr args) (funcall fn (cadr args) (car args)))
+          (args (funcall fn (car args)))
+          ((funcall fn)))))
+
+(defun -rotate-args (n fn)
+  "Return a function that calls FN with args rotated N places to the right.
+The returned function takes the same number of arguments as FN,
+rotates the list of arguments N places to the right (left if N is
+negative) just like `-rotate', and applies FN to the result.
+
+See also: `-flip'."
+  (declare (pure t) (side-effect-free t))
+  (if (zerop n)
+      fn
+    (let ((even (= (% n 2) 0)))
+      (lambda (&rest args)
+        (cond ((cddr args) ;; Open-code for speed.
+               (apply fn (-rotate n args)))
+              ((cdr args)
+               (let ((fst (car args))
+                     (snd (cadr args)))
+                 (funcall fn (if even fst snd) (if even snd fst))))
+              (args
+               (funcall fn (car args)))
+              ((funcall fn)))))))
 
 (defun -const (c)
   "Return a function that returns C ignoring any additional arguments.
 
 In types: a -> b -> a"
+  (declare (pure t) (side-effect-free t))
   (lambda (&rest _) c))
 
 (defmacro -cut (&rest params)
@@ -3147,30 +3196,51 @@ See SRFI-26 for detailed description."
     `(lambda ,args
        ,(let ((body (--map (if (eq it '<>) (pop args) it) params)))
           (if (eq (car params) '<>)
-              (cons 'funcall body)
+              (cons #'funcall body)
             body)))))
 
 (defun -not (pred)
-  "Take a unary predicate PRED and return a unary predicate
-that returns t if PRED returns nil and nil if PRED returns
-non-nil."
-  (lambda (x) (not (funcall pred x))))
+  "Return a predicate that negates the result of PRED.
+The returned predicate passes its arguments to PRED.  If PRED
+returns nil, the result is non-nil; otherwise the result is nil.
 
-(defun -orfn (&rest preds)
-  "Take list of unary predicates PREDS and return a unary
-predicate with argument x that returns non-nil if at least one of
-the PREDS returns non-nil on x.
+See also: `-andfn' and `-orfn'."
+  (declare (pure t) (side-effect-free t))
+  (lambda (&rest args) (not (apply pred args))))
 
-In types: [a -> Bool] -> a -> Bool"
-  (lambda (x) (-any? (-cut funcall <> x) preds)))
+(defun -orfn (&rest preds)
+  "Return a predicate that returns the first non-nil result of PREDS.
+The returned predicate takes a variable number of arguments,
+passes them to each predicate in PREDS in turn until one of them
+returns non-nil, and returns that non-nil result without calling
+the remaining PREDS.  If all PREDS return nil, or if no PREDS are
+given, the returned predicate returns nil.
+
+See also: `-andfn' and `-not'."
+  (declare (pure t) (side-effect-free t))
+  ;; Open-code for speed.
+  (cond ((cdr preds) (lambda (&rest args) (--some (apply it args) preds)))
+        (preds (car preds))
+        (#'ignore)))
 
 (defun -andfn (&rest preds)
-  "Take list of unary predicates PREDS and return a unary
-predicate with argument x that returns non-nil if all of the
-PREDS returns non-nil on x.
-
-In types: [a -> Bool] -> a -> Bool"
-  (lambda (x) (-all? (-cut funcall <> x) preds)))
+  "Return a predicate that returns non-nil if all PREDS do so.
+The returned predicate P takes a variable number of arguments and
+passes them to each predicate in PREDS in turn.  If any one of
+PREDS returns nil, P also returns nil without calling the
+remaining PREDS.  If all PREDS return non-nil, P returns the last
+such value.  If no PREDS are given, P always returns non-nil.
+
+See also: `-orfn' and `-not'."
+  (declare (pure t) (side-effect-free t))
+  ;; Open-code for speed.
+  (cond ((cdr preds) (lambda (&rest args) (--every (apply it args) preds)))
+        (preds (car preds))
+        ;; As a `pure' function, this runtime check may generate
+        ;; backward-incompatible bytecode for `(-andfn)' at compile-time,
+        ;; but I doubt that's a problem in practice (famous last words).
+        ((fboundp 'always) #'always)
+        ((lambda (&rest _) t))))
 
 (defun -iteratefn (fn n)
   "Return a function FN composed N times with itself.
diff --git a/dash.texi b/dash.texi
index e7e0376..0d30090 100644
--- a/dash.texi
+++ b/dash.texi
@@ -4357,47 +4357,83 @@ taking 1 argument which is a list of @var{n} arguments.
 @end defun
 
 @anchor{-on}
-@defun -on (operator transformer)
-Return a function of two arguments that first applies
-@var{transformer} to each of them and then applies @var{operator} on the
-results (in the same order).
+@defun -on (op trans)
+Return a function that calls @var{trans} on each arg and @var{op} on the 
results.
+The returned function takes a variable number of arguments, calls
+the function @var{trans} on each one in turn, and then passes those
+results as the list of arguments to @var{op}, in the same order.
 
-In types: (b -> b -> c) -> (a -> b) -> a -> a -> c
+For example, the following pairs of expressions are morally
+equivalent:
+
+  (funcall (-on #'+ #'1+) 1 2 3) = (+ (1+ 1) (1+ 2) (1+ 3))
+  (funcall (-on #'+ #'1+))       = (+)
 
 @example
 @group
-(-sort (-on '< 'length) '((1 2 3) (1) (1 2)))
+(-sort (-on #'< #'length) '((1 2 3) (1) (1 2)))
     @result{} ((1) (1 2) (1 2 3))
 @end group
 @group
-(-min-by (-on '> 'length) '((1 2 3) (4) (1 2)))
-    @result{} (4)
+(funcall (-on #'min #'string-to-number) "22" "2" "1" "12")
+    @result{} 1
 @end group
 @group
-(-min-by (-on 'string-lessp 'number-to-string) '(2 100 22))
-    @result{} 22
+(-min-by (-on #'> #'length) '((1 2 3) (4) (1 2)))
+    @result{} (4)
 @end group
 @end example
 @end defun
 
 @anchor{-flip}
-@defun -flip (func)
-Swap the order of arguments for binary function @var{func}.
+@defun -flip (fn)
+Return a function that calls @var{fn} with its arguments reversed.
+The returned function takes the same number of arguments as @var{fn}.
+
+For example, the following two expressions are morally
+equivalent:
 
-In types: (a -> b -> c) -> b -> a -> c
+  (funcall (-flip #'-) 1 2) = (- 2 1)
+
+See also: @code{-rotate-args} (@pxref{-rotate-args}).
 
 @example
 @group
-(funcall (-flip '<) 2 1)
-    @result{} t
+(-sort (-flip #'<) '(4 3 6 1))
+    @result{} (6 4 3 1)
 @end group
 @group
-(funcall (-flip '-) 3 8)
-    @result{} 5
+(funcall (-flip #'-) 3 2 1 10)
+    @result{} 4
 @end group
 @group
-(-sort (-flip '<) '(4 3 6 1))
-    @result{} (6 4 3 1)
+(funcall (-flip #'1+) 1)
+    @result{} 2
+@end group
+@end example
+@end defun
+
+@anchor{-rotate-args}
+@defun -rotate-args (n fn)
+Return a function that calls @var{fn} with args rotated @var{n} places to the 
right.
+The returned function takes the same number of arguments as @var{fn},
+rotates the list of arguments @var{n} places to the right (left if @var{n} is
+negative) just like @code{-rotate} (@pxref{-rotate}), and applies @var{fn} to 
the result.
+
+See also: @code{-flip} (@pxref{-flip}).
+
+@example
+@group
+(funcall (-rotate-args -1 #'list) 1 2 3 4)
+    @result{} (2 3 4 1)
+@end group
+@group
+(funcall (-rotate-args 1 #'-) 1 10 100)
+    @result{} 89
+@end group
+@group
+(funcall (-rotate-args 2 #'list) 3 4 5 1 2)
+    @result{} (1 2 3 4 5)
 @end group
 @end example
 @end defun
@@ -4414,11 +4450,11 @@ In types: a -> b -> a
     @result{} 2
 @end group
 @group
-(-map (-const 1) '("a" "b" "c" "d"))
+(mapcar (-const 1) '("a" "b" "c" "d"))
     @result{} (1 1 1 1)
 @end group
 @group
-(-sum (-map (-const 1) '("a" "b" "c" "d")))
+(-sum (mapcar (-const 1) '("a" "b" "c" "d")))
     @result{} 4
 @end group
 @end example
@@ -4449,17 +4485,23 @@ See @var{srfi-26} for detailed description.
 
 @anchor{-not}
 @defun -not (pred)
-Take a unary predicate @var{pred} and return a unary predicate
-that returns t if @var{pred} returns nil and nil if @var{pred} returns
-non-nil.
+Return a predicate that negates the result of @var{pred}.
+The returned predicate passes its arguments to @var{pred}.  If @var{pred}
+returns nil, the result is non-nil; otherwise the result is nil.
+
+See also: @code{-andfn} (@pxref{-andfn}) and @code{-orfn} (@pxref{-orfn}).
 
 @example
 @group
-(funcall (-not 'even?) 5)
+(funcall (-not #'numberp) "5")
     @result{} t
 @end group
 @group
-(-filter (-not (-partial '< 4)) '(1 2 3 4 5 6 7 8))
+(-sort (-not #'<) '(5 2 1 0 6))
+    @result{} (6 5 2 1 0)
+@end group
+@group
+(-filter (-not (-partial #'< 4)) '(1 2 3 4 5 6 7 8))
     @result{} (1 2 3 4)
 @end group
 @end example
@@ -4467,19 +4509,26 @@ non-nil.
 
 @anchor{-orfn}
 @defun -orfn (&rest preds)
-Take list of unary predicates @var{preds} and return a unary
-predicate with argument x that returns non-nil if at least one of
-the @var{preds} returns non-nil on x.
+Return a predicate that returns the first non-nil result of @var{preds}.
+The returned predicate takes a variable number of arguments,
+passes them to each predicate in @var{preds} in turn until one of them
+returns non-nil, and returns that non-nil result without calling
+the remaining @var{preds}.  If all @var{preds} return nil, or if no 
@var{preds} are
+given, the returned predicate returns nil.
 
-In types: [a -> Bool] -> a -> Bool
+See also: @code{-andfn} (@pxref{-andfn}) and @code{-not} (@pxref{-not}).
 
 @example
 @group
-(-filter (-orfn 'even? (-partial (-flip '<) 5)) '(1 2 3 4 5 6 7 8 9 10))
-    @result{} (1 2 3 4 6 8 10)
+(-filter (-orfn #'natnump #'booleanp) '(1 nil "a" -4 b c t))
+    @result{} (1 nil t)
+@end group
+@group
+(funcall (-orfn #'symbolp (-cut string-match-p "x" <>)) "axe")
+    @result{} 1
 @end group
 @group
-(funcall (-orfn 'stringp 'even?) "foo")
+(funcall (-orfn #'= #'+) 1 1)
     @result{} t
 @end group
 @end example
@@ -4487,24 +4536,27 @@ In types: [a -> Bool] -> a -> Bool
 
 @anchor{-andfn}
 @defun -andfn (&rest preds)
-Take list of unary predicates @var{preds} and return a unary
-predicate with argument x that returns non-nil if all of the
-@var{preds} returns non-nil on x.
+Return a predicate that returns non-nil if all @var{preds} do so.
+The returned predicate @var{p} takes a variable number of arguments and
+passes them to each predicate in @var{preds} in turn.  If any one of
+@var{preds} returns nil, @var{p} also returns nil without calling the
+remaining @var{preds}.  If all @var{preds} return non-nil, @var{p} returns the 
last
+such value.  If no @var{preds} are given, @var{p} always returns non-nil.
 
-In types: [a -> Bool] -> a -> Bool
+See also: @code{-orfn} (@pxref{-orfn}) and @code{-not} (@pxref{-not}).
 
 @example
 @group
-(funcall (-andfn (-cut < <> 10) 'even?) 6)
-    @result{} t
+(-filter (-andfn #'numberp (-cut < <> 5)) '(a 1 b 6 c 2))
+    @result{} (1 2)
 @end group
 @group
-(funcall (-andfn (-cut < <> 10) 'even?) 12)
-    @result{} nil
+(mapcar (-andfn #'numberp #'1+) '(a 1 b 6))
+    @result{} (nil 2 nil 7)
 @end group
 @group
-(-filter (-andfn (-not 'even?) (-cut >= 5 <>)) '(1 2 3 4 5 6 7 8 9 10))
-    @result{} (1 3 5)
+(funcall (-andfn #'= #'+) 1 1)
+    @result{} 2
 @end group
 @end example
 @end defun
diff --git a/dev/examples.el b/dev/examples.el
index d5d5210..0125da2 100644
--- a/dev/examples.el
+++ b/dev/examples.el
@@ -871,15 +871,15 @@ value rather than consuming a list to produce a single 
value."
     (-partition-after-pred #'booleanp '(t)) => '((t))
     (-partition-after-pred #'booleanp '(0 t)) => '((0 t))
     (--partition-after-pred (= (% it 2) 0) '()) => '()
-    (--partition-after-pred (= (% it 2) 1) '()) => '()
+    (--partition-after-pred (= (mod it 2) 1) '()) => '()
     (--partition-after-pred (= (% it 2) 0) '(0)) => '((0))
-    (--partition-after-pred (= (% it 2) 1) '(0)) => '((0))
+    (--partition-after-pred (= (mod it 2) 1) '(0)) => '((0))
     (--partition-after-pred (= (% it 2) 0) '(0 1)) => '((0) (1))
-    (--partition-after-pred (= (% it 2) 1) '(0 1)) => '((0 1))
+    (--partition-after-pred (= (mod it 2) 1) '(0 1)) => '((0 1))
     (--partition-after-pred (= (% it 2) 0) '(0 1 2)) => '((0) (1 2))
-    (--partition-after-pred (= (% it 2) 1) '(0 1 2)) => '((0 1) (2))
+    (--partition-after-pred (= (mod it 2) 1) '(0 1 2)) => '((0 1) (2))
     (--partition-after-pred (= (% it 2) 0) '(0 1 2 3)) => '((0) (1 2) (3))
-    (--partition-after-pred (= (% it 2) 1) '(0 1 2 3)) => '((0 1) (2 3))
+    (--partition-after-pred (= (mod it 2) 1) '(0 1 2 3)) => '((0 1) (2 3))
     (--partition-after-pred t '()) => ()
     (--partition-after-pred t '(0)) => '((0))
     (--partition-after-pred t '(0 1)) => '((0) (1))
@@ -1055,7 +1055,9 @@ related predicates."
     (-cons*) => ()
     (-cons* ()) => ()
     (-cons* 1 ()) => '(1)
-    (-cons* 1 '(2)) => '(1 2))
+    (-cons* 1 '(2)) => '(1 2)
+    ;; Assert that &rest conses a fresh list in case that ever changes.
+    (let ((l (list 1 2))) (apply #'-cons* l) l) => '(1 2))
 
   (defexamples -snoc
     (-snoc '(1 2 3) 4) => '(1 2 3 4)
@@ -1769,30 +1771,83 @@ or readability."
     => '((1 (1)) (1 (2)) (5 (5))))
 
   (defexamples -on
-    (-sort (-on '< 'length) '((1 2 3) (1) (1 2))) => '((1) (1 2) (1 2 3))
-    (-min-by (-on '> 'length) '((1 2 3) (4) (1 2))) => '(4)
-    (-min-by (-on 'string-lessp 'number-to-string) '(2 100 22)) => 22
-    (-max-by (-on '> 'car) '((2 2 3) (3) (1 2))) => '(3)
-    (-sort (-on 'string-lessp 'number-to-string) '(10 12 1 2 22)) => '(1 10 12 
2 22)
-    (funcall (-on '+ '1+) 1 2) => 5
-    (funcall (-on '+ 'identity) 1 2) => 3
-    (funcall (-on '* 'length) '(1 2 3) '(4 5)) => 6
-    (funcall (-on (-on '+ 'length) 'cdr) '(1 2 3) '(4 5)) => 3
-    (funcall (-on '+ (lambda (x) (length (cdr x)))) '(1 2 3) '(4 5)) => 3
-    (-sort (-on '< 'car) '((3 2 5) (2) (1 2))) => '((1 2) (2) (3 2 5))
-    (-sort (-on '< (lambda (x) (length x))) '((1 2 3) (1) (1 2))) => '((1) (1 
2) (1 2 3))
-    (-sort (-on (-on '< 'car) 'cdr) '((0 3) (2 1) (4 2 8))) => '((2 1) (4 2 8) 
(0 3))
-    (-sort (-on '< 'cadr) '((0 3) (2 1) (4 2 8))) => '((2 1) (4 2 8) (0 3)))
+    (-sort (-on #'< #'length) '((1 2 3) (1) (1 2))) => '((1) (1 2) (1 2 3))
+    (funcall (-on #'min #'string-to-number) "22" "2" "1" "12") => 1
+    (-min-by (-on #'> #'length) '((1 2 3) (4) (1 2))) => '(4)
+    (-min-by (-on #'string< #'number-to-string) '(2 100 22)) => 22
+    (-max-by (-on #'> #'car) '((2 2 3) (3) (1 2))) => '(3)
+    (-sort (-on #'string< #'number-to-string) '(12 1 2 22)) => '(1 12 2 22)
+    (funcall (-on #'+ #'1+) 1 2) => 5
+    (funcall (-on #'+ #'identity) 1 2) => 3
+    (funcall (-on #'* #'length) '(1 2 3) '(4 5)) => 6
+    (funcall (-on (-on #'+ #'length) #'cdr) '(1 2 3) '(4 5)) => 3
+    (funcall (-on #'+ (lambda (x) (length (cdr x)))) '(1 2 3) '(4 5)) => 3
+    (-sort (-on #'< #'car) '((3 2 5) (2) (1 2))) => '((1 2) (2) (3 2 5))
+    (-sort (-on #'< (lambda (x) (length x))) '((1 2 3) (1) (1 2)))
+    => '((1) (1 2) (1 2 3))
+    (-sort (-on (-on #'< #'car) #'cdr) '((0 3) (2 1) (4 2 8)))
+    => '((2 1) (4 2 8) (0 3))
+    (-sort (-on #'< #'cadr) '((0 3) (2 1) (4 2 8))) => '((2 1) (4 2 8) (0 3))
+    (funcall (-on #'not #'not) nil) => nil
+    (funcall (-on #'+ #'1+) 1 10 100 1000) => 1115
+    (funcall (-on #'+ #'1+) 1 10 100) => 114
+    (funcall (-on #'+ #'1+) 1 10) => 13
+    (funcall (-on #'+ #'1+) 1) => 2
+    (funcall (-on #'+ #'1+)) => 0
+    (funcall (-on #'1+ #'1+) 0) => 2
+    (funcall (-on #'+ #'*)) => 0
+    (funcall (-on #'* #'+)) => 1)
 
   (defexamples -flip
-    (funcall (-flip '<) 2 1) => t
-    (funcall (-flip '-) 3 8) => 5
-    (-sort (-flip '<) '(4 3 6 1)) => '(6 4 3 1))
+    (-sort (-flip #'<) '(4 3 6 1)) => '(6 4 3 1)
+    (funcall (-flip #'-) 3 2 1 10) => 4
+    (funcall (-flip #'1+) 1) => 2
+    (funcall (-flip #'<) 2 1) => t
+    (funcall (-flip #'list) 1 2 3) => '(3 2 1)
+    (funcall (-flip #'list) 1 2) => '(2 1)
+    (funcall (-flip #'list) 1) => '(1)
+    (funcall (-flip #'list)) => '()
+    ;; Assert that &rest conses a fresh list in case that ever changes.
+    (let ((a (list 1 2 3 4))) (apply (-flip #'-) a) a) => '(1 2 3 4))
+
+  (defexamples -rotate-args
+    (funcall (-rotate-args -1 #'list) 1 2 3 4) => '(2 3 4 1)
+    (funcall (-rotate-args 1 #'-) 1 10 100) => 89
+    (funcall (-rotate-args 2 #'list) 3 4 5 1 2) => '(1 2 3 4 5)
+    (funcall (-rotate-args -2 #'list) 1 2 3 4) => '(3 4 1 2)
+    (funcall (-rotate-args 0 #'list) 1 2 3 4) => '(1 2 3 4)
+    (funcall (-rotate-args 1 #'list) 1 2 3 4) => '(4 1 2 3)
+    (funcall (-rotate-args 2 #'list) 1 2 3 4) => '(3 4 1 2)
+    (funcall (-rotate-args -2 #'list) 1 2 3) => '(3 1 2)
+    (funcall (-rotate-args -1 #'list) 1 2 3) => '(2 3 1)
+    (funcall (-rotate-args 0 #'list) 1 2 3) => '(1 2 3)
+    (funcall (-rotate-args 1 #'list) 1 2 3) => '(3 1 2)
+    (funcall (-rotate-args 2 #'list) 1 2 3) => '(2 3 1)
+    (funcall (-rotate-args -2 #'list) 1 2) => '(1 2)
+    (funcall (-rotate-args -1 #'list) 1 2) => '(2 1)
+    (funcall (-rotate-args 0 #'list) 1 2) => '(1 2)
+    (funcall (-rotate-args 1 #'list) 1 2) => '(2 1)
+    (funcall (-rotate-args 2 #'list) 1 2) => '(1 2)
+    (funcall (-rotate-args -2 #'list) 1) => '(1)
+    (funcall (-rotate-args -1 #'list) 1) => '(1)
+    (funcall (-rotate-args 0 #'list) 1) => '(1)
+    (funcall (-rotate-args 1 #'list) 1) => '(1)
+    (funcall (-rotate-args 2 #'list) 1) => '(1)
+    (funcall (-rotate-args -2 #'list)) => '()
+    (funcall (-rotate-args -1 #'list)) => '()
+    (funcall (-rotate-args 0 #'list)) => '()
+    (funcall (-rotate-args 1 #'list)) => '()
+    (funcall (-rotate-args 2 #'list)) => '()
+    (let ((a (list 1 2 3))) (apply (-rotate-args 2 #'-) a) a) => '(1 2 3))
 
   (defexamples -const
     (funcall (-const 2) 1 3 "foo") => 2
-    (-map (-const 1) '("a" "b" "c" "d")) => '(1 1 1 1)
-    (-sum (-map (-const 1) '("a" "b" "c" "d"))) => 4)
+    (mapcar (-const 1) '("a" "b" "c" "d")) => '(1 1 1 1)
+    (-sum (mapcar (-const 1) '("a" "b" "c" "d"))) => 4
+    (funcall (-const t)) => t
+    (funcall (-const nil)) => nil
+    (funcall (-const t) nil) => t
+    (funcall (-const nil) nil) => nil)
 
   (defexamples -cut
     (funcall (-cut list 1 <> 3 <> 5) 2 4) => '(1 2 3 4 5)
@@ -1801,17 +1856,57 @@ or readability."
     (-filter (-cut < <> 5) '(1 3 5 7 9)) => '(1 3))
 
   (defexamples -not
-    (funcall (-not 'even?) 5) => t
-    (-filter (-not (-partial '< 4)) '(1 2 3 4 5 6 7 8)) => '(1 2 3 4))
+    (funcall (-not #'numberp) "5") => t
+    (-sort (-not #'<) '(5 2 1 0 6)) => '(6 5 2 1 0)
+    (-filter (-not (-partial #'< 4)) '(1 2 3 4 5 6 7 8)) => '(1 2 3 4)
+    ;; Variadic `<' was introduced in Emacs 24.4.
+    (funcall (-not (lambda (a b c) (and (< a b) (< b c)))) 1 2 3) => nil
+    (funcall (-not (lambda (a b c) (and (< a b) (< b c)))) 3 2 1) => t
+    (funcall (-not #'<) 1 2) => nil
+    (funcall (-not #'<) 2 1) => t
+    (funcall (-not #'+) 1) => nil
+    (funcall (-not #'+)) => nil)
 
   (defexamples -orfn
-    (-filter (-orfn 'even? (-partial (-flip '<) 5)) '(1 2 3 4 5 6 7 8 9 10)) 
=> '(1 2 3 4 6 8 10)
-    (funcall (-orfn 'stringp 'even?) "foo") => t)
+    (-filter (-orfn #'natnump #'booleanp) '(1 nil "a" -4 b c t)) => '(1 nil t)
+    (funcall (-orfn #'symbolp (-cut string-match-p "x" <>)) "axe") => 1
+    (funcall (-orfn #'= #'+) 1 1) => t
+    (funcall (-orfn #'+ #'null)) => 0
+    (funcall (-orfn #'+ #'null) 1) => 1
+    (funcall (-orfn #'+ #'null) 1 2) => 3
+    (funcall (-orfn #'+ #'null) 1 2 3) => 6
+    (funcall (-orfn #'ignore #'+)) => 0
+    (funcall (-orfn #'ignore #'+) 1) => 1
+    (funcall (-orfn #'ignore #'+) 1 2) => 3
+    (funcall (-orfn #'ignore #'+) 1 2 3) => 6
+    (-filter (-orfn #'symbolp) '(a b 1 nil t 2)) => '(a b nil t)
+    (-filter (-orfn #'null) '(a b 1 nil t 2)) => '(nil)
+    (-filter (-orfn) '(nil t)) => '()
+    (-orfn #'null) => #'null
+    (-orfn) => #'ignore)
 
   (defexamples -andfn
-    (funcall (-andfn (-cut < <> 10) 'even?) 6) => t
-    (funcall (-andfn (-cut < <> 10) 'even?) 12) => nil
-    (-filter (-andfn (-not 'even?) (-cut >= 5 <>)) '(1 2 3 4 5 6 7 8 9 10)) => 
'(1 3 5))
+    (-filter (-andfn #'numberp (-cut < <> 5)) '(a 1 b 6 c 2)) => '(1 2)
+    (mapcar (-andfn #'numberp #'1+) '(a 1 b 6)) => '(nil 2 nil 7)
+    (funcall (-andfn #'= #'+) 1 1) => 2
+    (funcall (-andfn #'ignore #'+)) => nil
+    (funcall (-andfn #'ignore #'+) 1) => nil
+    (funcall (-andfn #'ignore #'+) 1 2) => nil
+    (funcall (-andfn #'+ #'ignore)) => nil
+    (funcall (-andfn #'+ #'ignore) 1) => nil
+    (funcall (-andfn #'+ #'ignore) 1 2) => nil
+    (funcall (-andfn #'+ #'list)) => '()
+    (funcall (-andfn #'+ #'list) 1) => '(1)
+    (funcall (-andfn #'+ #'list) 1 2) => '(1 2)
+    (funcall (-andfn #'list #'+)) => nil
+    (funcall (-andfn #'list #'+) 1) => 1
+    (funcall (-andfn #'list #'+) 1 2) => 3
+    (funcall (-andfn #'* #'+)) => 0
+    (funcall (-andfn #'+ #'*)) => 1
+    (-andfn #'null) => #'null
+    (funcall (-andfn)) => t
+    (funcall (-andfn) nil) => t
+    (funcall (-andfn) t) => t)
 
   (defexamples -iteratefn
     (funcall (-iteratefn (lambda (x) (* x x)) 3) 2) => 256



reply via email to

[Prev in Thread] Current Thread [Next in Thread]