Python's range() analog in Common Lisp
There is no built-in way of generating a sequence of numbers, the canonical way of doing so is to do one of:
- Use
loop
- Write a utility function that uses
loop
An example implementation would be (this only accepts counting "from low" to "high"):
(defun range (max &key (min 0) (step 1))
(loop for n from min below max by step
collect n))
This allows you to specify an (optional) minimum value and an (optional) step value.
To generate odd numbers: (range 10 :min 1 :step 2)
alexandria implements scheme's iota:
(ql:quickload :alexandria)
(alexandria:iota 4 :start 2 :step 2)
;; (2 4 6 8)
Here's how I'd approach the problem:
(defun generate (from to &optional (by 1))
#'(lambda (f)
(when (< from to)
(prog1 (or (funcall f from) t)
(incf from by)))))
(defmacro with-generator ((var from to &optional (by 1)) &body body)
(let ((generator (gensym)))
`(loop with ,generator = (generate ,from ,to ,by)
while
(funcall ,generator
#'(lambda (,var) ,@body)))))
(with-generator (i 1 10)
(format t "~&i = ~s" i))
But this is just the general idea, there's a lot of room for improvement.
OK, since there seems to be a discussion here. I've assumed that what is really needed is the analogue to Python's range
generator function. Which, in certain sense generates a list of numbers, but does it so by yielding a number each iteration (so that it doesn't create more then one item at a time). Generators are a somewhat rare concept (few languages implement it), so I assumed that the mention of Python suggested that this exact feature is desired.
Following some criticism of my example above, here's a different example that illustrates the reason to why a generator might be used rather then a simple loop.
(defun generate (from to &optional (by 1))
#'(lambda ()
(when (< from to)
(prog1 from
(incf from by)))))
(defmacro with-generator
((var generator &optional (exit-condition t)) &body body)
(let ((g (gensym)))
`(do ((,g ,generator))
(nil)
(let ((,var (funcall ,g)))
(when (or (null ,var) ,exit-condition)
(return ,g))
,@body))))
(let ((gen
(with-generator (i (generate 1 10) (> i 4))
(format t "~&i = ~s" i))))
(format t "~&in the middle")
(with-generator (j gen (> j 7))
(format t "~&j = ~s" j)))
;; i = 1
;; i = 2
;; i = 3
;; i = 4
;; in the middle
;; j = 6
;; j = 7
This is, again, only an illustration of the purpose of this function. It is probably wasteful to use it for generating integers, even if you need to do that in two steps, but generators are best with parsers, when you want to yield a more complex object which is built based upon the previous state of the parser, for example, and a bunch of other things. Well, you can read an argument about it here: http://en.wikipedia.org/wiki/Generator_%28computer_programming%29