Common Lisp 中的函数名称和动态绑定



我正在阅读Peter Norvig的Paradigms of AI。在 6.2 章中,作者使用了如下代码(不是原始代码,我挑出了令人不安的部分(:

代码片段:

(progv '(op arg) '(1+ 1)
(eval '(op arg)))

按照作者的初衷,这段代码应该返回2,但在sbcl 1.1.1中,解释器显然没有在环境中查找op,抛出op: undefined function

此实现是否特定于?因为代码必须在其他一些 lisp 上测试过。

p.s 原始代码

你可能的意思

(progv '(op arg) '(1+ 1)
  (eval '(funcall op arg)))

编辑(2013-08-21(:

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在绑定v1v2、&c.到相应的val1val2、&c.的progv中被调用,所以如果这些变量中的任何一个在code中看起来是自由的,那么当code被计算时,它们就会被绑定。

问题

我在这里看到的问题是,通过代码我们无法判断该值是要保存为变量的symbol-value还是symbol-function。因此,当您将+作为某个相应变量的值时,例如v,那么它将始终保存为varsymbol-value,而不是symbol-function
因此,当您尝试使用它时,例如(v 1 2),它将不起作用。因为函数的命名空间中没有名为 v 的函数(请参阅此处(。

那么,该怎么办呢?

可能的解决方案可以是显式检查要绑定到变量的值。如果值是函数,则应将其绑定到变量的函数值。此检查可以通过 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))))

相关内容

  • 没有找到相关文章

最新更新