prolog two lists are exactly the same

2020-07-28 11:06发布

问题:

I want to write a function that returns true if two lists are exactly the same(order of elements matters).

I tried it this way:

same([ ], [ ]).   
same([H1|R1], [H2|R2]):-
    H1 == H2,
    same(R1, R2).

It returns true while two lists are the same, also I expect if I have

?- same(X, [1, 2, 3]).

I want it to return

X = [1, 2, 3].

But it doesn't work if input is like this. Here are some sample outputs I got:

?- same([1, 2], [1, 2]).

true.

?- same([2, 1], [1, 2]).

false.

?- same(X, [1, 2, 3]).

false.

?- same([1, 2, 3], [1, 2, X]).

false.

How to fix it?

回答1:

The problem is that you're using ==/2 (checking whether two items are instantiated the same) rather than =/2 (checks if two items are unified or unifiable). Just change to unification:

same([], []).

same([H1|R1], [H2|R2]):-
    H1 = H2,
    same(R1, R2).

Then this will have the behavior you're looking for:

| ?- same(X, [1, 2, 3]).

X = [1,2,3] ? a

no
| ?- same([1, 2], [1, 2]).

(1 ms) yes
| ?- same([2, 1], [1, 2]).

no
| ?- same([1, 2, 3], [1, 2, X]).

X = 3

(1 ms) yes
| ?- same([A,B,C], L).

L = [A,B,C]

yes
% In this last example, A, B, and C are variables. So it says L is [A,B,C],
% whatever A, B, and C are.

If you query X == 3 in Prolog, and X is not bound to the value 3, or it is just unbound, it will fail. If X is unbound and you query, X = 3, then Prolog will unify X (bind it) with 3 and it will succeed.

For more regarding the difference between =/2 and ==/2, see What is the difference between == and = in Prolog?

You can also use maplist for a nice, compact solution. maplist is very handy for iterating through a list:

same(L1, L2) :- maplist(=, L1, L2).

Here, unification (=/2) is still used for exactly the same reason as above.


Finally, as @Boris points out, in Prolog, the unification predicate will work on entire lists. In this case, this would suffice:

same(L1, L2) :- L1 = L2.

Or equivalently:

same(L, L).  % Would unify L1 and L2 queried as same(L1, L2)

This will succeed if the lists are the same, or will attempt to unify them by unifying each element in turn.

| ?- same([1,2,X], [1,2,3]).    % Or just [1,2,X] = [1,2,3]

X = 3

yes
| ?- same([1,2,X], [1,2,3,4]).  % Or just [1,2,X] = [1,2,3,4]

no

The prior more elaborate approaches are considered an exercise in list processing for illustration. But the simplest and most correct method for comparison and/or unification of lists would be L1 = L2.



标签: list prolog