branch: externals/dash commit 88737493cd7fdded213b8fa2a3c2bf832dae9517 Author: Basil L. Contovounesios <conto...@tcd.ie> Commit: Basil L. Contovounesios <conto...@tcd.ie>
Improve and simplify right-associative reductions * Translate recursion to iteration to avoid exceeding max-lisp-eval-depth. * Rewrite functions in terms of anaphoric macros. * Expand test cases. --- dash.el | 43 ++++++++++++++++++++----------------------- dev/examples.el | 40 +++++++++++++++++++++++----------------- 2 files changed, 43 insertions(+), 40 deletions(-) diff --git a/dash.el b/dash.el index 8d1d9a6..e0437b8 100644 --- a/dash.el +++ b/dash.el @@ -205,7 +205,7 @@ Return nil, used for side-effects only." "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 -FN is not called. +do not call FN. In the anaphoric form `--reduce-from', the accumulated value is exposed as symbol `acc'. @@ -225,9 +225,9 @@ See also: `-reduce', `-reduce-r'" (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, FN must accept no arguments as well, and -reduce return the result of calling FN with no arguments. If -LIST has only 1 item, it is returned and FN is not called. +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'. @@ -237,6 +237,11 @@ See also: `-reduce-from', `-reduce-r'" (-reduce-from fn (car list) (cdr list)) (funcall fn))) +(defmacro --reduce-r-from (form initial-value list) + "Anaphoric version of `-reduce-r-from'." + (declare (debug (form form form))) + `(--reduce-from ,form ,initial-value (reverse ,list))) + (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 @@ -246,20 +251,18 @@ Note: this function works the same as `-reduce-from' but the operation associates from right instead of from left. See also: `-reduce-r', `-reduce'" - (if (not list) initial-value - (funcall fn (car list) (-reduce-r-from fn initial-value (cdr list))))) + (--reduce-r-from (funcall fn it acc) initial-value list)) -(defmacro --reduce-r-from (form initial-value list) - "Anaphoric version of `-reduce-r-from'." - (declare (debug (form form form))) - `(-reduce-r-from (lambda (&optional it acc) ,form) ,initial-value ,list)) +(defmacro --reduce-r (form list) + "Anaphoric version of `-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, FN must -accept no arguments as well, and reduce return the result of -calling FN with no arguments. If LIST has only 1 item, it is -returned and FN is not called. +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. @@ -268,15 +271,9 @@ Note: this function works the same as `-reduce' but the operation associates from right instead of from left. See also: `-reduce-r-from', `-reduce'" - (cond - ((not list) (funcall fn)) - ((not (cdr list)) (car list)) - (t (funcall fn (car list) (-reduce-r fn (cdr list)))))) - -(defmacro --reduce-r (form list) - "Anaphoric version of `-reduce-r'." - (declare (debug (form form))) - `(-reduce-r (lambda (&optional it acc) ,form) ,list)) + (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. diff --git a/dev/examples.el b/dev/examples.el index 05669e9..7ae2d1f 100644 --- a/dev/examples.el +++ b/dev/examples.el @@ -303,34 +303,40 @@ new list." (defexamples -reduce-from (-reduce-from '- 10 '(1 2 3)) => 4 - (-reduce-from (lambda (memo item) - (concat "(" memo " - " (int-to-string item) ")")) "10" '(1 2 3)) => "(((10 - 1) - 2) - 3)" - (--reduce-from (concat acc " " it) "START" '("a" "b" "c")) => "START a b c" - (-reduce-from '+ 7 '()) => 7 - (-reduce-from '+ 7 '(1)) => 8) + (-reduce-from (lambda (memo item) (format "(%s - %d)" memo item)) "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) (defexamples -reduce-r-from (-reduce-r-from '- 10 '(1 2 3)) => -8 - (-reduce-r-from (lambda (item memo) - (concat "(" (int-to-string item) " - " memo ")")) "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 '+ 7 '()) => 7 - (-reduce-r-from '+ 7 '(1)) => 8) + (-reduce-r-from (lambda (item memo) (format "(%d - %s)" item memo)) "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) (defexamples -reduce (-reduce '- '(1 2 3 4)) => -8 - (-reduce (lambda (memo item) (format "%s-%s" memo item)) '(1 2 3)) => "1-2-3" - (--reduce (format "%s-%s" acc it) '(1 2 3)) => "1-2-3" - (-reduce '+ '()) => 0 - (-reduce '+ '(1)) => 1 + (-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 (- acc it) '(1)) => 1 (--reduce (format "%s-%s" acc it) '()) => "nil-nil") (defexamples -reduce-r (-reduce-r '- '(1 2 3 4)) => -2 - (-reduce-r (lambda (item memo) (format "%s-%s" memo item)) '(1 2 3)) => "3-2-1" - (--reduce-r (format "%s-%s" acc it) '(1 2 3)) => "3-2-1" + (-reduce-r (lambda (item memo) (format "%s-%d" memo item)) '(1 2 3)) => "3-2-1" + (--reduce-r (format "%s-%d" acc it) '(1 2 3)) => "3-2-1" (-reduce-r '+ '()) => 0 - (-reduce-r '+ '(1)) => 1 + (-reduce-r '- '(1)) => 1 + (--reduce (- it acc) '(1)) => 1 (--reduce-r (format "%s-%s" it acc) '()) => "nil-nil") (defexamples -reductions-from