Common lisp 将包名称添加到符号

Common lisp 将包名称添加到符号,common-lisp,symbols,Common Lisp,Symbols,这是特定语境下的一般符号问题。我想我需要回答的问题是:给定一个包含符号'foo'的参数,我如何操作符号的包部分,使其成为'package:foo'的eql 更具体的上下文:有一个单元测试包fiveam,它将测试函数存储在一个哈希表(it.bese.fiveam::*tests)中,该哈希表的键类似于package::test name,该哈希表指向包含测试的对象。要运行测试,通常会传递到run函数一个作为散列键的符号:(run!'package::test name。如果我从定义测试的tests

这是特定语境下的一般符号问题。我想我需要回答的问题是:给定一个包含符号'foo'的参数,我如何操作符号的包部分,使其成为'package:foo'的eql

更具体的上下文:有一个单元测试包fiveam,它将测试函数存储在一个哈希表(
it.bese.fiveam::*tests
)中,该哈希表的键类似于
package::test name
,该哈希表指向包含测试的对象。要运行测试,通常会传递到
run函数一个作为散列键的符号:
(run!'package::test name
。如果我从定义测试的
tests
包中调用
run!
,我可以在
(run!test name)
上执行C-x C-e操作。从SLIME REPL调用时,我必须执行
(tests::run!'!tests::tests::test name)
,这是一个轻微的不便

我想用
(run!test name)
从cl-user运行测试,并省略包名。我原以为包装
run!
并将缺少的包添加到符号中会很简单,但我所有的尝试都失败了,我想部分原因是
cl-user:test name
tests:test name
不同

所讨论的哈希表使用
eql
测试相等性。在
测试
包中:

(eql 'tests::foo 'foo) => T
在CL-USER中:

(eql 'tests::foo 'foo) => nil
各种函数可以返回符号(例如intern、make符号或format符号),但它们都不是哈希表中键的eql:

(eql (alexandria:format-symbol t "foo::bar") 'foo::bar) => nil
(eql (make-symbol "foo::bar") 'foo::bar) => nil
从SLIME/REPL/FIVEAM的上下文中提取这一点来概括我认为问题所在的地方,我不知道如何将
'bar
转换为
'foo:bar
作为符号。我可以手动将其指定为
'foo:bar
,但鉴于
'bar
,我似乎无法从eql
'foo:bar
中获得任何信息

注意:我并不真正关心为包名键入额外的几个字母。我在这里真正尝试的是提高我对范围和指定符号的理解


谢谢。

首先,我假设您知道,您可以使用扩展命令
在package
中切换到SLIME REPL中的
test
包(即,在REPL提示符下,键入逗号
,然后在package
中键入
,系统将提示您输入包名),这样的交换软件包对你来说很不方便

一种解决方案是在您当前使用的任何软件包中引入一个小助手函数:

(defun run-test (name &optional (package 'test))
   (funcall (find-symbol #.(symbol-name 'run!) package)
            (find-symbol (symbol-name name) package)))
或者更简单(假设
run!
的定义来自fiveam包,通过
:使用
:导入
测试
包中)

你现在可以称之为

(run-test 'check-everything)
请注意,我们在此处使用
find symbol
,而不是
intern
,因为我们希望符号在所有情况下都存在。如果您希望助手在任何地方都可以轻松访问,您甚至可以这样做

(defun :run (name &optional (package 'test))
   (it.bese.fiveam:run! (find-symbol (symbol-name name) package)))
现在你可以称之为

(:run 'check-everything)
不管当前的包是什么,请注意,我只建议在REPL.clobbing全局名称空间(如关键字函数名称空间)中使用的帮助程序使用这种方法,我觉得这样做有点可疑


只是为了更好的衡量:给出的代码都没有经过测试(甚至没有通过REPL),所以要小心。另外,我衷心建议您阅读CLHS中的,这应该被认为是最终的源代码™ 对于这些东西。

首先,我假设,您知道,您可以在SLIME REPL中使用扩展命令
在package
中切换到
test
包(即,在REPL提示符下,键入逗号
,然后在package
中键入
,系统将提示您输入包名),这样的交换软件包对你来说很不方便

一种解决方案是在您当前使用的任何软件包中引入一个小助手函数:

(defun run-test (name &optional (package 'test))
   (funcall (find-symbol #.(symbol-name 'run!) package)
            (find-symbol (symbol-name name) package)))
或者更简单(假设
run!
的定义来自fiveam包,通过
:使用
:导入
测试
包中)

你现在可以称之为

(run-test 'check-everything)
请注意,我们在此处使用
find symbol
,而不是
intern
,因为我们希望符号在所有情况下都存在。如果您希望助手在任何地方都可以轻松访问,您甚至可以这样做

(defun :run (name &optional (package 'test))
   (it.bese.fiveam:run! (find-symbol (symbol-name name) package)))
现在你可以称之为

(:run 'check-everything)
不管当前的包是什么,请注意,我只建议在REPL.clobbing全局名称空间(如关键字函数名称空间)中使用的帮助程序使用这种方法,我觉得这样做有点可疑


只是为了更好的衡量:给出的代码都没有经过测试(甚至没有通过REPL),所以要小心。另外,我衷心建议您阅读CLHS中的,这应该被认为是最终的源代码™ 对于这些内容。

您可以使用该功能导入所需的符号:

(import '(fiveam:run! my-tests::foo))
这会将两个符号导入到当前包中(您也可以将另一个包作为另一个参数)

(run! 'foo)

如果在某些尝试失败后尝试此导入,则可能会进入调试器,在调试器中可以选择适当的重新启动来解决同名符号之间的冲突(如“TAKE NEW”)。

您可以使用该函数导入所需的符号:

(import '(fiveam:run! my-tests::foo))
这会将两个符号导入到当前包中(您也可以将另一个包作为另一个参数)

(run! 'foo)
如果在某些尝试失败后尝试此导入,则可能会进入调试器,在调试器中可以选择适当的重新启动来解决同名符号之间的冲突(如“TAKE NEW”)。

(查找符号(符号名称栏):foo)
将返回名为
FOO
的包中名为
BAR的符号(如果该符号在该包中驻留)。
(查找符号(符号名称“BAR”):f