You could also use the SERIES package:
(defpackage :so (:use :cl :series :local-time))
(in-package :so)
(let ((stop-date (timestamp- (today) 10 :day)))
(scan-fn ;; type of elements (could be T here)
'timestamp
;; init function
(lambda () (today))
;; step function
(lambda (ts) (timestamp- ts 1 :day))
;; termination test
(lambda (ts) (not (timestamp>= ts stop-date)))))
The above returns an instance of a series object, which is a lazy (on-demand) stream of values, compiled efficiently. In a REPL, this is displayed as #Z(...)
(where dots are elements). If you want to convert it to a list, you can call collect
:
(collect *) ;; assuming * is the last returned value
If you want a vector instead:
(collect 'vector **)
Which gives:
#(@2019-02-19T01:00:00.000000+01:00 @2019-02-18T01:00:00.000000+01:00
@2019-02-17T01:00:00.000000+01:00 @2019-02-16T01:00:00.000000+01:00
@2019-02-15T01:00:00.000000+01:00 @2019-02-14T01:00:00.000000+01:00
@2019-02-13T01:00:00.000000+01:00 @2019-02-12T01:00:00.000000+01:00
@2019-02-11T01:00:00.000000+01:00 @2019-02-10T01:00:00.000000+01:00
@2019-02-09T01:00:00.000000+01:00)
Note also that in the case collect
lexically encloses the scan-fn
function, it can directly express the code as a loop. For example:
(let ((stop-date (timestamp- (today) 10 :day)))
(collect
(scan-fn ;; type of elements (could be T here)
'timestamp
;; init function
(lambda () (today))
;; step function
(lambda (ts) (timestamp- ts 1 :day))
;; termination test
(lambda (ts) (not (timestamp>= ts stop-date))))))
The collect
form is macroexpanded as:
(LET* (#:STATE-1062 #:ITEMS-1063 (#:LASTCONS-1060 (LIST NIL)) #:LST-1061)
(DECLARE (TYPE CONS #:LASTCONS-1060)
(TYPE LIST #:LST-1061))
(LOCALLY
(DECLARE (TYPE TIMESTAMP #:STATE-1062)
(TYPE TIMESTAMP #:ITEMS-1063))
(SETQ #:STATE-1062 ((LAMBDA () (TODAY))))
(SETQ #:LST-1061 #:LASTCONS-1060)
(TAGBODY
#:LL-1064
(IF ((LAMBDA (TS) (NOT (TIMESTAMP>= TS STOP-DATE))) #:STATE-1062)
(GO SERIES::END))
(SETQ #:ITEMS-1063 #:STATE-1062)
(SETQ #:STATE-1062 ((LAMBDA (TS) (TIMESTAMP- TS 1 :DAY)) #:STATE-1062))
(SETQ #:LASTCONS-1060
(SETF (CDR #:LASTCONS-1060) (CONS #:ITEMS-1063 NIL)))
(GO #:LL-1064)
SERIES::END)
(CDR #:LST-1061)))
As mentioned by Evhince, the Common Lisp cookbook has a section about Series, see https://lispcookbook.github.io/cl-cookbook/iteration.html