【问题标题】:Prolog: having true and false valueProlog:具有真假值
【发布时间】:2017-03-17 01:51:25
【问题描述】:

我正在学习使用 SWI Prolog,并且正在学习使用列表。一个小练习是检查一个元素是否在列表中。这是我得到的:

member(X,[X|_]).
member(X,[_|T]):-member[X|T].

第一种情况按预期进行:

?- member(a,[b,a]).
true.

但第二个没有,因为似乎出现了一些回溯:

?- member(a,[a,b]).
true ;
false.

我怎样才能防止这种情况发生,即让 Prolog 只返回我 true? (我不想忽略 false。)

【问题讨论】:

  • 第一个true表示成功。 false 意味着当你用; 要求它找到更多解决方案时,它没有找到更多解决方案,所以它在那个时候返回了false。正常的 Prolog 行为。此外,member/2 是一个标准的 Prolog 谓词。你应该把你的名字命名为别的。标准谓词与您显示的行为相同。

标签: list prolog


【解决方案1】:

member/2 是一个标准的 Prolog 谓词。你应该把你的名字命名为别的。标准谓词与您显示的行为相同。

查询时:

?- member(a, [a,b]).
true ;
false.

Prolog 发现 a 匹配第一个元素并成功。列表中还有更多内容要检查,因此它会提示您进行更多检查。按; 表示“是的,请检查更多”。当它这样做时,它找不到更多的a 成员,因此产生false(在GNU Prolog 中,它会说no)。

您可以通过以下任一方式使其消失:

  • 不按;,而是按Enter,或者
  • 使用once/1:once(member(a, [a,b])),或者
  • 您可以更改谓词以在第一个子句中包含一个cut,但这是一个坏主意,因为它在一般情况下不起作用:member(X, [a,b]) 只会返回X = a 然后停止。李>

【讨论】:

    【解决方案2】:

    使用基于library(reif)memberd/2 可用于SICStus|SWI,在许多情况下,您会获得确定性:

    ?- memberd(a, [a,b]).
    true.
    
    ?- memberd(a, [a,a]).
    true.
    
    ?- memberd(a, [a,X]).
    true.
    
    ?- memberd(a, [a|Xs]).
    true.
    

    将此与member/2进行比较:

    ?- member(a, [a,b]).
       true
    ;  false.              % leftover choicepoint
    
    ?- member(a, [a,a]).
       true
    ;  true.               % redundant solution
    
    ?- member(a, [a,X]).
      true
    ; X = a.               % redundant solution
    
    ?- member(a, [a|Xs]).
       true
    ;  Xs = [a|_A]         % redundant answer
    ;  Xs = [_A, a|_B]     % redundant answer
    ;  Xs = [_A, _B, a|_C] % redundant answer
    ...
    

    在必要时,memberd/2 的实现仍然会产生不同的答案

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

    即使在这种情况下,memberd/2 也避免了 member/2 的冗余:

    ?- member(a, [X,Y]).
       X = a
    ;  Y = a.        % partially redundant
    

    这两个答案是部分多余的:X = a, Y = a 被两者都描述了!

    ?- member(a, [X,Y]), X = a, Y = a.
       X = Y, Y = a
    ;  X = Y, Y = a.    % redundant solution
    

    【讨论】:

      【解决方案3】:

      请注意,由于member(X,[X|_])member(X,[_|T]) 统一,因此任何查询都将与这两个子句统一。您需要互斥条款。由于 prolog cut 会破坏可逆性(如前所述),因此还有另一种选择:

      member(X,[X|_]).
      member(X,[Y|T]):- X \== Y, member[X|T].
      

      【讨论】:

      • 这里有个好主意,但你需要dif/2 代替(\==)/2!还有一些括号等。
      【解决方案4】:

      另一个答案很好,但也许重要的是要补充一点,member/2 在教科书中正好有这个实现,因为它使用模式匹配和统一,它可以做更多有趣的事情......

      ?- member(a(X), [a(1), b(2), c(3), a(4), b(5), a(6)]).
      X = 1 ;
      X = 4 ;
      X = 6.
      

      还有memberchk/2,仅用于测试会员资格。另一个答案也解释了如何实现。

      看来这两者是故意不一样的(为什么要不然呢?)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多