David Steuber <david@david-steuber.com> wrote:
+---------------
| ;;; Fibonacci sequence generator as closure
| (let ((a 0) (b 1))
| (defun fib-gen ()
| "Return next Fibonacci number in sequence with each call"
| (let ((ret b) (n a))
| (setf a b
| b (+ ret n))
| ret)))
|
| (progn
| (dotimes (i 10)
| (format t "~A " (fib-gen)))
| (terpri))
+---------------
That works, but of course permits only one Fibonacci sequence generator
per Lisp image. Instead, I generally prefer to use anonymous closures[1]
for such generators, which are initialized to the beginning each time
a new closure is created, and whose steppings can be interleaved in any
desired order:
> (defun make-fib-gen (&optional (first 0) (second (1+ first)))
(let ((a first)
(b second))
(flet ((fib-gen ()
(prog1 a
(psetf a b
b (+ a b)))))
#'fib-gen)))
MAKE-FIB-GEN
> (defvar *fg1* (make-fib-gen))
*FG1*
> (defvar *fg2* (make-fib-gen))
*FG2*
> (defvar *fg3* (make-fib-gen 17 56))
*FG3*
> (loop for i below 10 collect (funcall *fg1*))
(0 1 1 2 3 5 8 13 21 34)
> (loop for i below 15 collect (funcall *fg2*))
(0 1 1 2 3 5 8 13 21 34 55 89 144 233 377)
> (loop for i below 10 collect (funcall *fg1*))
(55 89 144 233 377 610 987 1597 2584 4181)
>
Now let's interleave all of them [including our forgotten friend *FG3*]:
> (loop for i below 5
collect (list (funcall *fg1*) (funcall *fg2*) (funcall *fg3*)))
((6765 610 17) (10946 987 56) (17711 1597 73) (28657 2584 129)
(46368 4181 202))
>
-Rob
[1] Although that the use of FLET as above (rather than LAMBDA per se)
causes many implementations to still store the "name" internally
in a way that is useful for debugging [note: this is in CMUCL,
and I compiled MAKE-FIB-GEN between creating *FG1* & *FG2*]:
> *fg1*
#<Interpreted Function FIB-GEN {485717D1}>
> *fg2*
#<Closure Over Function FIB-GEN {48530471}>
>
-----
Rob Warnock <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607