Prolog 差异例程

4

我需要帮助创建一种例行程序。我需要创建一个类似以下的例行程序:

difference([(a,b),(a,c),(b,c),(d,e)],[(a,_)],X).

X = [(b,c),(d,e)].

我在这个问题上真的需要帮助。

我已经写了一个方法,可以删除它找到的第一个出现.. 但是我需要删除所有出现。以下是我目前为止的代码...

memberOf(A, [A|_]).
memberOf(A, [_|B]) :-
    memberOf(A, B).

mapdiff([], _, []) :- !.
mapdiff([A|C], B, D) :-
        memberOf(A, B), !,
        mapdiff(C, B, D).
mapdiff([A|B], C, [A|D]) :-
        mapdiff(B, C, D).

我从列表(subtract)中获取了这段代码。

虽然我不完全理解它的作用,但我知道它几乎是我想要的。我没有使用subtract,因为我的最终代码必须与WIN-Prolog兼容...我正在SWI Prolog上进行测试。


你的代码在SWI-Prolog和GNU-Prolog中对我有效。我不了解WIN-Prolog,所以无法为你提供帮助。 - Stephan202
1
它能够工作,但它不能移除所有的A出现。它只会移除第一个。 - SteveW
1
你说得对。我不知道为什么看错了(?). 我想问题出在成员检查执行了统一操作,因此在第一次测试后(a, _)变成了(a, b),这将不再与(a, c)匹配。我正在考虑一个好的解决方案... - Stephan202
不好意思,我希望一些更熟练的Prolog用户能够帮助你。(我应该花时间写我的论文 :)) - Stephan202
3个回答

4

有点棘手!谦卑的咖啡有一个正确的想法。这里提供了一种使用双重否定的花哨解决方案:

difference([], _, []).
difference([E|Es], DL, Res) :-
    \+ \+ member(E, DL), !,
    difference(Es, DL, Res).
difference([E|Es], DL, [E|Res]) :-
    difference(Es, DL, Res).

适用于SWI-PROLOG. 说明:

第1条款: 基本情况。没有任何东西可与之相比较!

第2条款: 如果E在差异列表DL中,那么member/2子目标将评估为true,但我们不想接受member/2在项中存在的变量之间创建的绑定,例如,我们希望变量在术语(a,_)中是可重复使用的,而不绑定到第一个解决方案。因此,第1个\+消除了由于成功评估member/2而创建的变量绑定,第二个\+将评估状态翻转为所需的true。剪切发生在检查之后,排除第3条款,并丢弃可统一元素。

第3条款: 保留两个列表中均不可统一的任何元素。


3

我不确定,但是类似这样的东西可能会起作用。您可以使用findall查找所有不能与模式统一的元素:

?- findall(X, (member(X, [(a,b),(b,c),(a,c)]), X \= (a,_)), Res).

获取回复

Res = [ (b, c) ]

所以
removeAll(Pattern, List, Result) :-
  findall(ZZ109, (member(ZZ109, List), ZZ109 \= Pattern), Result).

假设Pattern中没有变量ZZ109,那么这个应该可以工作(不幸的是我不知道如何获取一个新的变量,可能在WIN-Prolog中有一个非便携式的方法)。然后可以递归定义difference

difference(List, [], List).
difference(List, [Pattern|Patterns], Result) :- 
  removeAll(Pattern, List, Result1),
  difference(Result1, Patterns, Result).

2
ZZ109是一个新的变量。在内部,Prolog会更改变量的名称。只有在同一条子句中明确使用ZZ109时,它才会是相同的变量。也就是说:Pattern中的ZZ109可能在内部重命名为_123,而差异子句中的ZZ109将被重命名为_314。不用担心这个问题...不过这是一个好的解决方案。 - neXus

2

您可以轻松修改代码,使其正常工作,只需使memberOF谓词检查列表中是否存在一个元素,该元素可以进行一致性检查而不实际进行一致性。在SWI Prolog中,可以通过以下方式实现:

memberOf(A, [B|_]) :- unifiable(A,B,_).

但是我不熟悉WIN-PRolog,所以不知道它是否有一个谓词或运算符,仅测试参数是否可以统一。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接