lisp - 以下使用 gensym 的 Common Lisp 宏有什么问题?

标签 lisp common-lisp

学习 Common Lisp(使用 GNU CLISP 2.43).. 所以可能是一个菜鸟错误。示例是“打印 x 和 y 之间的素数”

(defun is-prime (n)
  (if (< n 2) (return-from is-prime NIL))

  (do ((i 2 (1+ i)))
      ((= i n) T)
    (if (= (mod n i) 0) 
        (return NIL))))

(defun next-prime-after (n)
  (do ((i (1+ n) (1+ i)))
      ((is-prime i) i)))

(defmacro do-primes-v2 ((var start end) &body body)
  `(do ((,var (if (is-prime ,start)
                  ,start
                  (next-prime-after ,start))
              (next-prime-after ,var)))
       ((> ,var ,end))
     ,@body))

(defmacro do-primes-v3 ((var start end) &body body)
  (let ((loop-start (gensym))
        (loop-end (gensym))) 
    `(do ((,loop-start ,start)
          (,loop-end ,end)
          (,var (if (is-prime ,loop-start)
                    ,loop-start
                    (next-prime-after ,loop-start))
                (next-prime-after ,var)))
         ((> ,var ,loop-end))
       ,@body )))

do-primes-v2 完美运行。

[13]> (do-primes-v2 (p 10 25) (format t "~d " p))
11 13 17 19 23

接下来我尝试使用 gensym 来避免宏扩展中的命名冲突 - do-primes-v3。但是我坚持使用

*** - EVAL: variable #:G3498 has no value

尝试使用宏扩展来查看是否可以发现错误,但我不能。

[16]> (macroexpand-1 `(do-primes-v3 (p 10 25) (format t "~d " p)))
(DO
 ((#:G3502 10) (#:G3503 25)
  (P (IF (IS-PRIME #:G3502) #:G3502 (NEXT-PRIME-AFTER #:G3502))
     (NEXT-PRIME-AFTER P)))
 ((> P #:G3503)) (FORMAT T "~d " P)) ;

最佳答案

使用 DO* 而不是 DO

DO 在绑定(bind)可见的范围内初始化绑定(bind)。 DO* 在绑定(bind) 可见的范围内初始化绑定(bind)。

在这种特殊情况下,var 需要引用其他绑定(bind) loop-start

关于lisp - 以下使用 gensym 的 Common Lisp 宏有什么问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/553281/

相关文章:

dynamic - 当 "parent"缓冲区具有我绑定(bind)的同名局部变量时,为什么 with-temp-buffer 中的代码会提示 void 变量?

lisp - 是否有一个简单的 lisp 等效于 Python 的生成器?

common-lisp - 通过 Emacs 离线查看 Common Lisp HyperSpec

lisp - 为什么 llvm 上没有好的方案/lisp?

character-encoding - 如何处理 Common Lisp (SBCL) 中的重音符号?

emacs - 如何在 Emacs Lisp 中创建列 View ?

scheme - 无法对 Racket 中的用户输入使用 eval

version-control - 我该如何将 Lisp 代码拆分成多个源文件?

Lisp - "Trying to bind a non symbol"错误

arrays - Lisp 为什么我的对象是同一个实例?