您在我的第一篇文章后澄清了您的问题,但下面已经有一些讨论。为防止混淆,我不会编辑它,而是写第二个:
你不能直接把你的问题写成prolog程序有两个原因:
- 您想在没有查询的情况下解决
- 您想查看(单个)推导步骤的解决方案
因此,我们将在谓词 mi_clause 中对子句数据库进行编码,该谓词具有两个参数:头部和带有主体的列表。谓词 Clause_clause_resolvent 有 6 个参数:每个子句的头部和主体以及解析器。在这里,解析器是在第二个子句的开头与第一个子句主体的第一个元素解析的结果。反之亦然。
mi_clause(m(_P,X), [m(_Q,X), m(_R,X)]). % your original clause, anonymous variables are prefixed with _ for compiler reasons
clause_clause_resolvent( Head1, Body1, Head2, Body2, RHead, RBody) :-
copy_term(clause(Head1,Body1), clause(H1,B1)), % create a variant of the first clause
copy_term(clause(Head2,Body2), clause(H2,B2)), % same for second clause
B1 = [H2|Rest1], % the prolog execution order always uses the first literal
H1 = RHead, % head of resolvent is the same (is only resolved with the query)
append(Rest1, B2, RBody). % create the new body
cmets 应该或多或少不言自明:copy_terms 创建输入子句的变体,否则您可能会丢失解析器。然后你选择第二个子句主体的第一个元素并尝试统一。实际上,这种统一足以正确地实例化两个子句。现在我们创建我们的 resolvent 子句:第 1 子句的头部被继承(以 unifier 替换为模),resolvent 的主体是第 1 条的主体,没有在第二个子句主体的主体之前添加解析的文字。
现在试试谓词,例如在 SWI Prolog 中:
?- mi_clause(H1,B1), mi_clause(H2,B2), clause_clause_resolvent(H1,B1,H2,B2,RH,RB).
H1 = m(_G1028, _G1029),
B1 = [m(_G1034, _G1029), m(_G1040, _G1029)],
H2 = m(_G1043, _G1044),
B2 = [m(_G1049, _G1044), m(_G1055, _G1044)],
RH = m(_G1068, _G1069),
RB = [m(_G1080, _G1069), m(_G1099, _G1069), m(_G1105, _G1069)].
如您所见,H1 和 H2 是您的子句头部的变体,包含新的匿名变量。 RB 的所有元素仍然是 m(_, _G1069) 的形式,获得您期望的子句的变体。
如果您想检查一般解决步骤,请将 B1 = [H2|Rest1] 行替换为 member_of_rest(H2, B1, Rest1) 并将其定义为:
member_of_rest(X, [X|Xs], Xs).
member_of_rest(X, [H|Xs], [H|Ys]) :-
member_of_rest(X, Xs, Ys).
作为一个很好的练习,您可以通过对子句clause_resolvent 的演绎闭包来扩展程序以查看任意解析序列(您可能希望确定链接顺序,否则会遇到无限递归)。
玩得开心!