我正在安装《人工智能现代方法》这本书的代码,代码来源于这里 http://aima.cs.berkeley.edu/lisp/doc/install.html,顺便说一下,我安装的是Lisp版本
我使用的是Ubuntu Trusty,Emacs SBCL slime环境,我将代码放置在~/.emacs.d目录下
按照上述链接的指示,我运行了(load “/home/w/.emacs.d/aima/code/aima.lisp”)
加载正常,输出为”T”
我运行(aima-load ‘all),这也正常工作,输出为”T”
但是当我运行(aima-compile)时,我得到了以下错误
Can't declare constant variable locally special: +NO-BINDINGS+ [Condition of type SIMPLE-ERROR]
我不太理解这个错误,我查阅了Hyperspec关于Declare和Special的说明,但这并没有帮助。我不反对使用一些技巧来解决这个问题,所以如果有人能帮我重新编写代码,或者告诉我是否有Emacs或SBCL的设置可以更改以正确声明上述变量,那就太好了。错误消息指的是这个文件/home/w/.emacs.d/aima/code/logic/algorithms/tell-ask.lisp
这一部分
(defmethod ask-each ((kb literal-kb) query fn) "For each proof of query, call fn on the substitution that the proof ends up with." (declare (special +no-bindings+)) (for each s in (literal-kb-sentences kb) do (when (equal s query) (funcall fn +no-bindings+))))
我已经验证了aima文件夹中所有文件的权限都设置为我的用户名可读写,并且我的用户名是所有者,作为纠正措施的一部分…但就理解错误而言,我需要帮助来找出下一步调试的步骤…代码可以从这里下载 http://aima.cs.berkeley.edu/lisp/code.tar.gz,对于有经验的Emacs/Lisp用户来说,安装非常简单…任何帮助都将不胜感激。
回答:
使用SBCL:
我同样尝试加载AIMA代码,在SBCL中遇到了相同的问题。只要在./logic/algorithms/tell-ask.lisp
中注释掉这一行:
(declare (special +no-bindings+))
像这样
;;(declare (special +no-bindings+))
,或者完全删除这一行。不过,我所做的就是:
(defmethod ask-each ((kb literal-kb) query fn) "For each proof of query, call fn on the substitution that the proof ends up with." ;;(declare (special +no-bindings+)) (for each s in (literal-kb-sentences kb) do (when (equal s query) (funcall fn +no-bindings+))))
你仍然会在SBCL中运行(aims-compile)
时遇到问题。它会抱怨一些常量被重新定义。只要查看可能的重启选项,每次选择:
0: [CONTINUE] GO ahead and change the value.
根据需要重复这个操作(大约6次),最终它会加载。这可能是由于AIMA的代码非标准构建/编译系统引起的。这可能很烦人,但另一种方法是跟踪代码,看看为什么/在哪里某些文件被重新加载。
使用Clozure (CCL):
CCL在./utilities/utilities.lisp
中遇到了不同的问题。CCL预定义了true
和false
函数,因此你必须确保直接在(defun true ...)
和(defun false ...)
之前的这两行:
#-(or MCL Lispworks)
更改为:
#-(or MCL Lispworks CCL)
此外,在同一源文件中,修改for-each
宏中的error
,使其看起来像这样:
(error "~a is an illegal variable in (for each ~a in ~a ...)" var var list)
有了这些修改,CCL似乎可以正常加载AIMA代码。
总的来说:
重新定义常量或以某种方式绕过调试器重启是一个坏主意。最好的解决方案是让(defconstant ...)
只被评估一次,或许通过将它们放置在一个单独的源文件中,并确保构建系统只选择一次。
另一个解决方案在这里找到 这里,它涉及到像这样用宏包装对defconstant
的调用(借用自 这里):
(defmacro define-constant (name value &optional doc) (if (boundp name) (format t "~&already defined ~A~%old value ~s~%attempted value ~s~%" name (symbol-value name) value)) `(defconstant ,name (if (boundp ',name) (symbol-value ',name) ,value) ,@(when doc (list doc))))
然后像这样替换所有defconstant
的出现:
(defconstant +no-bindings+ '((nil)) "Indicates unification success, with no variables.")
替换为:
(define-constant +no-bindings+ '((nil)) "Indicates unification success, with no variables.")
如果你选择define-constant
“解决方案”,请确保define-constant
首先被评估。