我正在阅读 Peter Norvig 的人工智能范式。在第 6.2 章中,作者使用了如下代码(不是原始代码,我挑出了令人不安的部分):
代码片段:
(progv '(op arg) '(1+ 1)
(eval '(op arg)))
按照作者的初衷,这段代码应该返回2,但是在 中,解释器显然没有在环境中sbcl 1.1.1
查找opop: undefined function
,而将.
这个实现是特定的吗?由于该代码必须已经在其他一些 lisp 上进行了测试。
ps原始代码
我正在阅读 Peter Norvig 的人工智能范式。在第 6.2 章中,作者使用了如下代码(不是原始代码,我挑出了令人不安的部分):
代码片段:
(progv '(op arg) '(1+ 1)
(eval '(op arg)))
按照作者的初衷,这段代码应该返回2,但是在 中,解释器显然没有在环境中sbcl 1.1.1
查找opop: undefined function
,而将.
这个实现是特定的吗?由于该代码必须已经在其他一些 lisp 上进行了测试。
ps原始代码
你大概是说
(progv '(op arg) '(1+ 1)
(eval '(funcall op arg)))
PAIP 是在 ANSI-Common-Lisp 之前的时代编写的,因此那里的代码可能包含一些不符合标准的地方。我们可以使示例与以下版本一起工作:
(defun match-if (pattern input bindings)
"Test an arbitrary expression involving variables.
The pattern looks like ((?if code) . rest)."
(and (eval (reduce (lambda (code binding)
(destructuring-bind (var . val) binding
(subst val var code)))
bindings :initial-value (second (first pattern))))
(pat-match (rest pattern) input bindings)))
;; CL-USER> (pat-match '(?x ?op ?y is ?z (?if (eql (?op ?x ?y) ?z))) '(3 + 4 is 7))
;; ((?Z . 7) (?Y . 4) (?OP . +) (?X . 3) (T . T))
;; CL-USER> (pat-match '(?x ?op ?y (?if (?op ?x ?y))) '(3 > 4))
;; NIL
第一个位置的元素不是作为值查找,而是作为函数查找,并且函数命名空间中没有动态绑定的概念。
快速浏览后,我会说原始代码旨在在类似的上下文中进行评估
(progv '(x y) '(12 34)
(eval '(> (+ x y) 99)))
即评估提供变量替代的公式,而不是函数名称。
到目前为止,其他答案是正确的,因为正在评估的实际形式不是progv
(简单地(op arg)
)绑定的变量,但没有人提到正在评估的内容。事实上,您链接的代码中的注释提供了一个(非常)简短的解释(这是该文件中唯一使用的代码progv
):
(defun match-if (pattern input bindings)
"Test an arbitrary expression involving variables.
The pattern looks like ((?if code) . rest)."
;; *** fix, rjf 10/1/92 (used to eval binding values)
(and (progv (mapcar #'car bindings)
(mapcar #'cdr bindings)
(eval (second (first pattern))))
(pat-match (rest pattern) input bindings)))
这个想法是match-if
调用
(match-if '((?if code) . rest) input ((v1 val1) (v2 val2) ...))
并eval
用 调用(second (first pattern))
,其值为code
。但是,eval
在将, , &c.progv
绑定到对应的, , &c. 的 中调用 ,因此如果这些变量中的任何一个在 中出现自由,那么它们在被评估时被绑定。v1
v2
val1
val2
code
code
我在这里看到的问题是,通过代码我们无法判断该值是否要保存为变量的symbol-value
or symbol-function
。因此,当您将 a+
作为某个相应变量的值时,例如v
,那么它将始终保存为symbol-value
of var
,而不是 it's symbol-function
。
因此,当您尝试将其用作 时(v 1 2)
,它将无法正常工作。v
因为在函数的命名空间中没有命名函数(参见this)。
一个可能的解决方案可以是显式检查要绑定到变量的值。如果值是一个函数,那么它应该绑定到变量的函数值。这种检查可以通过fboundp
.
因此,我们可以制作一个宏functioner
和一个修改版本的match-if
. functioner
检查该值是否是一个函数,并适当地设置它。match-if
执行动态本地绑定,并允许绑定变量范围内的其他代码。
(defmacro functioner (var val)
`(if (and (symbolp ',val)
(fboundp ',val))
(setf (symbol-function ',var) #',val)
(setf ,var ,val)))
(defun match-if (pattern input bindings)
(eval `(and (let ,(mapcar #'(lambda (x) (list (car x))) bindings)
(declare (special ,@ (mapcar #'car bindings)))
(loop for i in ',bindings
do (eval `(functioner ,(first i) ,(rest i))))
(eval (second (first ',pattern))))
(pat-match (rest ',pattern) ',input ',bindings))))