I have a prolog rule position_that_is_equals_to_two
that sets X
to the position at which the number 2
was found in the provided list of three elements [X, Y, Z]
:
position_that_is_equals_to_two([X, Y, Z], X) :-
include(==(2), [X, Y, Z], AllElementsWhichHaveAValueOfTwo),
nth0(0, AllElementsWhichHaveAValueOfTwo, X).
When querying it, I immediately get false
:
?- position_that_is_equals_to_two([X, _, _], X)
false
However, when I replace include/3 with individual comparisons, prolog gives three possible values for X
, which is the output I would expect:
position_that_is_equals_to_two([X, Y, Z], X) :-
(
( X == 2 ; X #= 1)
; ( Y == 2 ; X #= 2)
; ( Z == 2 ; X #= 3)
).
Querying it:
?- position_that_is_equals_to_two([X, _, _], X)
X = 1
X = 2
X = 3
Why is the first variant returning false
? How can it me modified to (1) still use include
and (2) list possible values for X
, like the second variant does?
How can it be modified to still use include?
It can't. Include shrinks the original list and throws away information you need to answer the question. With AllElementsWhichHaveAValueOfTwo = [2]
what is the index of that two? Was it 0, 1, 2 or 50,000? You can't know.
Worse, include/3 has the signature include(:Goal, +List1, ?List2)
and the + means the List1 must be provided, you can't give it unground variables like [X,Y,Z] and have it fill them in. So it can't be used for that reason also.
Take this query:
?- position_that_is_equals_to_two([X, _, _], X)
What you expect out of it is that X in the list has value two and X as the index has value zero. You want 2 = 0
. That can't work.
Your other code is giving the right answer for the wrong reasons; the code (X == 2 ; X #= 1)
says "variable X must be two OR variable X must be one" which is allowed but for your indexing you need them both at the same time, not either/or. What you want it to say is "first list item must be two AND the index must be one".
Change the code to (X = 2, X = 1)
which is logically how it should be and you're back to asking for 2 = 1 which can't work.