I started learning Prolog a few hours ago, and I'm quite stuck trying to implement a solver for the Farmer problem. I know that there are many examples in the net, but for the purposes of learning I'd like to understand why my code doesn't work, whether or not the approach is valid, and what's the correct way to reason a problem like this.
See below the code. What I've done is:
And what I've achieved so far is:
I think I have found the problem, please correct me if I'm wrong: if the solution requires more than 3 steps, the last trip rule evaluates at least twice, and after the first recursive execution the PreviousStates accumulator is not empty. When unifying? the explored answer, the not(member(Next,PreviousStates)) then fails because the Next state contains variables that will match what's already in the head of the PreviousStates list.
So, my questions are:
Thanks in advance for your help!
%Define what are the unsafe states for the Farmer, Goat, Cabbage and Wolf
unsafeState(F,G,C,W) :-
(C=G, not(C=F));
(G=W, not(G=F)).
safeState(F,G,C,W) :- not(unsafeState(F,G,C,W)).
%Define what are the valid and safe transitions
isSafeTransition(state(F,F,C,W),state(Fend,Fend,C,W)) :- safeState(F,F,C,W), safeState(Fend,Fend,C,W).
isSafeTransition(state(F,G,F,W),state(Fend,G,Fend,W)) :- safeState(F,G,F,W), safeState(Fend,G,Fend,W).
isSafeTransition(state(F,G,C,F),state(Fend,G,C,Fend)) :- safeState(F,G,C,F), safeState(Fend,G,C,Fend).
isSafeTransition(state(F,G,C,W),state(Fend,G,C,W)) :- safeState(F,G,C,W), safeState(Fend,G,C,W).
% Initial matching rule
trip(A,B,Path):- trip(A,B,Path, []).
% Finishing rule
trip(CurrentState, EndState,Path, _):-
[CurrentState| [EndState|[]] ] = Path,
isSafeTransition(CurrentState, EndState).
trip(CurrentState,EndState,Path, PreviousStates):-
[CurrentState|[Next|Tail]] = Path,
not(member(Next,PreviousStates)),
isSafeTransition(CurrentState,Next),
trip(Next,EndState, [Next|Tail], [CurrentState|PreviousStates]).
I've found the problem myself, I'm posting the explanation in case is helpful for someone.
The issue is that there isn't any rule that limits the possible values for the positions. Basically I've forgotten to limit the possible values to be n or s...
When solving the query, the potential values for the variables are infinite. That's why a state containing variables is stored in the accumulator and matches the next state.
To solve the problem, I've added two facts that define the valid values for the positions, and modified the rule that controls whether a state is valid or not to include these values.
Find below the fixed program:
% Define the valid sides for any participant
side(n).
side(s).
% Define what are the valid states for the Farmer, Goat, Cabbage and Wolf
unsafeState(F,G,C,W) :-
(C=G, not(C=F));
(G=W, not(G=F)).
validState(F,G,C,W) :-
side(F),side(G),side(C),side(W),
not(unsafeState(F,G,C,W)).
%Define what are the valid and safe transitions
isSafeTransition(state(F,F,C,W),state(Fend,Fend,C,W)) :-
validState(F,F,C,W), validState(Fend,Fend,C,W).
isSafeTransition(state(F,G,F,W),state(Fend,G,Fend,W)) :-
validState(F,G,F,W), validState(Fend,G,Fend,W).
isSafeTransition(state(F,G,C,F),state(Fend,G,C,Fend)) :-
validState(F,G,C,F), validState(Fend,G,C,Fend).
isSafeTransition(state(F,G,C,W),state(Fend,G,C,W)) :-
validState(F,G,C,W), validState(Fend,G,C,W).
% Initial matching rule
trip(A,B,Path):- trip(A,B,Path, []).
% Finishing rule
trip(CurrentState, EndState,Path, _):-
[CurrentState| [EndState|[]] ] = Path,
isSafeTransition(CurrentState, EndState).
trip(CurrentState,EndState,Path, PreviousStates):-
[CurrentState|[Next|Tail]] = Path,
not(member(CurrentState,PreviousStates)),
isSafeTransition(CurrentState,Next),
trip(Next,EndState, [Next|Tail], [CurrentState|PreviousStates]).
I'm still a total newbie in Prolog, so if anyone can contribute with any correction, please do it!