我正在尝试理解SICP here
中描述的统一算法特别是在程序“extend-if-possible”中,有一个检查(标有星号“*”的第一个地方),它检查右手“表达式”是否是已经绑定的变量在当前框架中的某些内容:
(define (extend-if-possible var val frame)
(let ((binding (binding-in-frame var frame)))
(cond (binding
(unify-match
(binding-value binding) val frame))
((var? val) ; *** why do we need this?
(let ((binding (binding-in-frame val frame)))
(if binding
(unify-match
var (binding-value binding) frame)
(extend var val frame))))
((depends-on? val var frame)
'failed)
(else (extend var val frame)))))
相关评论指出:
“在第一种情况下,如果我们尝试匹配的变量没有绑定,但我们试图匹配它的值本身就是一个(不同的)变量,有必要检查该值是否为绑定,如果是,则匹配其值。如果匹配的双方都未绑定,我们可以绑定到另一方。“
但是,我无法想到实际需要的情况。
它在谈论什么,我想想,你可能在那里有以下框架绑定:
{?y = 4}
然后被要求“extendIfPossible”绑定从?z到?y。
当出现“*”检查时,当被要求用“?y”扩展“?z”时,我们看到“?y”已经绑定到4,然后递归尝试将“?z”统一为“ 4“,这导致我们用”?z = 4“扩展框架。
如果没有检查,我们最终只会用“?z =?y”扩展框架。但在这两种情况下,只要?z还没有被其他东西束缚,我就没有看到问题。
注意,如果?z 已经已绑定到其他内容,那么代码不会到达标记为“*”的部分(我们已经递归到统一什么?z已经是匹配)。
经过深思熟虑后,我意识到可能存在某种形式的争论,即生成一个“最简单”的MGU(最常见的统一者)。例如你可能想要一个引用其他变量的变量最少的MGU ......也就是说,我们宁愿生成替换{?x = 4,?y = 4}而不是替换{?x =?y,? y = 4} ...但我不认为这种算法在任何情况下都不会保证这种行为,因为如果你要求它将“(?x 4)”与“(?y?y)”统一起来那么你仍然会结束{?x =?y,?y = 4}。如果行为无法保证,为什么会有额外的复杂性?
我的推理是否正确?如果没有,那么在生成正确的 MGU时需要进行“*”检查的反例是什么?
答案 0 :(得分:5)
这是一个很好的问题!
我认为原因是你不想以{ ?x = ?y, ?y = ?x }
之类的循环绑定结束。特别是,如果省略了检查,将(?x ?y)
与(?y ?x)
统一将为您提供上面的圆形框。通过检查,您可以获得预期的帧{?x =?y}。
框架中的循环绑定很糟糕,因为它们可能导致使用框架执行替换的函数(例如instantiate
)在无限循环中运行。
答案 1 :(得分:0)
没有它,你就不会得到最通用的统一者。还有工作要做:统一x和y。