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
相关产品推荐
相关产品推荐

