これが私が問題に取り組む方法です:
(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))
しかし、これは単なる一般的な考え方であり、改善の余地がたくさんあります。
OK、ここで議論があるようですので。本当に必要なのはPythonのrange
ジェネレーター関数に類似していると思います。これは、ある意味で数値のリストを生成しますが、反復ごとに数値を生成することによって生成します(一度に複数のアイテムが作成されないようにするため)。ジェネレーターはややまれな概念です(いくつかの言語がそれを実装しています)ので、Pythonの言及は、この正確な機能が望ましいことを示唆していると思いました。
上記の私の例に対するいくつかの批判に続いて、単純なループではなくジェネレーターが使用される理由を説明する別の例を次に示します。
(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
これもまた、この機能の目的を示したものにすぎません。2つのステップで行う必要がある場合でも、整数の生成に使用するのはおそらく無駄ですが、パーサーの以前の状態に基づいて構築されたより複雑なオブジェクトを生成する場合は、ジェネレーターがパーサーに最適です。たとえば、他にもたくさんあります。さて、あなたはここでそれについての議論を読むことができます:http: //en.wikipedia.org/wiki/Generator_%28computer_programming%29