Improve -rpartial, -juxt, and -compose

* dash.el (-rpartial, -juxt): Mark as pure and side-effect-free.
Fix docstrings.
(-compose): Ditto.  Optimize for speed.
* dev/examples.el (-rpartial, -juxt, -compose): Extend tests.

* README.md:
* dash.texi: Regenerate docs.
master
Basil L. Contovounesios 5 years ago
parent 1ca9d6b9b2
commit 5326ed8c9f
No known key found for this signature in database
GPG Key ID: 205AB54A5D5D8CFF
  1. 44
      README.md
  2. 42
      dash.el
  3. 60
      dash.texi
  4. 45
      dev/examples.el

@ -2811,40 +2811,44 @@ was called.
#### -rpartial `(fn &rest args)` #### -rpartial `(fn &rest args)`
Takes a function `fn` and fewer than the normal arguments to `fn`, Return a function that is a partial application of `fn` to `args`.
and returns a fn that takes a variable number of additional `args`. `args` is a list of the last `n` arguments to pass to `fn`. The result
When called, the returned function calls `fn` with the additional is a new function which does the same as `fn`, except that the last
args first and then `args`. `n` arguments are fixed at the values with which this function was
called. This is like [`-partial`](#-partial-fun-rest-args), except the arguments are fixed
starting from the right rather than the left.
```el ```el
(funcall (-rpartial '- 5) 8) ;; => 3 (funcall (-rpartial #'- 5)) ;; => -5
(funcall (-rpartial '- 5 2) 10) ;; => 3 (funcall (-rpartial #'- 5) 8) ;; => 3
(funcall (-rpartial #'- 5 2) 10) ;; => 3
``` ```
#### -juxt `(&rest fns)` #### -juxt `(&rest fns)`
Takes a list of functions and returns a fn that is the Return a function that is the juxtaposition of `fns`.
juxtaposition of those fns. The returned fn takes a variable The returned function takes a variable number of `args`, applies
number of args, and returns a list containing the result of each of `fns` in turn to `args`, and returns the list of results.
applying each fn to the args (left-to-right).
```el ```el
(funcall (-juxt '+ '-) 3 5) ;; => (8 -2) (funcall (-juxt) 1 2) ;; => ()
(-map (-juxt 'identity 'square) '(1 2 3)) ;; => ((1 1) (2 4) (3 9)) (funcall (-juxt #'+ #'- #'* #'/) 7 5) ;; => (12 2 35 1)
(mapcar (-juxt #'number-to-string #'1+) '(1 2)) ;; => (("1" 2) ("2" 3))
``` ```
#### -compose `(&rest fns)` #### -compose `(&rest fns)`
Takes a list of functions and returns a fn that is the Compose `fns` into a single composite function.
composition of those fns. The returned fn takes a variable Return a function that takes a variable number of `args`, applies
number of arguments, and returns the result of applying the last function in `fns` to `args`, and returns the result of
each fn to the result of applying the previous fn to calling each remaining function on the result of the previous
the arguments (right-to-left). function, right-to-left. If no `fns` are given, return a variadic
`identity` function.
```el ```el
(funcall (-compose 'square '+) 2 3) ;; => (square (+ 2 3)) (funcall (-compose #'- #'1+ #'+) 1 2 3) ;; => -7
(funcall (-compose 'identity 'square) 3) ;; => (square 3) (funcall (-compose #'identity #'1+) 3) ;; => 4
(funcall (-compose 'square 'identity) 3) ;; => (square 3) (mapcar (-compose #'not #'stringp) '(nil "")) ;; => (t nil)
``` ```
#### -applify `(fn)` #### -applify `(fn)`

@ -3002,28 +3002,38 @@ structure such as plist or alist."
(defalias '-partial #'apply-partially) (defalias '-partial #'apply-partially)
(defun -rpartial (fn &rest args) (defun -rpartial (fn &rest args)
"Takes a function FN and fewer than the normal arguments to FN, "Return a function that is a partial application of FN to ARGS.
and returns a fn that takes a variable number of additional ARGS. ARGS is a list of the last N arguments to pass to FN. The result
When called, the returned function calls FN with the additional is a new function which does the same as FN, except that the last
args first and then ARGS." N arguments are fixed at the values with which this function was
called. This is like `-partial', except the arguments are fixed
starting from the right rather than the left."
(declare (pure t) (side-effect-free t))
(lambda (&rest args-before) (apply fn (append args-before args)))) (lambda (&rest args-before) (apply fn (append args-before args))))
(defun -juxt (&rest fns) (defun -juxt (&rest fns)
"Takes a list of functions and returns a fn that is the "Return a function that is the juxtaposition of FNS.
juxtaposition of those fns. The returned fn takes a variable The returned function takes a variable number of ARGS, applies
number of args, and returns a list containing the result of each of FNS in turn to ARGS, and returns the list of results."
applying each fn to the args (left-to-right)." (declare (pure t) (side-effect-free t))
(lambda (&rest args) (mapcar (lambda (x) (apply x args)) fns))) (lambda (&rest args) (mapcar (lambda (x) (apply x args)) fns)))
(defun -compose (&rest fns) (defun -compose (&rest fns)
"Takes a list of functions and returns a fn that is the "Compose FNS into a single composite function.
composition of those fns. The returned fn takes a variable Return a function that takes a variable number of ARGS, applies
number of arguments, and returns the result of applying the last function in FNS to ARGS, and returns the result of
each fn to the result of applying the previous fn to calling each remaining function on the result of the previous
the arguments (right-to-left)." function, right-to-left. If no FNS are given, return a variadic
(lambda (&rest args) `identity' function."
(car (-reduce-r-from (lambda (fn xs) (list (apply fn xs))) (declare (pure t) (side-effect-free t))
args fns)))) (let* ((fns (nreverse fns))
(head (car fns))
(tail (cdr fns)))
(cond (tail
(lambda (&rest args)
(--reduce-from (funcall it acc) (apply head args) tail)))
(fns head)
((lambda (&optional arg &rest _) arg)))))
(defun -applify (fn) (defun -applify (fn)
"Return a function that applies FN to a single list of args. "Return a function that applies FN to a single list of args.

@ -4226,18 +4226,24 @@ was called.
@anchor{-rpartial} @anchor{-rpartial}
@defun -rpartial (fn &rest args) @defun -rpartial (fn &rest args)
Takes a function @var{fn} and fewer than the normal arguments to @var{fn}, Return a function that is a partial application of @var{fn} to @var{args}.
and returns a fn that takes a variable number of additional @var{args}. @var{args} is a list of the last @var{n} arguments to pass to @var{fn}. The result
When called, the returned function calls @var{fn} with the additional is a new function which does the same as @var{fn}, except that the last
args first and then @var{args}. @var{n} arguments are fixed at the values with which this function was
called. This is like @code{-partial} (@pxref{-partial}), except the arguments are fixed
starting from the right rather than the left.
@example @example
@group @group
(funcall (-rpartial '- 5) 8) (funcall (-rpartial #'- 5))
@result{} -5
@end group
@group
(funcall (-rpartial #'- 5) 8)
@result{} 3 @result{} 3
@end group @end group
@group @group
(funcall (-rpartial '- 5 2) 10) (funcall (-rpartial #'- 5 2) 10)
@result{} 3 @result{} 3
@end group @end group
@end example @end example
@ -4245,43 +4251,47 @@ args first and then @var{args}.
@anchor{-juxt} @anchor{-juxt}
@defun -juxt (&rest fns) @defun -juxt (&rest fns)
Takes a list of functions and returns a fn that is the Return a function that is the juxtaposition of @var{fns}.
juxtaposition of those fns. The returned fn takes a variable The returned function takes a variable number of @var{args}, applies
number of args, and returns a list containing the result of each of @var{fns} in turn to @var{args}, and returns the list of results.
applying each fn to the args (left-to-right).
@example @example
@group @group
(funcall (-juxt '+ '-) 3 5) (funcall (-juxt) 1 2)
@result{} (8 -2) @result{} ()
@end group
@group
(funcall (-juxt #'+ #'- #'* #'/) 7 5)
@result{} (12 2 35 1)
@end group @end group
@group @group
(-map (-juxt 'identity 'square) '(1 2 3)) (mapcar (-juxt #'number-to-string #'1+) '(1 2))
@result{} ((1 1) (2 4) (3 9)) @result{} (("1" 2) ("2" 3))
@end group @end group
@end example @end example
@end defun @end defun
@anchor{-compose} @anchor{-compose}
@defun -compose (&rest fns) @defun -compose (&rest fns)
Takes a list of functions and returns a fn that is the Compose @var{fns} into a single composite function.
composition of those fns. The returned fn takes a variable Return a function that takes a variable number of @var{args}, applies
number of arguments, and returns the result of applying the last function in @var{fns} to @var{args}, and returns the result of
each fn to the result of applying the previous fn to calling each remaining function on the result of the previous
the arguments (right-to-left). function, right-to-left. If no @var{fns} are given, return a variadic
@code{identity} function.
@example @example
@group @group
(funcall (-compose 'square '+) 2 3) (funcall (-compose #'- #'1+ #'+) 1 2 3)
@result{} (square (+ 2 3)) @result{} -7
@end group @end group
@group @group
(funcall (-compose 'identity 'square) 3) (funcall (-compose #'identity #'1+) 3)
@result{} (square 3) @result{} 4
@end group @end group
@group @group
(funcall (-compose 'square 'identity) 3) (mapcar (-compose #'not #'stringp) '(nil ""))
@result{} (square 3) @result{} (t nil)
@end group @end group
@end example @end example
@end defun @end defun

@ -1640,20 +1640,37 @@ or readability."
(funcall (-partial #'+) 5) => 5 (funcall (-partial #'+) 5) => 5
(apply (-partial #'+ 5) 10 '(1 2)) => 18) (apply (-partial #'+ 5) 10 '(1 2)) => 18)
(unless (version< emacs-version "24") (defexamples -rpartial
(defexamples -rpartial (funcall (-rpartial #'- 5)) => -5
(funcall (-rpartial '- 5) 8) => 3 (funcall (-rpartial #'- 5) 8) => 3
(funcall (-rpartial '- 5 2) 10) => 3) (funcall (-rpartial #'- 5 2) 10) => 3
(funcall (-rpartial #'-)) => 0
(defexamples -juxt (apply (-rpartial #'- 1) 2 '(20 3)) => -22)
(funcall (-juxt '+ '-) 3 5) => '(8 -2)
(-map (-juxt 'identity 'square) '(1 2 3)) => '((1 1) (2 4) (3 9))) (defexamples -juxt
(funcall (-juxt) 1 2) => '()
(defexamples -compose (funcall (-juxt #'+ #'- #'* #'/) 7 5) => '(12 2 35 1)
(funcall (-compose 'square '+) 2 3) => (square (+ 2 3)) (mapcar (-juxt #'number-to-string #'1+) '(1 2)) => '(("1" 2) ("2" 3))
(funcall (-compose 'identity 'square) 3) => (square 3) (funcall (-juxt #'+ #'-)) => '(0 0)
(funcall (-compose 'square 'identity) 3) => (square 3) (funcall (-juxt)) => '())
(funcall (-compose (-compose 'not 'even?) 'square) 3) => (funcall (-compose 'not (-compose 'even? 'square)) 3)))
(defexamples -compose
(funcall (-compose #'- #'1+ #'+) 1 2 3) => -7
(funcall (-compose #'identity #'1+) 3) => 4
(mapcar (-compose #'not #'stringp) '(nil "")) => '(t nil)
(funcall (-compose #'1+ #'identity) 3) => 4
(mapcar (lambda (fn)
(list (funcall fn 0) (funcall fn 1)))
(list (-compose (-compose #'natnump #'1+) #'lognot)
(-compose #'natnump (-compose #'1+ #'lognot))
(-compose #'natnump #'1+ #'lognot)))
=> '((t nil) (t nil) (t nil))
(funcall (-compose)) => nil
(funcall (-compose) nil) => nil
(funcall (-compose) nil 1) => nil
(funcall (-compose) 1) => 1
(funcall (-compose) 1 2) => 1
(-compose #'+) => #'+)
(defexamples -applify (defexamples -applify
(funcall (-applify #'+) ()) => 0 (funcall (-applify #'+) ()) => 0

Loading…
Cancel
Save