lisp - Clozure Common Lisp 中的 Sharpsign dot 宏
问题描述
我想在宏的情况下使用常量变量,如“Common Lisp Recipes”一书推荐的那样。
- 10-2。在 CASE 宏中使用常量变量作为键
不幸的是,它在 Clozure CL 中不起作用。
(defpackage #:foo
(:use #:cl))
(in-package #:foo)
(defconstant +one+ 1)
(defconstant +two+ 2)
(defun lol (gg)
(ecase gg
(#.+one+ :one)
(#.+two+ :two)))
此代码无法加载。
Unbound variable: FOO::+ONE+
[Condition of type UNBOUND-VARIABLE]
Restarts:
0: [CONTINUE] Retry getting the value of FOO::+ONE+.
1: [USE-VALUE] Specify a value of FOO::+ONE+ to use this time.
2: [STORE-VALUE] Specify a value of FOO::+ONE+ to store and use.
该代码在 SBCL 中运行良好。为什么它在 CCL 中不起作用?
我在 macOS 上使用 64 位 Clozure CL 1.12。
解决方案
CCL 会很乐意为我加载这个文件的源代码,我相信任何 CL 都应该这样做。
它不会做的,如果任何 CL 会做,我会感到惊讶的是,编译它。它不会编译它,因为defconstant
没有在编译时定义常量。这意味着,在lol
编译时,会引用一个尚未定义的变量。
如果你想像这样对待常量,你需要确保变量是在编译时定义的。有两种方法可以做到这一点:
首先,您可以添加合适eval-when
的 ery,之后相关的源代码块将是:
(eval-when (:compile-toplevel :load-toplevel :execute)
(defconstant +one+ 1)
(defconstant +two+ 2))
(defun lol (gg)
(ecase gg
(#.+one+ :one)
(#.+two+ :two)))
第二种是将常量放在自己的文件中,该文件在使用之前编译和加载。通常使用 ASDF 等系统定义工具进行管理。
注意:我相信任何 CL 都应该能够加载源代码,因为我认为,在加载源代码文件时,即使是仅编译器实现也需要一次处理它们:我认为这是不合法的换句话说(load "foo.lisp")
,变成。(load (compile-file "foo.lisp"))
然而,我可能错了:我已经很长时间没有从法医上阅读规范了。
推荐阅读
- java - 如何递归地做我的金字塔数字模式?
- sql - CTE 问题(带有..as 构造)
- mysql - 如何搜索所有表记录,如果不存在记录创建一个新的空?
- python - 获取推文中提到的所有用户及其用户 ID
- django - 从 Heroku Git 存储库中删除密钥
- powerbi - 数据查询模型中的月比百分比
- python-3.x - 为什么 python 为共享锁抛出“multiprocessing.managers.RemoteError”?
- javascript - 为什么当我选择超过 10 天时条件不起作用?
- python - 使用 CTRL+Z 终止 python2 脚本和服务
- java - RestTemplate 调用外部 API(Cloudflare 服务器)时被禁止