Just bind a variable with a copy of the value. E.g.:
(let ((i i))
(lambda () i))
This is actually an important technique with iteration constructs, because something like
(loop for i from 1 to 10
collecting (lambda () i))
may return ten closures over the same variables, so it becomes necessary to write:
(loop for i from 1 to 10
collecting (let ((i i)) (lambda () i)))
If you really only need a function that returns the value, you could also use constantly (but I expect the real use case is more complicated):
(loop for i from 1 to 10
collecting (constantly i))
The ambiguity in iteration forms is actually specified by the standard, in some cases. E.g., for dotimes, dolist
It is implementation-dependent whether dotimes establishes a new binding of var on each iteration or whether it establishes a binding for var once at the beginning and then assigns it on any subsequent iterations.
The more primitive do, however, actually specifies that there is one set of bindings for the form, and that they are updated at each iteration (emphasis added):
At the beginning of each iteration other than the first, vars are updated as follows. …
This ambiguity gives implementations a bit more flexibility. Dolist, for instance could be defined with either of the following:
(defmacro dolist ((var list &optional result) &body body)
`(progn (mapcar #'(lambda (,var)
,@(ex:body-declarations body)
(tagbody
,@(ex:body-tags-and-statements body)))
,list)
(let ((,var nil))
,result)))
(defmacro dolist ((var list &optional result) &body body)
(let ((l (gensym (string '#:list-))))
`(do* ((,l ,list (rest ,l))
(,var (first ,l) (first ,l)))
((endp ,l) ,result)
,@body)))
LET
. – Offshore