Prolog:得到相反的结果

时间:2016-09-05 19:53:13

标签: prolog prolog-dif

我有以下代码:

neighbor(C1, C2, [C1, C2|L]).
neighbor(C1, C2, [C2, C1|L]).
neighbor(C1, C2, [H|L]) :- neighbor(C1, C2, L).

not_neighbors(C5, C2, E, R) :-
    not_neighbor(C5, C2, E).

not_neighbors(C5, C2, E, R) :-
    not_neighbor(C5, C2, R).

/* THIS DON'T WORK */
not_neighbor(C5, C2, E) :-
    \+ neighbor(C5, C2, E).

或者:

same_position(I, J, [I|U], [J|V]).
same_position(I, J, [M|U], [N|V]) :-
    I \== M,   % optimisation
    J \== N,   % optimisation
    same_position(I, J, U, V).

/* THIS DON'T WORK */
not_under(C4, C1, R, E) :-
    \+ same_position(C4, C1, R, E).

我知道问题在于否定,我希望得到same_position的相反结果。

微米。 @CapelliC建议我使用dif/2,但我不知道如何在我的具体例子中应用它。

2 个答案:

答案 0 :(得分:3)

让我们首先从逻辑上思考列表中“邻居”的含义:在列表中AB个邻居元素是什么情况?

回答:如果列表的格式为[...,X,Y,...]至少,则包含以下其中一项:

  • A = X B = Y
  • A = Y B = X

按逻辑术语:(A = XB = Y)∨(A = YB = X)。

我们想说明相反,这是否定公式:

((A = XB = Y)∨(A = YB = X))≡

≡¬(A = XB = Y)∧¬(A = YB = X)≡

≡(¬A = X∨¬B = Y)∧(¬A = Y∨¬B = X)≡

AXBY)∧(AY∨{{1} }≠B

谁会想到De Morgan的法律有任何实际应用,对吧?

要在Prolog中声明XX,我们会使用强大的 Y 约束,正如@CapelliC已经建议的那样。 dif/2为真 iff ,其参数为不同的条款。它是一个谓词,可以在各个方向正常运行。如果您的Prolog系统尚未提供,请确保让您的供应商知道您需要它!在此之前,如果需要,您可以使用iso_dif/2 近似

在Prolog中,上述因此变为:

( dif(A, X) ; dif(B, Y) ), ( dif(A, Y) ; dif(B, X) )

因为dif/2表示连词,而(',')/2表示 disjunction

所以我们有:

not_neighbours(_, _, []).
not_neighbours(_, _, [_]).
not_neighbours(A, B, [X,Y|Rest]) :-
        ( dif(A, X) ; dif(B, Y) ),
        ( dif(A, Y) ; dif(B, X) ),
        not_neighbours(A, B, [Y|Rest]).

一些测试用例让我们对谓词的正确性更有信心:

?- not_neighbours(a, b, [a,b]).
false.

?- not_neighbours(A, B, [A,B]).
false.

?- not_neighbours(A, B, [_,A,B|_]).
false.

?- not_neighbours(A, B, [_,B,A|_]).
false.

?- not_neighbours(a, b, [_,a,c,_]).
true .

请注意,如果所有参数都是变量,这个定义也可以正常工作,我们称之为最常见的情况。

此解决方案的一个缺点是(;)/2创建了许多替代方案,其中许多方案根本不重要。我们可以通过另一个代数等价来显着提高效率,让我们摆脱不必要的替代方案:

¬A∨B≡A→B

因此,在我们的案例中,我们可以写{((;)/2∨¬A = X)为B = YA = XB

我们可以使用强大的if_/3元谓词在Prolog中表达暗示

Y

因此我们可以声明性地将我们的解决方案写成:

not_neighbours(_, _, []).
not_neighbours(_, _, [_]).
not_neighbours(A, B, [X,Y|Rest]) :-
        impl(A=X, dif(B, Y)),
        impl(B=X, dif(A, Y)),
        not_neighbours(A, B, [Y|Rest]).

示例查询:

?- not_neighbours(a, b, [x,y]).
true ;
false.

更一般的情况:

?- not_neighbours(a, b, [X,Y]).
X = a,
dif(Y, b) ;
X = b,
dif(Y, a) ;
dif(X, b),
dif(X, a) ;
false.

您可以使用此谓词来检查生成答案的。尝试迭代深化以公平地列举所有答案:

impl(A, B) :- if_(A, B, true).

值得注意的是,纯粹的逻辑推理因此使我们成为一个普遍的高效的Prolog程序。

?- length(Ls, _), not_neighbours(A, B, Ls). 起初可能对您来说不寻常,因为它出现在第一个Prolog系统中,然后被一些供应商忽略了一段时间。如今,dif/2在越来越多的实现中变得可用(作为重要的内置谓词),允许您以声明方式声明两个术语不同。 dif/2可以避免其不纯的替代方案在Prolog课程中造成的大量混淆。

答案 1 :(得分:1)

如果您想生成非邻居,\+将无法按照定义 semidet 执行,并且永远不会绑定变量。你需要一些东西 构建答案。一种选择是生成所有对,然后使用\+ neighbor(...)过滤非邻居。直接的建设性方法也不是那么难,尽管需要两个排序使代码变得复杂一点:

not_neighbor(C1, C2, List) :-
    append(_, [C10,_|Postfix], List),
    member(C20, Postfix),
    swap(C1,C2, C10,C20).

swap(X,Y, X,Y).
swap(X,Y, Y,X).

请参阅http://swish.swi-prolog.org/p/njssKnba.pl