Prolog separating into two lists issue

后端 未结 4 1266
太阳男子
太阳男子 2020-12-12 06:40

I have a prolog assignment.

I need to look at the first item in a list, see if its following items are the same until they are not and separate the lists by the firs

相关标签:
4条回答
  • 2020-12-12 07:26
    grab(Xs, Ys, Zs) :-
       eqprefix(Xs, Ys, Zs).
    
    eqprefix([],[],[]).
    eqprefix([X],[],[X]).
    eqprefix([X,Y|Xs], [], [X,Y|Xs]) :-
        dif(X,Y).
    eqprefix([X,X|Xs], [X|Ys], Zs) :-
       eqprefix2([X|Xs], Ys, Zs).
    
    eqprefix2([X], [X], []).
    eqprefix2([X,Y|Xs], [X], [Y|Xs]) :-
        dif(X,Y).
    eqprefix2([X,X|Xs], [X|Ys], Zs) :-
        eqprefix2([X|Xs], Ys, Zs).
    
    ?- eqprefix([a,a,a,b,c],Ys,Zs).
    Ys = [a, a, a],
    Zs = [b, c] ;
    false.
    
    ?- eqprefix(Xs,[a,a,a],[b,c]).
    Xs = [a, a, a, b, c] ;
    false.
    
    ?- eqprefix([A,B,C,D,E],[a|Ys],[b,c]).
    A = B, B = C, C = a,
    D = b,
    E = c,
    Ys = [a, a] ;
    false.
    

    In the definition you gave, you get many different answers:

    ?- grab([a,a,a,b,c],Ys,Zs).
      Ys = [a, a], Zs = [a, b, c]
    ; Ys = [a],    Zs = [a, a, b, c]
    ; Ys = [a],    Zs = [a, a, b, c]
    ; Ys = [],     Zs = [a, a, a, b, c].
    
    0 讨论(0)
  • 2020-12-12 07:31

    Here is a solution using dcgs. Most interesting is here the usage of a non-terminal that is not context-free. I will start with an attempt that is too general:

    grab_tentative(Xs, Ys, Zs) :-
       phrase((seq(Ys),seq(Zs)), Xs).
    
    seq([]) --> [].
    seq([E|Es]) --> [E], seq(Es).
    

    grab_tentative/3 ensures that Xs consists of Ys concatenated with Zs. That is way too general, but all intended solutions are already included.

    ?- Xs = [A,B,C], grab_tentative(Xs,Ys,Zs).
       Xs = Zs, Zs = [A, B, C], Ys = []
    ;  Xs = [A, B, C], Ys = [A], Zs = [B, C]
    ;  Xs = [A, B, C], Ys = [A, B], Zs = [C]
    ;  Xs = Ys, Ys = [A, B, C], Zs = []
    ;  false.
    

    The first answer says that Ys = [], but (as has been clarified by @Sarah), Ys should always be a non-empty list, so we can restrict the answers to non-empty lists:

    grab_tentative(Xs, Ys, Zs) :-
       Ys = [_|_],
       phrase((seq(Ys),seq(Zs)), Xs).
    

    The answers Xs = [A, B, C], Ys = [A, B], Zs = [C] and Xs = Ys, Ys = [A, B, C], Zs = [] both permit that A and B are different. So we have to add that they are the same:

    grab_tentative(Xs, Ys, Zs) :-
       Ys = [A|_],
       phrase((all_seq(=(A),Ys),seq(Zs)), Xs).
    
    all_seq(_, []) --> [].
    all_seq(C_1, [C|Cs]) -->
       [C],
       {call(C_1,C)},
       all_seq(C_1, Cs).
    

    Now, the answers are already a bit better:

    ?- Xs = [A,B,C], grab_tentative(Xs,Ys,Zs).
       Xs = [A, B, C], Ys = [A], Zs = [B, C]
    ;  Xs = [B, B, C], A = B, Ys = [B, B], Zs = [C]
    ;  Xs = Ys, Ys = [C, C, C], A = B, B = C, Zs = []
    ;  false.
    

    The first answer includes that A = B. So, it really should contain dif(A,B). To do so we need to introduce such a context. Here is way to do this. Note that or_end//1 is like []//0, except that it ensures some extra condition.

    grab_final(Xs, Ys, Zs) :-
       Ys = [A|_],
       phrase((all_seq(=(A),Ys), or_end(dif(A)), seq(Zs)), Xs).
    
    or_end(C_1) -->
      call(cond_or_end(C_1)). % interface to predicates
    
    cond_or_end(_C_1, [], []).
    cond_or_end(C_1, [E|Es], [E|Es]) :-
    

    Now, the answers are as expected:

    ?- Xs = [A,B,C], grab_final(Xs, Ys, Zs).
       Xs = [A, B, C], Ys = [A], Zs = [B, C], dif(A, B)
    ;  Xs = [B, B, C], A = B, Ys = [B, B], Zs = [C], dif(B, C)
    ;  Xs = Ys, Ys = [C, C, C], A = B, B = C, Zs = []
    ;  false.
    
    0 讨论(0)
  • 2020-12-12 07:41

    Here is another solution that takes into account what @Sarah wrote. Given this use, grab/3 should never succeed for an empty list for the first or second argument.

    grab([A], [A], []).
    grab([A,B|Bs], [A], [B|Bs]) :-
       dif(A,B).
    grab([A,A|Xs], [A|As], Bs) :-
       grab([A|Xs], As, Bs).
    
    ?- Xs = [A,B], grab(Xs,Ys,Zs).
      Xs = [A, B], Ys = [A],    Zs = [B], dif(A, B)
    ; Xs = Ys,     Ys = [B, B], Zs = [],  A = B
    ; false.
    
    0 讨论(0)
  • 2020-12-12 07:43

    When the first two elements are different you do not need a recursive goal.

    grab([], [], []).
    grab([A,A|Rest], [A|As], L2):- !, grab([A|Rest], As, L2).
    grab([A|Tail], [A], Tail).
    
    0 讨论(0)
提交回复
热议问题