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

Codewars中Common Lisp的find-symbol需显式包名问题咨询

Common Lisp包环境差异导致find-symbol失效的问题解析

问题背景

我在Codewars上解决编程挑战,使用SBCL和Rove进行测试,需要将字符串转换为符号。Codewars要求代码必须放在包内才能被识别,我的示例代码如下:

(defpackage #:challenge/solution
  (:use #:cl)
  (:export #:function-to-test))
(in-package #:challenge/solution)

(defun function-to-test (str)
  (let ((symbols (print '(A B C D E F G H I))))
       (print (find-symbol  (string-upcase str)))
  ))

调用代码:

(function-to-test  "C" 1)

本地运行输出:

(A B C D E F G H I) 
C 

但Codewars服务器运行输出:

(CHALLENGE/SOLUTION::A CHALLENGE/SOLUTION::B CHALLENGE/SOLUTION::C
 CHALLENGE/SOLUTION::D CHALLENGE/SOLUTION::E CHALLENGE/SOLUTION::F
 CHALLENGE/SOLUTION::G CHALLENGE/SOLUTION::H CHALLENGE/SOLUTION::I) 
NIL

只有显式指定符号所在包才能正常运行:

(find-symbol  (string-upcase str) :challenge/solution)

问题原因

  • find-symbol的查找规则:find-symbol默认在当前动态包环境中查找符号,而非函数定义所在的包。
  • 环境差异:
    • 本地运行时,你是在challenge/solution包的上下文里调用函数,find-symbol默认在此包内查找,所以能找到目标符号。
    • Codewars服务器调用函数时,是在其他包(比如CL-USER)的上下文执行,此时find-symbol在调用者的包内查找,而你的A/B/C等符号仅属于challenge/solution包,因此返回NIL。
  • 符号归属:代码中'(A B C ...)是在challenge/solution包的编译/读取阶段创建的,所以这些符号明确属于该包——服务器输出里的CHALLENGE/SOLUTION::C(双冒号表示符号属于指定包且未导出)也验证了这一点。

替代方案(无需硬编码包名)

  • 保存编译期包环境:
    通过eval-when将函数定义所在的包(编译时的*package*)保存为参数,后续查找时直接使用:
    (defpackage #:challenge/solution
      (:use #:cl)
      (:export #:function-to-test))
    (in-package #:challenge/solution)
    
    ;; 保存当前包的编译期值,确保任何时候都能正确引用
    (eval-when (:compile-toplevel :load-toplevel :execute)
      (defparameter *solution-package* *package*))
    
    (defun function-to-test (str)
      (let ((symbols '(A B C D E F G H I)))
        (print symbols)
        (print (find-symbol (string-upcase str) *solution-package*))))
    
  • 从已有符号获取包:
    既然已经有了symbols列表中的符号,可以直接提取其中一个符号的包作为查找上下文:
    (defun function-to-test (str)
      (let ((symbols '(A B C D E F G H I)))
        (print symbols)
        (print (find-symbol (string-upcase str) (symbol-package (first symbols))))))
    
  • 词法绑定当前包:
    在函数内部将*package*绑定到目标包,强制find-symbol在该包内查找:
    (defun function-to-test (str)
      (let ((*package* (find-package '#:challenge/solution)))
        (let ((symbols '(A B C D E F G H I)))
          (print symbols)
          (print (find-symbol (string-upcase str))))))
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 21:52:47