【问题标题】:Prolog : get the opposite resultProlog:得到相反的结果
【发布时间】:2016-09-05 19:53:13
【问题描述】:

我有以下代码:

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 的相反结果。

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

【问题讨论】:

  • 对不起,这里是我的“邻居”函数:neighbor(C1, C2, [C1, C2|L])。邻居(C1,C2,[C2,C1|L])。邻居(C1,C2,[H|L]):- 邻居(C1,C2,L)。
  • 你能编辑你的帖子来放吗
  • 当然可以。完成。

标签: prolog prolog-dif


【解决方案1】:

让我们首先从逻辑上思考一下列表中的“邻居”意味着什么:在什么情况下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)∧(AYBX)

谁会想到德摩根定律有任何实际应用,对吧?

要在 Prolog 中声明 XY,我们使用强大的 dif/2 约束,正如 @CapelliC 已经建议的那样。 dif/2 是真的iff 它的论点是不同的 项。它是一个谓词,可以在各个方向正确工作。如果您的 Prolog 系统还没有提供它,请确保让您的供应商知道您需要它!在此之前,如有必要,您可以近似使用iso_dif/2

在 Prolog 中,以上内容因此变为:

(差异(A,X);差异(B,Y)),(差异(A,Y);差异(B,X))

因为(',')/2 表示合取,而(;)/2 表示析取

所以我们有:

not_neighbours(_, _, [])。 not_neighbours(_, _, [_])。 not_neighbours(A, B, [X,Y|Rest]) :- (差异(A,X);差异(B,Y)), (差异(A,Y);差异(B,X)), not_neighbours(A, B, [Y|Rest])。

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

?- not_neighbours(a, b, [a,b])。 错误。 ?- not_neighbours(A, B, [A,B])。 错误。 ?- not_neighbours(A, B, [_,A,B|_])。 错误。 ?- not_neighbours(A, B, [_,B,A|_])。 错误。 ?- not_neighbours(a, b, [_,a,c,_])。 真的。

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

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

¬ A ∨ B ≡ A →乙

因此,在我们的例子中,我们可以将 (¬ A = X ∨ ¬ B = Y) 写成 A = X →BY

我们可以用强大的if_/3 元谓词在Prolog 中表达蕴涵

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

因此我们可以声明式地等效地编写我们的解决方案:

not_neighbours(_, _, [])。 not_neighbours(_, _, [_])。 not_neighbours(A, B, [X,Y|Rest]) :- 实现(A=X,差异(B,Y)), impl(B=X, 差异(A, Y)), not_neighbours(A, B, [Y|Rest])。

示例查询:

?- not_neighbours(a, b, [x,y])。 ; 错误的。

还有一个更一般的情况:

?- not_neighbours(a, b, [X,Y])。 X = 一个, 差异(Y,b); X = b, 差异(Y,一); 差异(X,b), 差异(X,一); 错误的。

您可以使用此谓词检查生成答案。尝试例如迭代深化以公平枚举所有答案:

?- length(Ls, _), not_neighbours(A, B, Ls).

值得注意的是,因此,纯逻辑推理将我们引向了一个通用的高效的 Prolog 程序。

dif/2 起初对您来说可能不寻常,因为它出现在第一个 Prolog 系统中,然后被一些供应商忽略了一段时间。如今,dif/2 作为一个重要的内置谓词在越来越多的实现中(再次)变得可用,它允许您以声明方式声明两个术语是不同的。使用 dif/2 可以避免其不纯的替代方案通常在 Prolog 课程中引起的巨大混乱。

【讨论】:

    【解决方案2】:

    如果你想生成非邻居,\+ 不会按照定义 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

    【讨论】:

      猜你喜欢
      • 2012-11-10
      • 2019-02-26
      • 1970-01-01
      • 1970-01-01
      • 2016-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多