You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在SBCL中运行DO循环时出现COMMON-LISP:PROGN未定义变量错误

Common Lisp中PROGN未绑定错误的排查

问题场景

在MacOS Sonoma 14.2.1系统上使用SBCL 2.4.1版本编写了以下Common Lisp函数,运行时出现PROGN未绑定的错误。此前在GNU CLISP中多次正常使用该写法,且程序其他部分使用PROGN也无问题。

原函数代码

(defun getEndLoop(n)
    (let ((lpCntThrshld 8192)) ; To be safe and avoid any possible infinite loop.
        (do ((count 0 (+ count 1)) (token n (collatzNext token PrimeList))
             ; tail implements a mechanism to detect loops in the flow of values.
             (tail n (if (and (eq stage 0) (eq (mod count 2) 1))
                        (collatzNext tail PrimeList) tail))
                 (stage 0 (if (and (> count 0) (eql token tail)) 1 stage)))

            (progn
                (if (> count lpCntThrshld) (return-from getEndLoop (list -1 fnID n)))

                (if (eq stage 1) ;(and (> count 0) (eql token tail))
                                (progn
                                    (format t "stage=~a" stage)
                                    (return-from getEndLoop NIL)
                                )
                        ))
        ) ; End do.
    ) ; End getEndLoop-let.
) ; End getEndLoop.

错误信息

; caught WARNING:
;   undefined variable: COMMON-LISP:PROGN
; 
; compilation unit finished
;   Undefined variable:
;     PROGN
;   caught 1 WARNING condition
Unhandled UNBOUND-VARIABLE in thread #<SB-THREAD:THREAD "main thread" RUNNING
                                {7005550003}>:
  The variable PROGN is unbound.

错误原因

问题出在DO循环的语法误用:
Common Lisp标准中DO的语法结构是:

(DO (variable-clause*) 
    (end-test-form result-form*) 
  declaration* 
  form*)

你错误地将原本属于**循环体(form*)的代码用PROGN包裹后,放在了结束测试(end-test-form)**的位置(也就是DO的第二个参数位置)。SBCL严格遵循标准,将该位置的PROGN视为普通变量而非特殊运算符,因此抛出“未绑定变量”的错误。CLISP对语法的宽容度更高,允许这种非标准写法,所以之前在CLISP中能正常运行。

修正后的代码

调整DO的结构,将结束条件与返回值逻辑放在第二个参数区域,循环体按需放在第三个参数区域:

(defun getEndLoop(n)
    (let ((lpCntThrshld 8192)) ; To be safe and avoid any possible infinite loop.
        (do ((count 0 (+ count 1)) 
             (token n (collatzNext token PrimeList))
             ; tail implements a mechanism to detect loops in the flow of values.
             (tail n (if (and (eq stage 0) (eq (mod count 2) 1))
                        (collatzNext tail PrimeList) 
                        tail))
             (stage 0 (if (and (> count 0) (eql token tail)) 
                        1 
                        stage)))
            ;; 结束测试:满足任一条件则退出循环
            ((or (> count lpCntThrshld) (eq stage 1))
             ;; 退出时的返回值逻辑
             (cond
               ((> count lpCntThrshld) (list -1 fnID n))
               ((eq stage 1) 
                (format t "stage=~a" stage)
                NIL)))
            ;; 循环体:每次迭代执行的额外操作(此处无需额外代码,逻辑已整合到结束测试)
        ) ; End do.
    ) ; End getEndLoop-let.
) ; End getEndLoop.

内容的提问来源于stack exchange,提问作者Michel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 15:24:49