I'm trying to generate prime numbers in a pythonic way- that is, using generators.
The python code would be more or less the following
def divisor_in_list(n, d):
""" Returns true if a divisor of n is in d, false otherwise"
primelist = 
i = 3
while divisor_in_list(i, primelist):
i += 2
(defun primes ()
(let* ((p (list 2)) (n 3))
(loop while (divisor-in-slist n p)
do (incf n 2))
(nconc p (list n))
(+ n 0) ;; Not actually sure how to return N directly :(
There is no direct equivalent of
yield in Common Lisp. One might use some functional approach or use some kind of library which provides lazy computation.
One way to complete your approach would be something like this, where we have a variable
f which holds the current continuation.
(defun make-prime-generator (&aux (p (list 2)) (n 2) f) (labels ((f2 () ; a function for the first iteration (incf n) (setf f #'fn) ; setting f to the next function 2) (fn () ; a function for all other iterations (loop while (divisor-in-list n p) do (incf n 2)) (push n p) n)) (setf f #'f2) ; setting f to the first function (lambda () ; returning a closure (funcall f)))) ; which calls the current f CL-USER 28 > (let ((p (make-prime-generator))) (flet ((p () (funcall p))) (loop repeat 10 do (print (p))))) 2 3 5 7 11 13 17 19 23 29 NIL
If one would be ambitious, one could hide above behind a macro, which would define all the code parts and which would manage the transition.
We can make the state changes a bit more explicit by introducing the local functions
(defun make-prime-generator (&aux (p (list 2)) (n 2) f) (flet ((init (function) (setf f function)) (exit (result function) (setf f function) result) (step () (funcall f))) (labels ((f2 () (incf n) (exit 2 #'fn)) (fn () (loop while (divisor-in-list n p) do (incf n 2)) (push n p) (exit n #'fn))) (init #'f2) #'step)))
Now that would be another, slightly more advanced, task: write a macro
gen-run which allows us to remove the boilerplate and make the code more declarative. It might be used like this:
(defmacro gen-run (f-descriptions &key start) (let ((§f (gensym "F")) (§init (gensym "INIT")) (§exit (gensym "EXIT")) (§step (gensym "STEP"))) `(let (,§f) (flet ((,§init (function) (setf ,§f function)) (,§exit (result function) (setf ,§f function) result) (,§step () (funcall ,§f))) (labels (,@(loop for fd in f-descriptions collect (destructuring-bind (name -> next &body body) fd (declare (ignore ->)) `(,name () (,§exit ((lambda () ,@body)) (function ,(if next next name))))))) (,§init (function ,start)) (function ,§step)))))) (defun make-prime-generator (&aux (p (list 2)) (n 2)) (gen-run ((f2 -> fn (incf n) 2) (fn -> fn (loop while (divisor-in-list n p) do (incf n 2)) (push n p) n)) :start f2))