From 38dc929ac0c8a83993931e27a34b66797824b5ad Mon Sep 17 00:00:00 2001 From: "Basil L. Contovounesios" Date: Thu, 7 Jan 2021 14:38:37 +0000 Subject: [PATCH] Fix, improve, and extend anaphoric folds * dash.el (--reduce-from, -reduce-from, -reduce-r-from): Use consistent argument naming and extend docstring. (--reduce): Protect against unused lexical var warnings. Extend docstring. (-reduce, --reduce-r, -reduce-r): Improve docstring. (--reduce-r-from): Use --each-r for speed. Use consistent argument naming and extend docstring. (--reductions-from, --reductions, --reductions-r-from) (--reductions-r): New macros (#314). (-reductions-from): Use --reductions-from. Improve docstring. (-reductions): Use --reductions-from. Fix return value for empty list (#314). Improve docstring. (-reductions-r-from): Use --reductions-r-from. Improve docstring. (-reductions-r): Use --reductions-r. Fix return value for empty list (#314). Improve docstring. (dash--keywords): Add new macro names. * dev/examples.el (Reductions): Clarify description. (-reduce-from, -reduce-r-from, -reduce, -reduce-r, -reductions-from) (-reductions-r-from, -reductions, -reductions-r): Fix and simplify existing tests. Add new tests. * README.md: * dash.texi: Regenerate docs. --- README.md | 174 ++++++++++++++++++---------------- dash.el | 247 +++++++++++++++++++++++++++++++++--------------- dash.texi | 194 +++++++++++++++++++------------------ dev/examples.el | 120 +++++++++++++++-------- 4 files changed, 445 insertions(+), 290 deletions(-) diff --git a/README.md b/README.md index 780f941..0da87b5 100644 --- a/README.md +++ b/README.md @@ -151,10 +151,10 @@ Functions returning a modified copy of the input list. ### Reductions -Functions reducing lists into single value. +Functions reducing lists to a single value (which may also be a list). -* [-reduce-from](#-reduce-from-fn-initial-value-list) `(fn initial-value list)` -* [-reduce-r-from](#-reduce-r-from-fn-initial-value-list) `(fn initial-value list)` +* [-reduce-from](#-reduce-from-fn-init-list) `(fn init list)` +* [-reduce-r-from](#-reduce-r-from-fn-init-list) `(fn init list)` * [-reduce](#-reduce-fn-list) `(fn list)` * [-reduce-r](#-reduce-r-fn-list) `(fn list)` * [-reductions-from](#-reductions-from-fn-init-list) `(fn init list)` @@ -884,137 +884,149 @@ See also: [`-remove-at`](#-remove-at-n-list), [`-remove`](#-remove-pred-list) ## Reductions -Functions reducing lists into single value. +Functions reducing lists to a single value (which may also be a list). -#### -reduce-from `(fn initial-value list)` +#### -reduce-from `(fn init list)` -Return the result of applying `fn` to `initial-value` and the -first item in `list`, then applying `fn` to that result and the 2nd -item, etc. If `list` contains no items, return `initial-value` and -do not call `fn`. +Reduce the function `fn` across `list`, starting with `init`. +Return the result of applying `fn` to `init` and the first element of +`list`, then applying `fn` to that result and the second element, +etc. If `list` is empty, return `init` without calling `fn`. -In the anaphoric form `--reduce-from`, the accumulated value is -exposed as symbol `acc`. - -See also: [`-reduce`](#-reduce-fn-list), [`-reduce-r`](#-reduce-r-fn-list) +This function's anaphoric counterpart is `--reduce-from`. +For other folds, see also [`-reduce`](#-reduce-fn-list) and [`-reduce-r`](#-reduce-r-fn-list). ```el -(-reduce-from '- 10 '(1 2 3)) ;; => 4 -(-reduce-from (lambda (memo item) (format "(%s - %d)" memo item)) "10" '(1 2 3)) ;; => "(((10 - 1) - 2) - 3)" +(-reduce-from #'- 10 '(1 2 3)) ;; => 4 +(-reduce-from #'list 10 '(1 2 3)) ;; => '(((10 1) 2) 3) (--reduce-from (concat acc " " it) "START" '("a" "b" "c")) ;; => "START a b c" ``` -#### -reduce-r-from `(fn initial-value list)` +#### -reduce-r-from `(fn init list)` -Replace conses with `fn`, nil with `initial-value` and evaluate -the resulting expression. If `list` is empty, `initial-value` is -returned and `fn` is not called. +Reduce the function `fn` across `list` in reverse, starting with `init`. +Return the result of applying `fn` to the last element of `list` and +`init`, then applying `fn` to the second-to-last element and the +previous result of `fn`, etc. That is, the first argument of `fn` is +the current element, and its second argument the accumulated +value. If `list` is empty, return `init` without calling `fn`. -Note: this function works the same as [`-reduce-from`](#-reduce-from-fn-initial-value-list) but the -operation associates from right instead of from left. +This function is like [`-reduce-from`](#-reduce-from-fn-init-list) but the operation associates +from the right rather than left. In other words, it starts from +the end of `list` and flips the arguments to `fn`. Conceptually, it +is like replacing the conses in `list` with applications of `fn`, and +its last link with `init`, and evaluating the resulting expression. -See also: [`-reduce-r`](#-reduce-r-fn-list), [`-reduce`](#-reduce-fn-list) +This function's anaphoric counterpart is `--reduce-r-from`. +For other folds, see also [`-reduce-r`](#-reduce-r-fn-list) and [`-reduce`](#-reduce-fn-list). ```el -(-reduce-r-from '- 10 '(1 2 3)) ;; => -8 -(-reduce-r-from (lambda (item memo) (format "(%d - %s)" item memo)) "10" '(1 2 3)) ;; => "(1 - (2 - (3 - 10)))" +(-reduce-r-from #'- 10 '(1 2 3)) ;; => -8 +(-reduce-r-from #'list 10 '(1 2 3)) ;; => '(1 (2 (3 10))) (--reduce-r-from (concat it " " acc) "END" '("a" "b" "c")) ;; => "a b c END" ``` #### -reduce `(fn list)` -Return the result of applying `fn` to the first 2 items in `list`, -then applying `fn` to that result and the 3rd item, etc. If `list` -contains no items, return the result of calling `fn` with no -arguments. If `list` contains a single item, return that item -and do not call `fn`. - -In the anaphoric form `--reduce`, the accumulated value is -exposed as symbol `acc`. +Reduce the function `fn` across `list`. +Return the result of applying `fn` to the first two elements of +`list`, then applying `fn` to that result and the third element, etc. +If `list` contains a single element, return it without calling `fn`. +If `list` is empty, return the result of calling `fn` with no +arguments. -See also: [`-reduce-from`](#-reduce-from-fn-initial-value-list), [`-reduce-r`](#-reduce-r-fn-list) +This function's anaphoric counterpart is `--reduce`. +For other folds, see also [`-reduce-from`](#-reduce-from-fn-init-list) and [`-reduce-r`](#-reduce-r-fn-list). ```el -(-reduce '- '(1 2 3 4)) ;; => -8 -(-reduce 'list '(1 2 3 4)) ;; => '(((1 2) 3) 4) +(-reduce #'- '(1 2 3 4)) ;; => -8 +(-reduce #'list '(1 2 3 4)) ;; => '(((1 2) 3) 4) (--reduce (format "%s-%d" acc it) '(1 2 3)) ;; => "1-2-3" ``` #### -reduce-r `(fn list)` -Replace conses with `fn` and evaluate the resulting expression. -The final nil is ignored. If `list` contains no items, return the -result of calling `fn` with no arguments. If `list` contains a single -item, return that item and do not call `fn`. - -The first argument of `fn` is the new item, the second is the -accumulated value. +Reduce the function `fn` across `list` in reverse. +Return the result of applying `fn` to the last two elements of +`list`, then applying `fn` to the third-to-last element and the +previous result of `fn`, etc. That is, the first argument of `fn` is +the current element, and its second argument the accumulated +value. If `list` contains a single element, return it without +calling `fn`. If `list` is empty, return the result of calling `fn` +with no arguments. -Note: this function works the same as [`-reduce`](#-reduce-fn-list) but the operation -associates from right instead of from left. +This function is like [`-reduce`](#-reduce-fn-list) but the operation associates from +the right rather than left. In other words, it starts from the +end of `list` and flips the arguments to `fn`. Conceptually, it is +like replacing the conses in `list` with applications of `fn`, +ignoring its last link, and evaluating the resulting expression. -See also: [`-reduce-r-from`](#-reduce-r-from-fn-initial-value-list), [`-reduce`](#-reduce-fn-list) +This function's anaphoric counterpart is `--reduce-r`. +For other folds, see also [`-reduce-r-from`](#-reduce-r-from-fn-init-list) and [`-reduce`](#-reduce-fn-list). ```el -(-reduce-r '- '(1 2 3 4)) ;; => -2 -(-reduce-r (lambda (item memo) (format "%s-%d" memo item)) '(1 2 3)) ;; => "3-2-1" +(-reduce-r #'- '(1 2 3 4)) ;; => -2 +(-reduce-r #'list '(1 2 3 4)) ;; => '(1 (2 (3 4))) (--reduce-r (format "%s-%d" acc it) '(1 2 3)) ;; => "3-2-1" ``` #### -reductions-from `(fn init list)` -Return a list of the intermediate values of the reduction. - -See [`-reduce-from`](#-reduce-from-fn-initial-value-list) for explanation of the arguments. - -See also: [`-reductions`](#-reductions-fn-list), [`-reductions-r`](#-reductions-r-fn-list), [`-reduce-r`](#-reduce-r-fn-list) +Return a list of `fn``s intermediate reductions across `list`. +That is, a list of the intermediate values of the accumulator +when [`-reduce-from`](#-reduce-from-fn-init-list) (which see) is called with the same +arguments. +This function's anaphoric counterpart is `--reductions-from`. +For other folds, see also [`-reductions`](#-reductions-fn-list) and [`-reductions-r`](#-reductions-r-fn-list). ```el -(-reductions-from (lambda (a i) (format "(%s FN %d)" a i)) "INIT" '(1 2 3 4)) ;; => '("INIT" "(INIT FN 1)" "((INIT FN 1) FN 2)" "(((INIT FN 1) FN 2) FN 3)" "((((INIT FN 1) FN 2) FN 3) FN 4)") -(-reductions-from 'max 0 '(2 1 4 3)) ;; => '(0 2 2 4 4) -(-reductions-from '* 1 '(1 2 3 4)) ;; => '(1 1 2 6 24) +(-reductions-from #'max 0 '(2 1 4 3)) ;; => '(0 2 2 4 4) +(-reductions-from #'* 1 '(1 2 3 4)) ;; => '(1 1 2 6 24) +(--reductions-from (format "(FN %s %d)" acc it) "INIT" '(1 2 3)) ;; => '("INIT" "(FN INIT 1)" "(FN (FN INIT 1) 2)" "(FN (FN (FN INIT 1) 2) 3)") ``` #### -reductions-r-from `(fn init list)` -Return a list of the intermediate values of the reduction. - -See [`-reduce-r-from`](#-reduce-r-from-fn-initial-value-list) for explanation of the arguments. - -See also: [`-reductions-r`](#-reductions-r-fn-list), [`-reductions`](#-reductions-fn-list), [`-reduce`](#-reduce-fn-list) +Return a list of `fn``s intermediate reductions across reversed `list`. +That is, a list of the intermediate values of the accumulator +when [`-reduce-r-from`](#-reduce-r-from-fn-init-list) (which see) is called with the same +arguments. +This function's anaphoric counterpart is `--reductions-r-from`. +For other folds, see also [`-reductions`](#-reductions-fn-list) and [`-reductions-r`](#-reductions-r-fn-list). ```el -(-reductions-r-from (lambda (i a) (format "(%d FN %s)" i a)) "INIT" '(1 2 3 4)) ;; => '("(1 FN (2 FN (3 FN (4 FN INIT))))" "(2 FN (3 FN (4 FN INIT)))" "(3 FN (4 FN INIT))" "(4 FN INIT)" "INIT") -(-reductions-r-from 'max 0 '(2 1 4 3)) ;; => '(4 4 4 3 0) -(-reductions-r-from '* 1 '(1 2 3 4)) ;; => '(24 24 12 4 1) +(-reductions-r-from #'max 0 '(2 1 4 3)) ;; => '(4 4 4 3 0) +(-reductions-r-from #'* 1 '(1 2 3 4)) ;; => '(24 24 12 4 1) +(--reductions-r-from (format "(FN %d %s)" it acc) "INIT" '(1 2 3)) ;; => '("(FN 1 (FN 2 (FN 3 INIT)))" "(FN 2 (FN 3 INIT))" "(FN 3 INIT)" "INIT") ``` #### -reductions `(fn list)` -Return a list of the intermediate values of the reduction. - -See [`-reduce`](#-reduce-fn-list) for explanation of the arguments. - -See also: [`-reductions-from`](#-reductions-from-fn-init-list), [`-reductions-r`](#-reductions-r-fn-list), [`-reduce-r`](#-reduce-r-fn-list) +Return a list of `fn``s intermediate reductions across `list`. +That is, a list of the intermediate values of the accumulator +when [`-reduce`](#-reduce-fn-list) (which see) is called with the same arguments. +This function's anaphoric counterpart is `--reductions`. +For other folds, see also [`-reductions`](#-reductions-fn-list) and [`-reductions-r`](#-reductions-r-fn-list). ```el -(-reductions (lambda (a i) (format "(%s FN %d)" a i)) '(1 2 3 4)) ;; => '(1 "(1 FN 2)" "((1 FN 2) FN 3)" "(((1 FN 2) FN 3) FN 4)") -(-reductions '+ '(1 2 3 4)) ;; => '(1 3 6 10) -(-reductions '* '(1 2 3 4)) ;; => '(1 2 6 24) +(-reductions #'+ '(1 2 3 4)) ;; => '(1 3 6 10) +(-reductions #'* '(1 2 3 4)) ;; => '(1 2 6 24) +(--reductions (format "(FN %s %d)" acc it) '(1 2 3)) ;; => '(1 "(FN 1 2)" "(FN (FN 1 2) 3)") ``` #### -reductions-r `(fn list)` -Return a list of the intermediate values of the reduction. - -See [`-reduce-r`](#-reduce-r-fn-list) for explanation of the arguments. - -See also: [`-reductions-r-from`](#-reductions-r-from-fn-init-list), [`-reductions`](#-reductions-fn-list), [`-reduce`](#-reduce-fn-list) +Return a list of `fn``s intermediate reductions across reversed `list`. +That is, a list of the intermediate values of the accumulator +when [`-reduce-r`](#-reduce-r-fn-list) (which see) is called with the same arguments. +This function's anaphoric counterpart is `--reductions-r`. +For other folds, see also [`-reductions-r-from`](#-reductions-r-from-fn-init-list) and +[`-reductions`](#-reductions-fn-list). ```el -(-reductions-r (lambda (i a) (format "(%d FN %s)" i a)) '(1 2 3 4)) ;; => '("(1 FN (2 FN (3 FN 4)))" "(2 FN (3 FN 4))" "(3 FN 4)" 4) -(-reductions-r '+ '(1 2 3 4)) ;; => '(10 9 7 4) -(-reductions-r '* '(1 2 3 4)) ;; => '(24 24 12 4) +(-reductions-r #'+ '(1 2 3 4)) ;; => '(10 9 7 4) +(-reductions-r #'* '(1 2 3 4)) ;; => '(24 24 12 4) +(--reductions-r (format "(FN %d %s)" it acc) '(1 2 3)) ;; => '("(FN 1 (FN 2 3))" "(FN 2 3)" 3) ``` #### -count `(pred list)` @@ -2142,7 +2154,7 @@ If elements of `tree` are lists themselves, apply `fn` recursively to elements of these nested lists. Then reduce the resulting lists using `folder` and initial value -`init-value`. See [`-reduce-r-from`](#-reduce-r-from-fn-initial-value-list). +`init-value`. See [`-reduce-r-from`](#-reduce-r-from-fn-init-list). This is the same as calling [`-tree-reduce`](#-tree-reduce-fn-tree) after [`-tree-map`](#-tree-map-fn-tree) but is twice as fast as it only traverse the structure once. @@ -2160,7 +2172,7 @@ If elements of `tree` are lists themselves, apply `fn` recursively to elements of these nested lists. Then reduce the resulting lists using `folder` and initial value -`init-value`. See [`-reduce-r-from`](#-reduce-r-from-fn-initial-value-list). +`init-value`. See [`-reduce-r-from`](#-reduce-r-from-fn-init-list). This is the same as calling [`-tree-reduce-from`](#-tree-reduce-from-fn-init-value-tree) after [`-tree-map`](#-tree-map-fn-tree) but is twice as fast as it only traverse the structure once. diff --git a/dash.el b/dash.el index 2303681..2b40bd7 100644 --- a/dash.el +++ b/dash.el @@ -216,122 +216,211 @@ This is the anaphoric counterpart to `-map'." (push ,form ,r)) (nreverse ,r)))) -(defmacro --reduce-from (form initial-value list) - "Anaphoric form of `-reduce-from'." +(defmacro --reduce-from (form init list) + "Accumulate a value by evaluating FORM across LIST. +This macro is like `--each' (which see), but it additionally +provides an accumulator variable `acc' which it successively +binds to the result of evaluating FORM for the current LIST +element before processing the next element. For the first +element, `acc' is initialized with the result of evaluating INIT. +The return value is the resulting value of `acc'. If LIST is +empty, FORM is not evaluated, and the return value is the result +of INIT. +This is the anaphoric counterpart to `-reduce-from'." (declare (debug (form form form))) - `(let ((acc ,initial-value)) + `(let ((acc ,init)) (--each ,list (setq acc ,form)) acc)) -(defun -reduce-from (fn initial-value list) - "Return the result of applying FN to INITIAL-VALUE and the -first item in LIST, then applying FN to that result and the 2nd -item, etc. If LIST contains no items, return INITIAL-VALUE and -do not call FN. +(defun -reduce-from (fn init list) + "Reduce the function FN across LIST, starting with INIT. +Return the result of applying FN to INIT and the first element of +LIST, then applying FN to that result and the second element, +etc. If LIST is empty, return INIT without calling FN. -In the anaphoric form `--reduce-from', the accumulated value is -exposed as symbol `acc'. - -See also: `-reduce', `-reduce-r'" - (--reduce-from (funcall fn acc it) initial-value list)) +This function's anaphoric counterpart is `--reduce-from'. +For other folds, see also `-reduce' and `-reduce-r'." + (--reduce-from (funcall fn acc it) init list)) (defmacro --reduce (form list) - "Anaphoric form of `-reduce'." + "Accumulate a value by evaluating FORM across LIST. +This macro is like `--reduce-from' (which see), except the first +element of LIST is taken as INIT. Thus if LIST contains a single +item, it is returned without evaluating FORM. If LIST is empty, +FORM is evaluated with `it' and `acc' bound to nil. +This is the anaphoric counterpart to `-reduce'." (declare (debug (form form))) (let ((lv (make-symbol "list-value"))) `(let ((,lv ,list)) (if ,lv (--reduce-from ,form (car ,lv) (cdr ,lv)) - (let (acc it) ,form))))) + (let (acc it) + (ignore acc it) + ,form))))) (defun -reduce (fn list) - "Return the result of applying FN to the first 2 items in LIST, -then applying FN to that result and the 3rd item, etc. If LIST -contains no items, return the result of calling FN with no -arguments. If LIST contains a single item, return that item -and do not call FN. - -In the anaphoric form `--reduce', the accumulated value is -exposed as symbol `acc'. - -See also: `-reduce-from', `-reduce-r'" + "Reduce the function FN across LIST. +Return the result of applying FN to the first two elements of +LIST, then applying FN to that result and the third element, etc. +If LIST contains a single element, return it without calling FN. +If LIST is empty, return the result of calling FN with no +arguments. + +This function's anaphoric counterpart is `--reduce'. +For other folds, see also `-reduce-from' and `-reduce-r'." (if list (-reduce-from fn (car list) (cdr list)) (funcall fn))) -(defmacro --reduce-r-from (form initial-value list) - "Anaphoric version of `-reduce-r-from'." +(defmacro --reduce-r-from (form init list) + "Accumulate a value by evaluating FORM across LIST in reverse. +This macro is like `--reduce-from', except it starts from the end +of LIST. +This is the anaphoric counterpart to `-reduce-r-from'." (declare (debug (form form form))) - `(--reduce-from ,form ,initial-value (reverse ,list))) + `(let ((acc ,init)) + (--each-r ,list (setq acc ,form)) + acc)) -(defun -reduce-r-from (fn initial-value list) - "Replace conses with FN, nil with INITIAL-VALUE and evaluate -the resulting expression. If LIST is empty, INITIAL-VALUE is -returned and FN is not called. +(defun -reduce-r-from (fn init list) + "Reduce the function FN across LIST in reverse, starting with INIT. +Return the result of applying FN to the last element of LIST and +INIT, then applying FN to the second-to-last element and the +previous result of FN, etc. That is, the first argument of FN is +the current element, and its second argument the accumulated +value. If LIST is empty, return INIT without calling FN. -Note: this function works the same as `-reduce-from' but the -operation associates from right instead of from left. +This function is like `-reduce-from' but the operation associates +from the right rather than left. In other words, it starts from +the end of LIST and flips the arguments to FN. Conceptually, it +is like replacing the conses in LIST with applications of FN, and +its last link with INIT, and evaluating the resulting expression. -See also: `-reduce-r', `-reduce'" - (--reduce-r-from (funcall fn it acc) initial-value list)) +This function's anaphoric counterpart is `--reduce-r-from'. +For other folds, see also `-reduce-r' and `-reduce'." + (--reduce-r-from (funcall fn it acc) init list)) (defmacro --reduce-r (form list) - "Anaphoric version of `-reduce-r'." + "Accumulate a value by evaluating FORM across LIST in reverse order. +This macro is like `--reduce', except it starts from the end of +LIST. +This is the anaphoric counterpart to `-reduce-r'." (declare (debug (form form))) `(--reduce ,form (reverse ,list))) (defun -reduce-r (fn list) - "Replace conses with FN and evaluate the resulting expression. -The final nil is ignored. If LIST contains no items, return the -result of calling FN with no arguments. If LIST contains a single -item, return that item and do not call FN. - -The first argument of FN is the new item, the second is the -accumulated value. - -Note: this function works the same as `-reduce' but the operation -associates from right instead of from left. - -See also: `-reduce-r-from', `-reduce'" + "Reduce the function FN across LIST in reverse. +Return the result of applying FN to the last two elements of +LIST, then applying FN to the third-to-last element and the +previous result of FN, etc. That is, the first argument of FN is +the current element, and its second argument the accumulated +value. If LIST contains a single element, return it without +calling FN. If LIST is empty, return the result of calling FN +with no arguments. + +This function is like `-reduce' but the operation associates from +the right rather than left. In other words, it starts from the +end of LIST and flips the arguments to FN. Conceptually, it is +like replacing the conses in LIST with applications of FN, +ignoring its last link, and evaluating the resulting expression. + +This function's anaphoric counterpart is `--reduce-r'. +For other folds, see also `-reduce-r-from' and `-reduce'." (if list (--reduce-r (funcall fn it acc) list) (funcall fn))) -(defun -reductions-from (fn init list) - "Return a list of the intermediate values of the reduction. - -See `-reduce-from' for explanation of the arguments. +(defmacro --reductions-from (form init list) + "Return a list of FORM's intermediate reductions across LIST. +That is, a list of the intermediate values of the accumulator +when `--reduce-from' (which see) is called with the same +arguments. +This is the anaphoric counterpart to `-reductions-from'." + (declare (debug (form form form))) + `(nreverse + (--reduce-from (cons (let ((acc (car acc))) (ignore acc) ,form) acc) + (list ,init) + ,list))) -See also: `-reductions', `-reductions-r', `-reduce-r'" - (nreverse (--reduce-from (cons (funcall fn (car acc) it) acc) (list init) list))) +(defun -reductions-from (fn init list) + "Return a list of FN's intermediate reductions across LIST. +That is, a list of the intermediate values of the accumulator +when `-reduce-from' (which see) is called with the same +arguments. +This function's anaphoric counterpart is `--reductions-from'. +For other folds, see also `-reductions' and `-reductions-r'." + (--reductions-from (funcall fn acc it) init list)) + +(defmacro --reductions (form list) + "Return a list of FORM's intermediate reductions across LIST. +That is, a list of the intermediate values of the accumulator +when `--reduce' (which see) is called with the same arguments. +This is the anaphoric counterpart to `-reductions'." + (declare (debug (form form))) + (let ((lv (make-symbol "list-value"))) + `(let ((,lv ,list)) + (if ,lv + (--reductions-from ,form (car ,lv) (cdr ,lv)) + (let (acc it) + (ignore acc it) + (list ,form)))))) (defun -reductions (fn list) - "Return a list of the intermediate values of the reduction. - -See `-reduce' for explanation of the arguments. - -See also: `-reductions-from', `-reductions-r', `-reduce-r'" - (and list (-reductions-from fn (car list) (cdr list)))) + "Return a list of FN's intermediate reductions across LIST. +That is, a list of the intermediate values of the accumulator +when `-reduce' (which see) is called with the same arguments. +This function's anaphoric counterpart is `--reductions'. +For other folds, see also `-reductions' and `-reductions-r'." + (if list + (--reductions-from (funcall fn acc it) (car list) (cdr list)) + (list (funcall fn)))) + +(defmacro --reductions-r-from (form init list) + "Return a list of FORM's intermediate reductions across reversed LIST. +That is, a list of the intermediate values of the accumulator +when `--reduce-r-from' (which see) is called with the same +arguments. +This is the anaphoric counterpart to `-reductions-r-from'." + (declare (debug (form form form))) + `(--reduce-r-from (cons (let ((acc (car acc))) (ignore acc) ,form) acc) + (list ,init) + ,list)) (defun -reductions-r-from (fn init list) - "Return a list of the intermediate values of the reduction. - -See `-reduce-r-from' for explanation of the arguments. - -See also: `-reductions-r', `-reductions', `-reduce'" - (--reduce-r-from (cons (funcall fn it (car acc)) acc) (list init) list)) + "Return a list of FN's intermediate reductions across reversed LIST. +That is, a list of the intermediate values of the accumulator +when `-reduce-r-from' (which see) is called with the same +arguments. +This function's anaphoric counterpart is `--reductions-r-from'. +For other folds, see also `-reductions' and `-reductions-r'." + (--reductions-r-from (funcall fn it acc) init list)) + +(defmacro --reductions-r (form list) + "Return a list of FORM's intermediate reductions across reversed LIST. +That is, a list of the intermediate values of the accumulator +when `--reduce-re' (which see) is called with the same arguments. +This is the anaphoric counterpart to `-reductions-r'." + (declare (debug (form list))) + (let ((lv (make-symbol "list-value"))) + `(let ((,lv (reverse ,list))) + (if ,lv + (--reduce-from (cons (let ((acc (car acc))) (ignore acc) ,form) acc) + (list (car ,lv)) + (cdr ,lv)) + (let (acc it) + (ignore acc it) + (list ,form)))))) (defun -reductions-r (fn list) - "Return a list of the intermediate values of the reduction. - -See `-reduce-r' for explanation of the arguments. - -See also: `-reductions-r-from', `-reductions', `-reduce'" - (when list - (let ((rev (reverse list))) - (--reduce-from (cons (funcall fn it (car acc)) acc) - (list (car rev)) - (cdr rev))))) + "Return a list of FN's intermediate reductions across reversed LIST. +That is, a list of the intermediate values of the accumulator +when `-reduce-r' (which see) is called with the same arguments. +This function's anaphoric counterpart is `--reductions-r'. +For other folds, see also `-reductions-r-from' and +`-reductions'." + (if list + (--reductions-r (funcall fn it acc) list) + (list (funcall fn)))) (defmacro --filter (form list) "Anaphoric form of `-filter'. @@ -2851,6 +2940,10 @@ structure such as plist or alist." "--reduce-from" "--reduce-r" "--reduce-r-from" + "--reductions" + "--reductions-from" + "--reductions-r" + "--reductions-r-from" "--remove" "--remove-first" "--remove-last" diff --git a/dash.texi b/dash.texi index bf1bd7b..c93dd34 100644 --- a/dash.texi +++ b/dash.texi @@ -1117,29 +1117,27 @@ See also: @code{-remove-at} (@pxref{-remove-at}), @code{-remove} (@pxref{-remove @section Reductions -Functions reducing lists into single value. +Functions reducing lists to a single value (which may also be a list). @anchor{-reduce-from} -@defun -reduce-from (fn initial-value list) -Return the result of applying @var{fn} to @var{initial-value} and the -first item in @var{list}, then applying @var{fn} to that result and the 2nd -item, etc. If @var{list} contains no items, return @var{initial-value} and -do not call @var{fn}. +@defun -reduce-from (fn init list) +Reduce the function @var{fn} across @var{list}, starting with @var{init}. +Return the result of applying @var{fn} to @var{init} and the first element of +@var{list}, then applying @var{fn} to that result and the second element, +etc. If @var{list} is empty, return @var{init} without calling @var{fn}. -In the anaphoric form @code{--reduce-from}, the accumulated value is -exposed as symbol @code{acc}. - -See also: @code{-reduce} (@pxref{-reduce}), @code{-reduce-r} (@pxref{-reduce-r}) +This function's anaphoric counterpart is @code{--reduce-from}. +For other folds, see also @code{-reduce} (@pxref{-reduce}) and @code{-reduce-r} (@pxref{-reduce-r}). @example @group -(-reduce-from '- 10 '(1 2 3)) +(-reduce-from #'- 10 '(1 2 3)) @result{} 4 @end group @group -(-reduce-from (lambda (memo item) (format "(%s - %d)" memo item)) "10" '(1 2 3)) - @result{} "(((10 - 1) - 2) - 3)" +(-reduce-from #'list 10 '(1 2 3)) + @result{} '(((10 1) 2) 3) @end group @group (--reduce-from (concat acc " " it) "START" '("a" "b" "c")) @@ -1149,24 +1147,31 @@ See also: @code{-reduce} (@pxref{-reduce}), @code{-reduce-r} (@pxref{-reduce-r}) @end defun @anchor{-reduce-r-from} -@defun -reduce-r-from (fn initial-value list) -Replace conses with @var{fn}, nil with @var{initial-value} and evaluate -the resulting expression. If @var{list} is empty, @var{initial-value} is -returned and @var{fn} is not called. +@defun -reduce-r-from (fn init list) +Reduce the function @var{fn} across @var{list} in reverse, starting with @var{init}. +Return the result of applying @var{fn} to the last element of @var{list} and +@var{init}, then applying @var{fn} to the second-to-last element and the +previous result of @var{fn}, etc. That is, the first argument of @var{fn} is +the current element, and its second argument the accumulated +value. If @var{list} is empty, return @var{init} without calling @var{fn}. -Note: this function works the same as @code{-reduce-from} (@pxref{-reduce-from}) but the -operation associates from right instead of from left. +This function is like @code{-reduce-from} (@pxref{-reduce-from}) but the operation associates +from the right rather than left. In other words, it starts from +the end of @var{list} and flips the arguments to @var{fn}. Conceptually, it +is like replacing the conses in @var{list} with applications of @var{fn}, and +its last link with @var{init}, and evaluating the resulting expression. -See also: @code{-reduce-r} (@pxref{-reduce-r}), @code{-reduce} (@pxref{-reduce}) +This function's anaphoric counterpart is @code{--reduce-r-from}. +For other folds, see also @code{-reduce-r} (@pxref{-reduce-r}) and @code{-reduce} (@pxref{-reduce}). @example @group -(-reduce-r-from '- 10 '(1 2 3)) +(-reduce-r-from #'- 10 '(1 2 3)) @result{} -8 @end group @group -(-reduce-r-from (lambda (item memo) (format "(%d - %s)" item memo)) "10" '(1 2 3)) - @result{} "(1 - (2 - (3 - 10)))" +(-reduce-r-from #'list 10 '(1 2 3)) + @result{} '(1 (2 (3 10))) @end group @group (--reduce-r-from (concat it " " acc) "END" '("a" "b" "c")) @@ -1177,24 +1182,23 @@ See also: @code{-reduce-r} (@pxref{-reduce-r}), @code{-reduce} (@pxref{-reduce}) @anchor{-reduce} @defun -reduce (fn list) -Return the result of applying @var{fn} to the first 2 items in @var{list}, -then applying @var{fn} to that result and the 3rd item, etc. If @var{list} -contains no items, return the result of calling @var{fn} with no -arguments. If @var{list} contains a single item, return that item -and do not call @var{fn}. - -In the anaphoric form @code{--reduce}, the accumulated value is -exposed as symbol @code{acc}. +Reduce the function @var{fn} across @var{list}. +Return the result of applying @var{fn} to the first two elements of +@var{list}, then applying @var{fn} to that result and the third element, etc. +If @var{list} contains a single element, return it without calling @var{fn}. +If @var{list} is empty, return the result of calling @var{fn} with no +arguments. -See also: @code{-reduce-from} (@pxref{-reduce-from}), @code{-reduce-r} (@pxref{-reduce-r}) +This function's anaphoric counterpart is @code{--reduce}. +For other folds, see also @code{-reduce-from} (@pxref{-reduce-from}) and @code{-reduce-r} (@pxref{-reduce-r}). @example @group -(-reduce '- '(1 2 3 4)) +(-reduce #'- '(1 2 3 4)) @result{} -8 @end group @group -(-reduce 'list '(1 2 3 4)) +(-reduce #'list '(1 2 3 4)) @result{} '(((1 2) 3) 4) @end group @group @@ -1206,27 +1210,32 @@ See also: @code{-reduce-from} (@pxref{-reduce-from}), @code{-reduce-r} (@pxref{- @anchor{-reduce-r} @defun -reduce-r (fn list) -Replace conses with @var{fn} and evaluate the resulting expression. -The final nil is ignored. If @var{list} contains no items, return the -result of calling @var{fn} with no arguments. If @var{list} contains a single -item, return that item and do not call @var{fn}. +Reduce the function @var{fn} across @var{list} in reverse. +Return the result of applying @var{fn} to the last two elements of +@var{list}, then applying @var{fn} to the third-to-last element and the +previous result of @var{fn}, etc. That is, the first argument of @var{fn} is +the current element, and its second argument the accumulated +value. If @var{list} contains a single element, return it without +calling @var{fn}. If @var{list} is empty, return the result of calling @var{fn} +with no arguments. -The first argument of @var{fn} is the new item, the second is the -accumulated value. +This function is like @code{-reduce} (@pxref{-reduce}) but the operation associates from +the right rather than left. In other words, it starts from the +end of @var{list} and flips the arguments to @var{fn}. Conceptually, it is +like replacing the conses in @var{list} with applications of @var{fn}, +ignoring its last link, and evaluating the resulting expression. -Note: this function works the same as @code{-reduce} (@pxref{-reduce}) but the operation -associates from right instead of from left. - -See also: @code{-reduce-r-from} (@pxref{-reduce-r-from}), @code{-reduce} (@pxref{-reduce}) +This function's anaphoric counterpart is @code{--reduce-r}. +For other folds, see also @code{-reduce-r-from} (@pxref{-reduce-r-from}) and @code{-reduce} (@pxref{-reduce}). @example @group -(-reduce-r '- '(1 2 3 4)) +(-reduce-r #'- '(1 2 3 4)) @result{} -2 @end group @group -(-reduce-r (lambda (item memo) (format "%s-%d" memo item)) '(1 2 3)) - @result{} "3-2-1" +(-reduce-r #'list '(1 2 3 4)) + @result{} '(1 (2 (3 4))) @end group @group (--reduce-r (format "%s-%d" acc it) '(1 2 3)) @@ -1237,97 +1246,100 @@ See also: @code{-reduce-r-from} (@pxref{-reduce-r-from}), @code{-reduce} (@pxref @anchor{-reductions-from} @defun -reductions-from (fn init list) -Return a list of the intermediate values of the reduction. - -See @code{-reduce-from} (@pxref{-reduce-from}) for explanation of the arguments. - -See also: @code{-reductions} (@pxref{-reductions}), @code{-reductions-r} (@pxref{-reductions-r}), @code{-reduce-r} (@pxref{-reduce-r}) +Return a list of @var{fn}'s intermediate reductions across @var{list}. +That is, a list of the intermediate values of the accumulator +when @code{-reduce-from} (@pxref{-reduce-from}) (which see) is called with the same +arguments. +This function's anaphoric counterpart is @code{--reductions-from}. +For other folds, see also @code{-reductions} (@pxref{-reductions}) and @code{-reductions-r} (@pxref{-reductions-r}). @example @group -(-reductions-from (lambda (a i) (format "(%s FN %d)" a i)) "INIT" '(1 2 3 4)) - @result{} '("INIT" "(INIT FN 1)" "((INIT FN 1) FN 2)" "(((INIT FN 1) FN 2) FN 3)" "((((INIT FN 1) FN 2) FN 3) FN 4)") -@end group -@group -(-reductions-from 'max 0 '(2 1 4 3)) +(-reductions-from #'max 0 '(2 1 4 3)) @result{} '(0 2 2 4 4) @end group @group -(-reductions-from '* 1 '(1 2 3 4)) +(-reductions-from #'* 1 '(1 2 3 4)) @result{} '(1 1 2 6 24) @end group +@group +(--reductions-from (format "(FN %s %d)" acc it) "INIT" '(1 2 3)) + @result{} '("INIT" "(FN INIT 1)" "(FN (FN INIT 1) 2)" "(FN (FN (FN INIT 1) 2) 3)") +@end group @end example @end defun @anchor{-reductions-r-from} @defun -reductions-r-from (fn init list) -Return a list of the intermediate values of the reduction. - -See @code{-reduce-r-from} (@pxref{-reduce-r-from}) for explanation of the arguments. - -See also: @code{-reductions-r} (@pxref{-reductions-r}), @code{-reductions} (@pxref{-reductions}), @code{-reduce} (@pxref{-reduce}) +Return a list of @var{fn}'s intermediate reductions across reversed @var{list}. +That is, a list of the intermediate values of the accumulator +when @code{-reduce-r-from} (@pxref{-reduce-r-from}) (which see) is called with the same +arguments. +This function's anaphoric counterpart is @code{--reductions-r-from}. +For other folds, see also @code{-reductions} (@pxref{-reductions}) and @code{-reductions-r} (@pxref{-reductions-r}). @example @group -(-reductions-r-from (lambda (i a) (format "(%d FN %s)" i a)) "INIT" '(1 2 3 4)) - @result{} '("(1 FN (2 FN (3 FN (4 FN INIT))))" "(2 FN (3 FN (4 FN INIT)))" "(3 FN (4 FN INIT))" "(4 FN INIT)" "INIT") -@end group -@group -(-reductions-r-from 'max 0 '(2 1 4 3)) +(-reductions-r-from #'max 0 '(2 1 4 3)) @result{} '(4 4 4 3 0) @end group @group -(-reductions-r-from '* 1 '(1 2 3 4)) +(-reductions-r-from #'* 1 '(1 2 3 4)) @result{} '(24 24 12 4 1) @end group +@group +(--reductions-r-from (format "(FN %d %s)" it acc) "INIT" '(1 2 3)) + @result{} '("(FN 1 (FN 2 (FN 3 INIT)))" "(FN 2 (FN 3 INIT))" "(FN 3 INIT)" "INIT") +@end group @end example @end defun @anchor{-reductions} @defun -reductions (fn list) -Return a list of the intermediate values of the reduction. - -See @code{-reduce} (@pxref{-reduce}) for explanation of the arguments. - -See also: @code{-reductions-from} (@pxref{-reductions-from}), @code{-reductions-r} (@pxref{-reductions-r}), @code{-reduce-r} (@pxref{-reduce-r}) +Return a list of @var{fn}'s intermediate reductions across @var{list}. +That is, a list of the intermediate values of the accumulator +when @code{-reduce} (@pxref{-reduce}) (which see) is called with the same arguments. +This function's anaphoric counterpart is @code{--reductions}. +For other folds, see also @code{-reductions} (@pxref{-reductions}) and @code{-reductions-r} (@pxref{-reductions-r}). @example @group -(-reductions (lambda (a i) (format "(%s FN %d)" a i)) '(1 2 3 4)) - @result{} '(1 "(1 FN 2)" "((1 FN 2) FN 3)" "(((1 FN 2) FN 3) FN 4)") -@end group -@group -(-reductions '+ '(1 2 3 4)) +(-reductions #'+ '(1 2 3 4)) @result{} '(1 3 6 10) @end group @group -(-reductions '* '(1 2 3 4)) +(-reductions #'* '(1 2 3 4)) @result{} '(1 2 6 24) @end group +@group +(--reductions (format "(FN %s %d)" acc it) '(1 2 3)) + @result{} '(1 "(FN 1 2)" "(FN (FN 1 2) 3)") +@end group @end example @end defun @anchor{-reductions-r} @defun -reductions-r (fn list) -Return a list of the intermediate values of the reduction. - -See @code{-reduce-r} (@pxref{-reduce-r}) for explanation of the arguments. - -See also: @code{-reductions-r-from} (@pxref{-reductions-r-from}), @code{-reductions} (@pxref{-reductions}), @code{-reduce} (@pxref{-reduce}) +Return a list of @var{fn}'s intermediate reductions across reversed @var{list}. +That is, a list of the intermediate values of the accumulator +when @code{-reduce-r} (@pxref{-reduce-r}) (which see) is called with the same arguments. +This function's anaphoric counterpart is @code{--reductions-r}. +For other folds, see also @code{-reductions-r-from} (@pxref{-reductions-r-from}) and +@code{-reductions} (@pxref{-reductions}). @example @group -(-reductions-r (lambda (i a) (format "(%d FN %s)" i a)) '(1 2 3 4)) - @result{} '("(1 FN (2 FN (3 FN 4)))" "(2 FN (3 FN 4))" "(3 FN 4)" 4) -@end group -@group -(-reductions-r '+ '(1 2 3 4)) +(-reductions-r #'+ '(1 2 3 4)) @result{} '(10 9 7 4) @end group @group -(-reductions-r '* '(1 2 3 4)) +(-reductions-r #'* '(1 2 3 4)) @result{} '(24 24 12 4) @end group +@group +(--reductions-r (format "(FN %d %s)" it acc) '(1 2 3)) + @result{} '("(FN 1 (FN 2 3))" "(FN 2 3)" 3) +@end group @end example @end defun diff --git a/dev/examples.el b/dev/examples.el index 0715e20..dc93f8e 100644 --- a/dev/examples.el +++ b/dev/examples.el @@ -354,73 +354,111 @@ new list." (-remove-at-indices '(2 3) '((0) (1) (2) (3) (4) (5) (6))) => '((0) (1) (4) (5) (6)))) (def-example-group "Reductions" - "Functions reducing lists into single value." + "Functions reducing lists to a single value (which may also be a list)." (defexamples -reduce-from - (-reduce-from '- 10 '(1 2 3)) => 4 - (-reduce-from (lambda (memo item) (format "(%s - %d)" memo item)) "10" '(1 2 3)) => "(((10 - 1) - 2) - 3)" + (-reduce-from #'- 10 '(1 2 3)) => 4 + (-reduce-from #'list 10 '(1 2 3)) => '(((10 1) 2) 3) (--reduce-from (concat acc " " it) "START" '("a" "b" "c")) => "START a b c" (--reduce-from (- acc it) 10 '(1 2 3)) => 4 (--reduce-from (- acc it) 10 '(1)) => 9 - (--reduce-from (- acc it) 10 '()) => 10 - (-reduce-from '- 7 '(1)) => 6 - (-reduce-from '- 7 '()) => 7) + (--reduce-from (- acc it) 10 ()) => 10 + (-reduce-from #'- 7 '(1)) => 6 + (-reduce-from #'- 7 ()) => 7 + (--reduce-from (list acc it-index) nil '(1 2 3)) => '(((nil 0) 1) 2) + (--reduce-from t nil '(1 2 3)) => t) (defexamples -reduce-r-from - (-reduce-r-from '- 10 '(1 2 3)) => -8 - (-reduce-r-from (lambda (item memo) (format "(%d - %s)" item memo)) "10" '(1 2 3)) => "(1 - (2 - (3 - 10)))" + (-reduce-r-from #'- 10 '(1 2 3)) => -8 + (-reduce-r-from #'list 10 '(1 2 3)) => '(1 (2 (3 10))) (--reduce-r-from (concat it " " acc) "END" '("a" "b" "c")) => "a b c END" (--reduce-r-from (- it acc) 10 '(1 2 3)) => -8 (--reduce-r-from (- it acc) 10 '(1)) => -9 - (--reduce-r-from (- it acc) 10 '()) => 10 - (-reduce-r-from '- 7 '(1)) => -6 - (-reduce-r-from '- 7 '()) => 7) + (--reduce-r-from (- it acc) 10 ()) => 10 + (-reduce-r-from #'- 7 '(1)) => -6 + (-reduce-r-from #'- 7 ()) => 7 + (--reduce-r-from (list acc it-index) nil '(1 2 3)) => '(((nil 2) 1) 0) + (--reduce-r-from t nil '(1 2 3)) => t) (defexamples -reduce - (-reduce '- '(1 2 3 4)) => -8 - (-reduce 'list '(1 2 3 4)) => '(((1 2) 3) 4) + (-reduce #'- '(1 2 3 4)) => -8 + (-reduce #'list '(1 2 3 4)) => '(((1 2) 3) 4) (--reduce (format "%s-%d" acc it) '(1 2 3)) => "1-2-3" - (-reduce '- '()) => 0 - (-reduce '- '(1)) => 1 + (-reduce #'- ()) => 0 + (-reduce #'- '(1)) => 1 (--reduce (- acc it) '(1)) => 1 - (--reduce (format "%s-%s" acc it) '()) => "nil-nil") + (--reduce (list acc it) ()) => '(nil nil) + (--reduce t '(1 2)) => t + (-reduce #'vector ()) => [] + (-reduce #'vector '(1)) => 1 + (-reduce #'vector '(1 2)) => [1 2]) (defexamples -reduce-r - (-reduce-r '- '(1 2 3 4)) => -2 - (-reduce-r (lambda (item memo) (format "%s-%d" memo item)) '(1 2 3)) => "3-2-1" + (-reduce-r #'- '(1 2 3 4)) => -2 + (-reduce-r #'list '(1 2 3 4)) => '(1 (2 (3 4))) (--reduce-r (format "%s-%d" acc it) '(1 2 3)) => "3-2-1" - (-reduce-r '+ '()) => 0 - (-reduce-r '- '(1)) => 1 + (-reduce-r #'+ ()) => 0 + (-reduce-r #'- '(1)) => 1 (--reduce (- it acc) '(1)) => 1 - (--reduce-r (format "%s-%s" it acc) '()) => "nil-nil") + (--reduce-r (list it acc) ()) => '(nil nil) + (--reduce-r t '(1 2)) => t + (-reduce-r #'vector ()) => [] + (-reduce-r #'vector '(1)) => 1 + (-reduce-r #'vector '(1 2)) => [1 2]) (defexamples -reductions-from - (-reductions-from (lambda (a i) (format "(%s FN %d)" a i)) "INIT" '(1 2 3 4)) => '("INIT" "(INIT FN 1)" "((INIT FN 1) FN 2)" "(((INIT FN 1) FN 2) FN 3)" "((((INIT FN 1) FN 2) FN 3) FN 4)") - (-reductions-from 'max 0 '(2 1 4 3)) => '(0 2 2 4 4) - (-reductions-from '* 1 '(1 2 3 4)) => '(1 1 2 6 24) - (-reductions-from '- 10 '(1)) => '(10 9) - (-reductions-from '- 10 ()) => '(10)) + (-reductions-from #'max 0 '(2 1 4 3)) => '(0 2 2 4 4) + (-reductions-from #'* 1 '(1 2 3 4)) => '(1 1 2 6 24) + (--reductions-from (format "(FN %s %d)" acc it) "INIT" '(1 2 3)) + => '("INIT" "(FN INIT 1)" "(FN (FN INIT 1) 2)" "(FN (FN (FN INIT 1) 2) 3)") + (-reductions-from #'- 10 '(1)) => '(10 9) + (-reductions-from #'- 10 ()) => '(10) + (--reductions-from (- acc it) 10 '(1)) => '(10 9) + (--reductions-from (- acc it) 10 ()) => '(10) + (--reductions-from t 10 '(1 2 3)) => '(10 t t t) + (--reductions-from (list acc it-index) nil '(1 2 3)) + => '(nil (nil 0) ((nil 0) 1) (((nil 0) 1) 2))) (defexamples -reductions-r-from - (-reductions-r-from (lambda (i a) (format "(%d FN %s)" i a)) "INIT" '(1 2 3 4)) => '("(1 FN (2 FN (3 FN (4 FN INIT))))" "(2 FN (3 FN (4 FN INIT)))" "(3 FN (4 FN INIT))" "(4 FN INIT)" "INIT") - (-reductions-r-from 'max 0 '(2 1 4 3)) => '(4 4 4 3 0) - (-reductions-r-from '* 1 '(1 2 3 4)) => '(24 24 12 4 1) - (-reductions-r-from '- 10 '(1)) => '(-9 10) - (-reductions-r-from '- 10 ()) => '(10)) + (-reductions-r-from #'max 0 '(2 1 4 3)) => '(4 4 4 3 0) + (-reductions-r-from #'* 1 '(1 2 3 4)) => '(24 24 12 4 1) + (--reductions-r-from (format "(FN %d %s)" it acc) "INIT" '(1 2 3)) + => '("(FN 1 (FN 2 (FN 3 INIT)))" "(FN 2 (FN 3 INIT))" "(FN 3 INIT)" "INIT") + (-reductions-r-from #'- 10 '(1)) => '(-9 10) + (-reductions-r-from #'- 10 ()) => '(10) + (--reductions-r-from (- acc it) 10 '(1)) => '(9 10) + (--reductions-r-from (- acc it) 10 ()) => '(10) + (--reductions-r-from t 10 '(1 2 3)) => '(t t t 10) + (--reductions-r-from (list acc it-index) nil '(1 2 3)) + => '((((nil 2) 1) 0) ((nil 2) 1) (nil 2) nil)) (defexamples -reductions - (-reductions (lambda (a i) (format "(%s FN %d)" a i)) '(1 2 3 4)) => '(1 "(1 FN 2)" "((1 FN 2) FN 3)" "(((1 FN 2) FN 3) FN 4)") - (-reductions '+ '(1 2 3 4)) => '(1 3 6 10) - (-reductions '* '(1 2 3 4)) => '(1 2 6 24) - (-reductions '- '(1)) => '(1) - (-reductions '- ()) => ()) + (-reductions #'+ '(1 2 3 4)) => '(1 3 6 10) + (-reductions #'* '(1 2 3 4)) => '(1 2 6 24) + (--reductions (format "(FN %s %d)" acc it) '(1 2 3)) + => '(1 "(FN 1 2)" "(FN (FN 1 2) 3)") + (-reductions #'- '(1)) => '(1) + (-reductions #'- ()) => '(0) + (-reductions #'vector ()) => '([]) + (-reductions #'vector '(1)) => '(1) + (-reductions #'vector '(1 2)) => '(1 [1 2]) + (--reductions t '(1 2 3)) => '(1 t t) + (--reductions (list it acc) ()) => '((nil nil)) + (--reductions (list it acc) '(1)) => '(1)) (defexamples -reductions-r - (-reductions-r (lambda (i a) (format "(%d FN %s)" i a)) '(1 2 3 4)) => '("(1 FN (2 FN (3 FN 4)))" "(2 FN (3 FN 4))" "(3 FN 4)" 4) - (-reductions-r '+ '(1 2 3 4)) => '(10 9 7 4) - (-reductions-r '* '(1 2 3 4)) => '(24 24 12 4) - (-reductions-r '- '(1)) => '(1) - (-reductions-r '- ()) => ()) + (-reductions-r #'+ '(1 2 3 4)) => '(10 9 7 4) + (-reductions-r #'* '(1 2 3 4)) => '(24 24 12 4) + (--reductions-r (format "(FN %d %s)" it acc) '(1 2 3)) + => '("(FN 1 (FN 2 3))" "(FN 2 3)" 3) + (-reductions-r #'- '(1)) => '(1) + (-reductions-r #'- ()) => '(0) + (-reductions-r #'vector ()) => '([]) + (-reductions-r #'vector '(1)) => '(1) + (-reductions-r #'vector '(1 2)) => '([1 2] 2) + (--reductions-r t '(1 2 3)) => '(t t 3) + (--reductions-r (list it acc) ()) => '((nil nil)) + (--reductions-r (list it acc) '(1)) => '(1)) (defexamples -count (-count 'even? '(1 2 3 4 5)) => 2