How do parenthesis work?

2019-08-03 18:30发布

问题:

I wrote an algorithm and tried to implement it in Prolog, but what I found out is that the parenthesis do not work as expected: what is written in is not all done before exiting the parenthesis. Here is the code:

%1. If the first member of L1 is smaller than L2
%     A. If the first member of L1 is not equal to Last
%            Than: A.1 Add the first member of L1 to the first member of NL
%                  Begin recurssion on the resumption of L1, L2 resumption of NL
%                  and Last from L1.
%            Else: A.2  begin the recursion on resumption of L1, L2 with the
%                       first member and L3 with the first member.
%  2. If the first member in L1 is equal to the first member of L2,
%             Than: Start recursion on resumption of L1 and L2 (with its first
%                   member) and Last = *.
%  3. If the first member of L1 is bigger than the first membber of L2
%             Than: begin recursion on L1 with the first member, resumption of
%             L2 and Last = x. %(x != * only for debugging)
%  

                              */
make_list([X1|L1], [X2|L2], [X3|NewL], Last) :-
    (
        X1 < X2,
        (
            X1 \= Last,   %A
            X3=X1;
            make_list(L1, [X2|L2], NewL, X1) %B
        ),  %Why those parenthesis do not work as expected?

        ! %green cut
    );
    (
        X1=X2,
        make_list(L1, [X2|L2], [X3|NewL], *)
    ),
    !
    ;
    make_list([X1|L1], L2, [X3|NewL], *).

My question is how to make it work as expected and why does B not work once A is done? After all it is also in the same parenthesis, e.g.:

?- make_list([6,6,10,20],[10,25,30],L, -).
L = [6|_G849]  % (should be [6,20]).

EDIT1: make_list should find all members in L1 that are not in L2 and put them in NewL, while Last stores the last member in L1 that was parsed.

EDIT2: no -> are allowed (this is howmework). If someone could show me how to express if then else in prolog, that could be great.

回答1:

In short: !/0 applies at the predicate level: here you'd want it to apply to some block level where blocks would be delimited by ( and ). This notion of cut applied to blocks does not exist in Prolog. A cut will erase all encountered choice points up until its location in a predicate.

And instead of writing your code with a lot of (;)/2 usage, consider introducing new clauses instead, for readability (precisely because we do not like parenthesis and figuring out (;)/2 and (,)/2 priorities):

c :- A; B.

can be written

c :- A.
c :- B.

It will quite often be better this way. Better to produce the code easily, better to maintain it, to read it and to expand it.

I didn't look at your predicate in depth or anything, just wanted to mention those two things.



回答2:

I suspect that "green cut" of yours is not green at all; you have

( A ; B ), !

so on exit from (A ; B) the first time, if A succeeded, B won't be tried anymore - that is what the cut ! is saying here: don't try any more.

If you want B to be tried too, remove the cut !.

If-then-else is:

ifte(A,B,C):- A, B.
ifte(A,B,C):- \+A, C.

We can spare us a not by using a cut,

ifte(A,B,C):- A, !, B.
ifte(A,B,C):- C.

About your code: we express and then with comma: A,B. To output the Last it's easiest to use a working predicate, with additional argument, "seen-last"; and in the base case finally the last seen and the output would be unified.



标签: prolog