当前位置:  开发笔记 > 编程语言 > 正文

为什么CLISP无法使用未加工名称调用某些函数?

如何解决《为什么CLISP无法使用未加工名称调用某些函数?》经验,为你挑选了1个好方法。

我编写了一个特殊的解析器生成器,它创建代码将旧的和鲜为人知的7位字符集转换为unicode.对解析器生成器的调用扩展为defun包含在a中的一堆s progn,然后进行编译.我只想将生成的defuns中的一个 - 顶级的 - 暴露给系统的其余部分; 所有其他内容都是解析器的内部,只能从顶层的动态范围内调用.因此,defun生成的其他s具有未处理的名称(用其创建gensym).这个策略适用于SBCL,但我最近使用CLISP进行了第一次测试,我得到的错误如下:

*** - FUNCALL: undefined function #:G16985

似乎CLISP无法处理具有未分隔名称的函数.(有趣的是,系统编译没有问题.)编辑:在大多数情况下,它似乎可以处理具有未分隔名称的函数.请参阅下面的Rörd的答案.

我的问题是:这是CLISP的一个问题,还是Common Lisp的限制,某些实现(例如SBCL)碰巧被克服了?

编辑:

例如,顶级生成函数(被调用)的宏扩展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指出这是由于长期存在的CLISP错误.



1> Rörd..:

你没有显示给出错误的一行,所以我只能猜测,但就我所见,唯一可能导致这个问题的是你指的是符号的名称,而不是试图称它时符号本身.

如果您指的是符号本身,那么您的所有lisp实现都必须查找该符号symbol-function.是否实习并不重要.

请问为什么你没有考虑另一种隐藏函数的方法,即一个labels语句或在一个只导出一个外部函数的新包中定义函数?

编辑:以下示例从与CLISP提示的交互中逐字复制.

如您所见,调用gensym命名的函数正在按预期工作.

[1]> (defmacro test ()
(let ((name (gensym)))
`(progn
(defun ,name () (format t "Hello!"))
(,name))))
TEST
[2]> (test)
Hello!
NIL

也许你试图调用函数的代码在之前被评估defun?如果宏扩展中除了各种defuns 之外还有任何代码,它可能是依赖于实现的,首先得到的是什么,因此SBCL和CLISP的行为可能会有所不同而没有任何违反标准的行为.

编辑2:一些进一步的调查表明,CLISP的行为取决于代码是直接解释还是首先编译然后解释.您可以通过load在CLISP中直接使用Lisp文件或首先调用compile-file它然后再load使用FASL 来查看差异.

您可以通过查看CLISP提供的第一次重启来查看正在发生的事情.它说的是"输入要使用的值而不是(FDEFINITION'#:G3219)." 因此,对于已编译的代码,CLISP引用符号并按名称引用它.

虽然这种行为似乎符合标准.可以在HyperSpec中找到以下定义:

功能标志 ñ.功能的指示符; 也就是说,一个表示函数的对象,它是以下之一:符号(表示在全局环境中由该符号命名的函数),或函数(表示自身).如果将符号用作函数指示符但是它没有作为函数的全局定义,或者它具有作为宏或特殊形式的全局定义,则后果是未定义的.另请参见扩展函数指示符.

我认为一个未处理的符号匹配"一个符号被用作函数指示符,但它没有一个全局定义作为一个函数",用于未指明的后果.

编辑3 :(我可以同意,我不确定CLISP的行为是否是一个错误.对标准术语的细节更有经验的人应该判断这一点.它归结为是否是一个未加工符号的功能单元 - 即只能通过直接保留符号对象而不能通过名称引用的符号 - 将被视为"全局定义"或不符合

无论如何,这是一个示例解决方案,通过实现一次性包中的符号来解决CLISP中的问题,避免了未处理符号的问题:

(defmacro test ()
  (let* ((pkg (make-package (gensym)))
         (name (intern (symbol-name (gensym)) pkg)))
    `(progn
       (defun ,name () (format t "Hello!"))
       (,name))))

(test)

编辑4:正如Joshua Taylor在对该问题的评论中指出的那样,这似乎是(10岁)CLISP错误#180的情况.

我测试过该bug报告建议两种解决方法,发现更换prognlocally实际上没有帮助,但取代它let ()呢.

推荐阅读
可爱的天使keven_464
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有