【发布时间】:2013-10-10 05:59:44
【问题描述】:
我编写了一个临时解析器生成器,它创建代码以将旧的和鲜为人知的 7 位字符集转换为 unicode。对解析器生成器的调用扩展为一组包含在progn 中的defuns,然后被编译。我只想将生成的defuns 之一——顶层的一个——暴露给系统的其余部分;所有其他都是解析器内部的,并且只能从顶级解析器的动态范围内调用。因此,生成的其他defuns 具有非内部名称(使用gensym 创建)。此策略适用于 SBCL,但我最近首次使用 CLISP 对其进行了测试,我收到如下错误:
*** - FUNCALL: undefined function #:G16985
似乎 CLISP 无法处理具有非内部名称的函数。 (有趣的是,系统编译时没有问题。) 编辑: 在大多数情况下,它似乎可以处理具有非内部名称的函数。请参阅下面 Rörd 的答案。
我的问题是:这是 CLISP 的问题,还是某些实现(例如 SBCL)碰巧克服的 Common Lisp 的限制?
编辑:
例如,顶级生成函数(称为parse)的宏扩展有如下表达式:
(PRINC (#:G75735 #:G75731 #:G75733 #:G75734) #:G75732)
评估这个表达式(通过调用parse)会导致类似上面的错误,即使该函数肯定是在同一个宏扩展中定义的:
(DEFUN #:G75735 (#:G75742 #:G75743 #:G75744) (DECLARE (OPTIMIZE (DEBUG 2)))
(DECLARE (LEXER #:G75742) (CONS #:G75743 #:G75744))
(MULTIPLE-VALUE-BIND (#:G75745 #:G75746) (POP-TOKEN #:G75742)
...
#:G75735 的两个实例绝对是同一个符号——而不是同名的两个不同符号。正如我所说,这适用于 SBCL,但不适用于 CLISP。
编辑:
SO 用户 Joshua Taylor 指出这是由于a long standing CLISP bug。
【问题讨论】:
-
印刷表示中的符号相同。然而,当你写
#:foo之类的东西时,读者会创建一个新符号,因此,例如,输入你的 REPL,你会得到(eq '#:foo '#:foo) ;=> nil。您是否尝试通过输入函数名称来调用该函数? -
@JoshuaTaylor 正如我在帖子中所说,这些符号是相同的符号。宏只调用一次
gensym,并将结果放在展开式中的多个位置。当然,读取宏扩展会导致创建两个不同的符号,但事实并非如此。 -
你能生成一些直接的代码来重现这个问题吗?我可以编写一个宏来定义一些相互递归的函数,这些函数由非内部符号命名,并且在 CLISP 中运行良好。参见,例如,pastebin.com/7MNGkgta。它有两个函数的名字是不固定的,一个函数的名字很容易调用,而且它似乎工作正常。
-
@JoshuaTaylor 如果不将其简化到据我所知,它可能开始起作用的地步,我真的无法做到这一点。如果您想给我发电子邮件(nbtrap AT nbtrap DOT com),我可以将实际项目代码发送给您,您会看到,该代码在 SBCL 上运行良好,但在 CLISP 下运行良好。问题是生成解析器的宏过于复杂,无法在此处简化为示例,尽管它生成的代码相当简单(大量
case表达式的集合)。 -
哦,一些额外的谷歌搜索可能会出现这种情况:看看这个错误报告#180 uninterned symbols not shared between forms in FAS file。我发现它是从this mailing list discussion 链接的。这与您的实际代码有关吗?也可以看看#281 Lexical Binding in Toplevel PROGN (Clisp 2.35)。
标签: lisp common-lisp sbcl clisp