这是另一个尝试:
unify_sto(X,Y):-
unify_with_occurs_check(X,Y) -> true ;
(
term_general(X, Y, XG, YG),
\+(unify_sto1(XG,YG)),
throw(error(type_error(acyclic,unify(X,Y)),_))
).
unify_sto1(X, Y):-
unify_with_occurs_check(X,Y).
unify_sto1(X, Y):-
X\=Y.
term_general(X, Y, XG, YG):-
((var(X) ; var(Y)) -> (XG=X, YG=Y) ;
((
functor(X, Functor, Len),
functor(Y, Functor, Len),
X=..[_|XL],
Y=..[_|YL],
term_general1(XL, YL, NXL, NYL)
) ->
(
XG=..[Functor|NXL],
YG=..[Functor|NYL]
) ;
( XG=_, YG=_ )
)).
term_general1([X|XTail], [Y|YTail], [XG|XGTail], [YG|YGTail]):-
term_general(X, Y, XG, YG),
term_general1(XTail, YTail, XGTail, YGTail).
term_general1([], [], [], []).
它首先尝试 unify_with_occurs_check,如果不成功,则继续构建两个更通用的术语,遍历每个术语的结构。
- 如果任一术语是变量,则将这两个术语保持原样。
- 如果这两个术语是同一个原子,或者它们都是具有相同函子和元数 [*] 的复合术语,它会遍历其参数,为它们创建一个更通用的术语。
- 否则,它会为每个术语分配一个新的变量。
然后它再次尝试 unify_with_occurs_check 更通用的术语来测试非循环统一并相应地抛出错误。
[*]在复合术语中对 arity 的测试是贪婪地完成的,因为 OP 声明只使用在此链接term_general1/4
的第 1 部分中定义的内置谓词与不包含的内置谓词将失败递归。length/2
. (已编辑:在调用 term_general1 之前 添加了两个functor/3
测试函子和参数的调用,以便在它们的参数不匹配时不尝试检查内部术语)
例如:
?- unify_sto(s(1)+A,A+s(B)).
A = s(1),
B = 1
?- unify_sto(1+A,2+s(A)).
ERROR: Type error: `acyclic' expected, found `unify(1+_G5322,2+s(_G5322))'
?- unify_sto(a(1)+X,b(1)+s(X)).
ERROR: Type error: `acyclic' expected, found `unify(a(1)+_G7068,b(1)+s(_G7068))'
编辑 2015 年 6 月 2 日:
上述解决方案对查询失败:
unify_sto(A+A,a(A)+b(A)).
是否不会产生统一错误。
这里对处理每个子项成对并在发现错误时立即产生错误的算法进行了改进:
unify_sto(X,Y):-
unify_with_occurs_check(X,Y) -> true ;
(
term_general(X, Y, unify(X,Y), XG, YG),
\+unify_with_occurs_check(XG,YG),
throw(error(type_error(acyclic,unify(X,Y)),_))
).
unify_sto1(X, Y):-
unify_with_occurs_check(X,Y).
unify_sto1(X, Y):-
X\=Y.
term_general(X, Y, UnifyTerm, XG, YG):-
((var(X) ; var(Y)) -> (XG=X, YG=Y) ;
((
functor(X, Functor, Len),
functor(Y, Functor, Len),
X=..[Functor|XL],
Y=..[Functor|YL],
term_general1(XL, YL, UnifyTerm, NXL, NYL)
) ->
(
XG=..[Functor|NXL],
YG=..[Functor|NYL]
) ;
( XG=_, YG=_ )
)).
term_general1([X|XTail], [Y|YTail], UnifyTerm, [XG|XGTail], [YG|YGTail]):-
term_general(X, Y, UnifyTerm, XG, YG),
\+(unify_with_occurs_check(XG,YG))-> throw(error(type_error(acyclic,UnifyTerm),_)) ;
term_general1(XTail, YTail, UnifyTerm, XGTail, YGTail).
term_general1([], [], _, [], []).
在原始答案中产生错误结果的查询的测试用例:
?- unify_sto(A+A,a(A)+b(A)).
ERROR: Type error: `acyclic' expected, found `unify(_G6902+_G6902,a(_G6902)+b(_G6902))'
?- unify_sto(A+A, a(_)+b(A)).
ERROR: Type error: `acyclic' expected, found `unify(_G5167+_G5167,a(_G5173)+b(_G5167))'