Search code examples
iterationcommon-lisp

Is there a way to tweak Common Lisp dotimes macro so that it does not start from zero but from a different number, such as 1?


I am using Emacs, Slime, and SBCL.

The default use of dotimes is:

CL-USER> (defun my-dotimes (n)
           (dotimes (i n)
             (format t "~s ~%" i)))

Which generates:

CL-USER> (my-dotimes 10)
0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
NIL

I wish the function could start counting from one. I can change it with:

CL-USER> (defun my-new-dotimes (n)
           (dotimes (i (- n 1))
             (format t "~s ~%" (+ i 1))))
MY-NEW-DOTIMES
CL-USER> (my-new-dotimes 10)
1 
2 
3 
4 
5 
6 
7 
8 
9 
NIL

But, it does not feel like an elegant solution.

The official documentation mentions a declare possibility. But I am not sure how to use it.

Is there a better way to do this?


Solution

  • CL-USER 15 > (defmacro dotimes-start ((var n start
                                           &optional (result nil))
                                          &body body)
                   `(loop for ,var from ,start
                          repeat ,n
                          do (progn ,@body)
                          finally (return ,result)))
    DOTIMES-START
    
    CL-USER 16 > (dotimes-start (i 10 2) (print i))
    
    2 
    3 
    4 
    5 
    6 
    7 
    8 
    9 
    10 
    11 
    NIL
    
    CL-USER 17 > (let ((s 0))
                   (dotimes-start (i 10 3 s)
                     (incf s (sin i))))
    -1.8761432