【问题标题】:Definite Logic Program定逻辑程序
【发布时间】:2015-07-12 13:17:43
【问题描述】:

目的是实现谓词noDupl/2

这个谓词的第一个参数是要分析的列表,第二个参数是不重复的数字列表。

我无法理解下面的代码,当我编译它时,它给出了一条错误消息,指出contained 是未定义的过程,但是作为提示,它被写入我们可以用作预定义谓词containednotContained。我想我需要定义containednotContained

noDupl(XS, Res):-
   help( XS, [],Res).

help([],_,[]).
help([X|XS],Seen,[X|Res]):-
   notContained(X,XS),
   notContained(X,Seen), 
   help(XS, [X|Seen], Res).
help([X|XS],Seen,Res):-
   contained(X,Seen),
   help(XS, Seen, Res).
help([X|XS],Seen,Res):-
   contained(X,XS),
   help(XS, [X|Seen], Res).

谁能解释一下这个问题。

【问题讨论】:

    标签: prolog


    【解决方案1】:

    缺少的定义可能是:

    contained(X,[X|_]).
    contained(X,[E|Es]) :-
       dif(X, E),
       contained(X, Es).
    
    notContained(_X, []).
    notContained(X, [E|Es]) :-
       dif(X, E),
       notContained(X, Es).
    

    (我更喜欢称这些关系为memberd/2non_member/2。)

    您给出的定义为到目前为止考虑的元素添加了一个额外的参数来扩展关系。

    要理解每个子句的含义,请按照箭头方向从右到左阅读每个子句(:- 是 1970 年代的 的 ASCII 格式)。让我们采用第一条规则:

    假设X 不是XS 的元素,并且
    前提是,X 不是Seen 的元素,并且
    前提是,help(X, [X|Seen], Res) 是真的,


    那么 help([X|XS],Seen,[X|Res]) 也是真的。

    换句话说,如果X既不在已访问元素列表Seen中,也不在尚未访问的元素XS中,则它不具有重复项。

    有点难以理解的是您给出的子句是否互斥 - 严格来说,这不是您关心的问题,只要您只对声明性属性感兴趣,但最好避免这种冗余。

    这是一个例子,其中显示了这种冗余:

    ?- noDupl([a,a,a],U).
    U = [] ;
    U = [] ;
    false.
    

    理想情况下,系统会给出一个确定的答案:

    ?- noDupl([a,a,a], U).
    U = [].
    

    就个人而言,我不喜欢将事情分成太多的情况。本质上,我们可以有两个:一个是重复的,一个是没有的。

    对于可能存在确定性的情况,例如当第一个参数“充分实例化”(包括基础列表)时,可以提供正确且仍然完全确定的定义。让我们看看这个方向是否有一些答案。

    【讨论】:

      【解决方案2】:

      我已经为你注释了你的代码:

      noDupl( XS , Res ) :- % Res is the [unique] set of element from the bag XS
        help( XS, [],Res)    % if invoking the helper succeeds.
        .                    %
      
      help( []     , _    , []      ) .  % the empty list is unique.
      help( [X|XS] , Seen , [X|Res] ) :- % A non-empty list is unique, if...
         notContained(X,XS),             % - its head (X) is not contained in its tail (XS), and
         notContained(X,Seen),           % - X has not already been seen, and
         help(XS, [X|Seen], Res).        % - the remainder of the list is unique.
      help( [X|XS] , Seen , Res ) :-     % otherwise...
         contained(X,Seen) ,             % - if X has been seen,
         help(XS, Seen, Res).            % - we discard it and recurse down on the tail.
      help([X|XS],Seen,Res):-            % otherwise...
         contained(X,XS),                % - if X is in the tail of the source list, 
         help(XS, [X|Seen], Res).        % - we discard it (but add it to 'seen').
      

      您的 contained/2 和 notContained/2` 谓词可能被定义为:

      contained( X , [X|_]  ) :- ! .
      contained( X , [Y|Ys] ) :- X \= Y , contained( X , Ys ) .
      
      not_contained( _ , [] ) .
      not_contained( X , [Y|Ys] ) :- X \= Y , not_contained(X,Ys) .
      

      现在,我可能在您的代码中遗漏了一些内容,但其中存在大量冗余。你可以简单地写这样的东西(使用内置的member/2reverse/2):

      no_dupes( List , Unique ) :- no_dupes( Bag , [] , Set ) .
      
      no_dupes( [] , V , S ) .      % if we've exhausted the bag, the list of visited items is our set (in reverse order of the source)
        reverse(V,S)                % - reverset it 
        .                           % - to put our set in source order
      no_dupes( [X|Xs] , V , S ) :- % otherwise ...
        ( member(X,V) ->            % - if X is already in the set, 
          V1 = V                    % -   then we discard X
        ; V1 = [X|V]                % -   else we add X to the set 
        ) ,                         % And...
        no_dupes( Xs , V1 , S )     % we recurse down on the remainder
        .                           % Easy!
      

      【讨论】:

        【解决方案3】:

        这能否以一种纯粹而高效的方式完成? ,通过使用 tpartition/4(=)/3 就像这样:

        dups_gone([]    ,[]).
        dups_gone([X|Xs],Zs0) :-
           tpartition(=(X),Xs,Ts,Fs),
           if_(Ts=[], Zs0=[X|Zs], Zs0=Zs),
           dups_gone(Fs,Zs).
        

        一些示例地面查询(所有这些都确定地成功):

        ?- dups_gone([a,a,a],Xs).
        Xs = [].
        
        ?- dups_gone([a,b,c],Xs).
        Xs = [a, b, c].
        
        ?- dups_gone([a,b,c,b],Xs).
        Xs = [a, c].
        
        ?- dups_gone([a,b,c,b,a],Xs).
        Xs = [c].
        
        ?- dups_gone([a,b,c,b,a,a,a],Xs).
        Xs = [c].
        
        ?- dups_gone([a,b,c,b,a,a,a,c],Xs).
        Xs = [].
        

        这也适用于更一般的查询。考虑:

        ?- length(Xs,N), dups_gone(Xs,Zs).
          N = 0, Xs = [],            Zs = []
        ; N = 1, Xs = [_A],          Zs = [_A]
        ; N = 2, Xs = [_A,_A],       Zs = []
        ; N = 2, Xs = [_A,_B],       Zs = [_A,_B],    dif(_A,_B)
        ; N = 3, Xs = [_A,_A,_A],    Zs = []
        ; N = 3, Xs = [_A,_A,_B],    Zs = [_B],       dif(_A,_B)
        ; N = 3, Xs = [_A,_B,_A],    Zs = [_B],       dif(_A,_B)
        ; N = 3, Xs = [_B,_A,_A],    Zs = [_B],       dif(_A,_B), dif(_A,_B)
        ; N = 3, Xs = [_A,_B,_C],    Zs = [_A,_B,_C], dif(_A,_B), dif(_A,_C), dif(_B,_C)
        ; N = 4, Xs = [_A,_A,_A,_A], Zs = [] 
        ...
        

        【讨论】:

        • @false。谢谢!为什么不使用dcgif_//3?它更简洁——但什么是正确的名称?
        猜你喜欢
        • 1970-01-01
        • 2015-11-10
        • 2013-04-12
        • 1970-01-01
        • 1970-01-01
        • 2011-05-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多