From f2cd73d2ab252399fdb00054e0062b996da3650e Mon Sep 17 00:00:00 2001 From: "Basil L. Contovounesios" Date: Tue, 5 Jan 2021 02:24:41 +0000 Subject: [PATCH] Make --dotimes more hygienic * dash.el (--dotimes): Protect 'it' from being changed in body. (-dotimes): Fix docstring. * dev/examples.el (-dotimes): Add more tests. * README.md: * dash.texi: Regenerate docs. --- README.md | 10 +++++++--- dash.el | 28 +++++++++++++++++++--------- dash.texi | 13 ++++++++++--- dev/examples.el | 7 +++++-- 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 079d584..c7fa812 100644 --- a/README.md +++ b/README.md @@ -2638,11 +2638,15 @@ Return nil, used for side-effects only. #### -dotimes `(num fn)` -Repeatedly calls `fn` (presumably for side-effects) passing in integers from 0 through `num-1`. +Call `fn` `num` times, presumably for side-effects. +`fn` is called with a single argument on successive integers +running from 0, inclusive, to `num`, exclusive. `fn` is not called +if `num` is less than 1. ```el -(let (s) (-dotimes 3 (lambda (n) (!cons n s))) s) ;; => '(2 1 0) -(let (s) (--dotimes 5 (!cons it s)) s) ;; => '(4 3 2 1 0) +(let (s) (-dotimes 3 (lambda (n) (push n s))) s) ;; => '(2 1 0) +(let (s) (-dotimes 0 (lambda (n) (push n s))) s) ;; => nil +(let (s) (--dotimes 5 (push it s)) s) ;; => '(4 3 2 1 0) ``` #### -doto `(eval-initial-value &rest forms)` diff --git a/dash.el b/dash.el index 843f2e8..b6dce42 100644 --- a/dash.el +++ b/dash.el @@ -166,18 +166,28 @@ Return nil, used for side-effects only." (--each-r-while list (funcall pred it) (funcall fn it))) (defmacro --dotimes (num &rest body) - "Repeatedly executes BODY (presumably for side-effects) with symbol `it' bound to integers from 0 through NUM-1." - (declare (debug (form body)) - (indent 1)) - (let ((n (make-symbol "num"))) + "Evaluate BODY NUM times, presumably for side-effects. +BODY is evaluated with the local variable `it' temporarily bound +to successive integers running from 0, inclusive, to NUM, +exclusive. BODY is not evaluated if NUM is less than 1. + +This is the anaphoric version of `-dotimes'." + (declare (debug (form body)) (indent 1)) + (let ((n (make-symbol "num")) + (i (make-symbol "i"))) `(let ((,n ,num) - (it 0)) - (while (< it ,n) - ,@body - (setq it (1+ it)))))) + (,i 0) + it) + (ignore it) + (while (< ,i ,n) + (setq it ,i ,i (1+ ,i)) + ,@body)))) (defun -dotimes (num fn) - "Repeatedly calls FN (presumably for side-effects) passing in integers from 0 through NUM-1." + "Call FN NUM times, presumably for side-effects. +FN is called with a single argument on successive integers +running from 0, inclusive, to NUM, exclusive. FN is not called +if NUM is less than 1." (declare (indent 1)) (--dotimes num (funcall fn it))) diff --git a/dash.texi b/dash.texi index b3644ea..86c5468 100644 --- a/dash.texi +++ b/dash.texi @@ -4002,15 +4002,22 @@ Return nil, used for side-effects only. @anchor{-dotimes} @defun -dotimes (num fn) -Repeatedly calls @var{fn} (presumably for side-effects) passing in integers from 0 through @var{num-1}. +Call @var{fn} @var{num} times, presumably for side-effects. +@var{fn} is called with a single argument on successive integers +running from 0, inclusive, to @var{num}, exclusive. @var{fn} is not called +if @var{num} is less than 1. @example @group -(let (s) (-dotimes 3 (lambda (n) (!cons n s))) s) +(let (s) (-dotimes 3 (lambda (n) (push n s))) s) @result{} '(2 1 0) @end group @group -(let (s) (--dotimes 5 (!cons it s)) s) +(let (s) (-dotimes 0 (lambda (n) (push n s))) s) + @result{} nil +@end group +@group +(let (s) (--dotimes 5 (push it s)) s) @result{} '(4 3 2 1 0) @end group @end example diff --git a/dev/examples.el b/dev/examples.el index a508b32..5bec9a7 100644 --- a/dev/examples.el +++ b/dev/examples.el @@ -1349,8 +1349,11 @@ new list." (let (s) (--each-r-while '(1 2 3 4) (>= it 3) (!cons it s)) s) => '(3 4)) (defexamples -dotimes - (let (s) (-dotimes 3 (lambda (n) (!cons n s))) s) => '(2 1 0) - (let (s) (--dotimes 5 (!cons it s)) s) => '(4 3 2 1 0)) + (let (s) (-dotimes 3 (lambda (n) (push n s))) s) => '(2 1 0) + (let (s) (-dotimes 0 (lambda (n) (push n s))) s) => () + (let (s) (--dotimes 5 (push it s)) s) => '(4 3 2 1 0) + (let (s) (--dotimes 0 (push it s)) s) => () + (let (s) (--dotimes 3 (push it s) (setq it -1)) s) => '(2 1 0)) (defexamples -doto (-doto '(1 2 3) (!cdr) (!cdr)) => '(3)