简体   繁体   中英

prolog two lists are exactly the same

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?

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([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

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM