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