将包名称添加到符号
Add package name to symbol
这是特定上下文中的一般符号问题。我想我需要回答的问题是:给定一个包含符号 'foo 的参数,我如何操作符号的包部分,使其等于 'package:foo?
更具体的上下文:有一个单元测试包 fiveam,它将测试函数存储在散列 table (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::test-name)
,这是一个轻微的不便。
我想 运行 使用 (run! 'test-name)
从 cl-user 进行测试并省略包名称。我认为包装 run!
并将丢失的包添加到符号中会很简单,但我的所有尝试都失败了,我猜部分原因是 CL-USER:test-name
与 tests:test-name
不同。
有问题的散列 table 使用 eql
来测试相等性。在 tests
包中:
(eql 'tests::foo 'foo) => T
在 CL-USER 中:
(eql 'tests::foo 'foo) => nil
各种函数可以 return 符号(例如 intern、make-symbol 或 format-symbol),但其中 none 与散列中的键相等 table:
(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
注意:我真的不在乎为包名称输入额外的几个字母。我在这里真正想做的是提高我对作用域和指定符号的理解。
谢谢。
首先,我假设您知道,您可以使用扩展命令 in-package
切换到 SLIME REPL 中的 test
包(即,在 REPL 提示符下,键入逗号 ,
后接 in-package
,系统会提示您输入包名),这样切换包对您来说很不方便。
一个解决方案可能是在您当前使用的任何包中引入一个小辅助函数:
(defun run-test (name &optional (package 'test))
(funcall (find-symbol #.(symbol-name 'run!) package)
(find-symbol (symbol-name name) package)))
或更简单(假设 run!
的定义来自 fiveam 包,通过 :use
或 :import
进入 test
包)
(defun run-test (name &optional (package 'test))
(it.bese.fiveam:run! (find-symbol (symbol-name name) package)))
您现在可以称其为
(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)
in 与当前包无关。请注意,我只建议将此用于打算在 REPL 中使用的助手。像这样破坏全局名称空间(如关键字函数名称空间)对我来说有点可疑。
仅供参考:none 给出的代码已经过测试(或者甚至通过了 REPL)所以要小心。另外,我衷心推荐阅读 CLHS 中的 chapter on packages and symbols,它应该被视为这些东西的终极来源™。
您可以使用函数import
导入您想要的符号:
(import '(fiveam:run! my-tests::foo))
这会将两个符号导入到您的当前包(您也可以提供不同的包作为另一个参数)。然后你可以
(run! 'foo)
如果您在几次尝试失败后尝试此导入,您可能会进入调试器,您可以在其中 select 适当的重新启动以解决同名符号之间的冲突(类似于“TAKE新”)。
这是特定上下文中的一般符号问题。我想我需要回答的问题是:给定一个包含符号 'foo 的参数,我如何操作符号的包部分,使其等于 'package:foo?
更具体的上下文:有一个单元测试包 fiveam,它将测试函数存储在散列 table (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::test-name)
,这是一个轻微的不便。
我想 运行 使用 (run! 'test-name)
从 cl-user 进行测试并省略包名称。我认为包装 run!
并将丢失的包添加到符号中会很简单,但我的所有尝试都失败了,我猜部分原因是 CL-USER:test-name
与 tests:test-name
不同。
有问题的散列 table 使用 eql
来测试相等性。在 tests
包中:
(eql 'tests::foo 'foo) => T
在 CL-USER 中:
(eql 'tests::foo 'foo) => nil
各种函数可以 return 符号(例如 intern、make-symbol 或 format-symbol),但其中 none 与散列中的键相等 table:
(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
.
'foo:bar
注意:我真的不在乎为包名称输入额外的几个字母。我在这里真正想做的是提高我对作用域和指定符号的理解。
谢谢。
首先,我假设您知道,您可以使用扩展命令 in-package
切换到 SLIME REPL 中的 test
包(即,在 REPL 提示符下,键入逗号 ,
后接 in-package
,系统会提示您输入包名),这样切换包对您来说很不方便。
一个解决方案可能是在您当前使用的任何包中引入一个小辅助函数:
(defun run-test (name &optional (package 'test))
(funcall (find-symbol #.(symbol-name 'run!) package)
(find-symbol (symbol-name name) package)))
或更简单(假设 run!
的定义来自 fiveam 包,通过 :use
或 :import
进入 test
包)
(defun run-test (name &optional (package 'test))
(it.bese.fiveam:run! (find-symbol (symbol-name name) package)))
您现在可以称其为
(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)
in 与当前包无关。请注意,我只建议将此用于打算在 REPL 中使用的助手。像这样破坏全局名称空间(如关键字函数名称空间)对我来说有点可疑。
仅供参考:none 给出的代码已经过测试(或者甚至通过了 REPL)所以要小心。另外,我衷心推荐阅读 CLHS 中的 chapter on packages and symbols,它应该被视为这些东西的终极来源™。
您可以使用函数import
导入您想要的符号:
(import '(fiveam:run! my-tests::foo))
这会将两个符号导入到您的当前包(您也可以提供不同的包作为另一个参数)。然后你可以
(run! 'foo)
如果您在几次尝试失败后尝试此导入,您可能会进入调试器,您可以在其中 select 适当的重新启动以解决同名符号之间的冲突(类似于“TAKE新”)。