首页 > 解决方案 > Clozure Common Lisp 中的 Sharpsign dot 宏

问题描述

我想在宏的情况下使用常量变量,如“Common Lisp Recipes”一书推荐的那样。

不幸的是,它在 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。

标签: lispcommon-lispccl

解决方案


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"))然而,我可能错了:我已经很长时间没有从法医上阅读规范了。


推荐阅读