如果您既不想使用调试,也不想使用辅助谓词编写其他方法,第三种选择是利用 SWI-Prolog 的许多内置功能进行元编程。在这种情况下,clause/2 predicate 可能会有所帮助(它是 ISO 标准的一部分,因此其他 Prolog 方言可能也有,但我没有检查过):
子句(:Head, ?Body)
如果Head 可以与子句头部统一,Body 可以与相应的子句主体统一,则为真。给出关于回溯的替代条款。事实上,Body 与原子true 统一。
所以我们可以编写一个通用谓词expl(+Goal,-Expl),为Goal 构造一个“解释”,以防Goal 成功:
flight(sea,msp).
flight(msp,jfk).
route(A,B) :- flight(A,B).
route(B,A) :- flight(A,B).
route(A,C) :- flight(A,B) , flight(B,C).
% construct an explanation for a solution
expl([],[]).
expl([Goal|Goals],[(Goal,BodyExpl)|Expl]) :-
clause(Goal,Body),
clause_body_list(Body,BodyL),
expl(BodyL,BodyExpl),
expl(Goals,Expl).
% turn output of clause/2 into a list
clause_body_list(true,[]) :- !.
clause_body_list((A,B),[A|BL]) :- !,
clause_body_list(B,BL).
clause_body_list(A,[A]) :- !.
这会产生:
?- expl([route(sea,jfk)],X).
X = [(route(sea, jfk), [(flight(sea, msp), []), (flight(msp, jfk), [])])].
它还支持带变量的回溯和查询:
?- expl([route(A,B)],X).
A = sea,
B = msp,
X = [(route(sea, msp), [(flight(sea, msp), [])])] ;
A = msp,
B = jfk,
X = [(route(msp, jfk), [(flight(msp, jfk), [])])] ;
A = msp,
B = sea,
X = [(route(msp, sea), [(flight(sea, msp), [])])] ;
A = jfk,
B = msp,
X = [(route(jfk, msp), [(flight(msp, jfk), [])])] ;
A = sea,
B = jfk,
X = [(route(sea, jfk), [(flight(sea, msp), []), (flight(msp, jfk), [])])] ;
false.
请注意,这样的解释不一定是列表,而是通常采用(SLD)树的形式,因此是输出的嵌套结构。
编辑:进一步解释上述内容:输出是(Goal, BodyExpl) 形式的“解释”列表,其中每个Goal 是已证明的(子)目标,并且BodyExpl 再次是用于证明Goal 的所有递归子目标的此类解释的列表。事实上,BodyExpl 部分是空的。一般来说,这个结构可以嵌套任意深度(取决于你的输入程序)。
如果您觉得这很难阅读,对进一步处理输出不感兴趣,并且只想要一个人类可读的解释,您可以执行以下操作:
flight(sea,msp).
flight(msp,jfk).
route(A,B) :- flight(A,B).
route(B,A) :- flight(A,B).
route(A,C) :- flight(A,B) , flight(B,C).
% construct an explanation for a solution
expl([]).
expl([Goal|Goals]) :-
clause(Goal,Body),
clause_body_list(Body,BodyL),
expl(BodyL),
expl(Goals),
write_expl(Goal,Body).
% turn output of clause/2 into a list
clause_body_list(true,[]) :- !.
clause_body_list((A,B),[A|BL]) :- !,
clause_body_list(B,BL).
clause_body_list(A,[A]) :- !.
% write explanation
write_expl(Goal, true) :- !,
writef('%w is a fact.\n',[Goal]).
write_expl(Goal, Body) :- !,
writef('%w because of %w.\n', [Goal,Body]).
这会产生例如:
?- expl([route(sea,jfk)]).
flight(msp,jfk) is a fact.
flight(sea,msp) is a fact.
route(sea,jfk) because of flight(sea,msp),flight(msp,jfk).
请注意,您只想在对expl 进行递归调用后调用write_expl,因为某些变量可能仅在递归调用期间被实例化。