SICStus Prolog 4.7.1中attribute_goal/2的残留目标丢失问题
SICStus Prolog 属性残留目标消失问题分析
问题代码
:- module(attach, [attach/1]). :- use_module(library(atts)). :- attribute a/0. attach(X) :- put_atts(X,a). verify_attribute(_,_,[]). attribute_goal(V,attach(V)) :- get_atts(V,a), put_atts(V,-a).
查询执行结果
| ?- attach(X), copy_term(X,Xc,Xcc), copy_term(X,Yc,Ycc). Xcc = attach:attach(Xc), Ycc = true ?
核心疑问
- 第二次
copy_term/3的残留目标为何消失? attribute_goal/2中的put_atts/2操作为何未被撤销?- 此前相关问题提到内置谓词
when/2存在类似问题,二者是否有关联?
问题解析
残留目标消失的直接原因
第一次调用copy_term(X,Xc,Xcc)时,会触发attribute_goal/2钩子。你的实现中,该钩子在生成attach(V)目标的同时执行了put_atts(V,-a)——这会直接移除原变量X上的a属性。当第二次调用copy_term(X,Yc,Ycc)时,X已无任何属性,自然不会生成残留目标,因此Ycc = true。put_atts/2操作未被撤销的原因copy_term/3处理属性时,不会自动回溯撤销attribute_goal/2中的副作用。attribute_goal/2的设计允许钩子谓词产生副作用(如清理属性、更新状态),这类操作不属于Prolog的回溯语义范畴,除非在钩子内部显式使用setup_call_cleanup/3等机制处理回溯。与
when/2问题的关联when/2的类似问题本质一致:这类内置谓词处理约束或属性时,会调用用户定义的钩子逻辑,而钩子中的副作用不受Prolog回溯机制管理,最终导致非预期的状态变更。
修正方案
若希望每次copy_term/3都能基于原变量属性生成残留目标,需移除attribute_goal/2中的put_atts(V,-a)操作,修改后的钩子代码如下:
attribute_goal(V,attach(V)) :- get_atts(V,a).
修改后,两次copy_term/3都会生成对应残留目标,执行查询会得到:
| ?- attach(X), copy_term(X,Xc,Xcc), copy_term(X,Yc,Ycc). Xcc = attach:attach(Xc), Ycc = attach:attach(Yc) ?
内容的提问来源于stack exchange,提问作者repeat
相关产品推荐
相关产品推荐

