I want to write change_state( L1, L2, -L3).
L1 contains states e.g: [milled, burned] L2 contains predicates e.g: [del(milled), add(shifted)] And L3 is the return list.
Example:
L1 = [milled, burned]
L2 = [del(burned), add(shifted)]
L3 = [milled, shifted]
So L1 is my start list and depending on the predicates in L2 I change the state of L1.
This is my solution with recursion:
change_state([], [], []).
change_state(X, [], []).
change_state(State, [H|T], NewState) :-
functor(H, N, 1),
arg(1, H, A),
( N = del
-> remove_from_list(A, State, NewState)
; arg(1, H, A),
add_to_list(A, State, NewState) ),
print(NewState),
change_state(NewState, T, X),
print(NewState).
I also put some prints into the function for debugging.
Now the problem:
If I call the function with
change_state([milled, burned], [del(burned), add(lol), add(hi)], L).
I get as an result
L = [milled].
So only the first predicate in L2 worked.
But the prints show me:
[milled][lol,milled][hi,lol,milled][hi,lol,milled][lol,milled][milled].
So it actually worked, but because of the recursion it goes back to the first state.
Any idea how to fix this?
CodePudding user response:
Although your code is already working correctly with the modifications that were indicated in the comments, I think a clearer implementation would be as follows:
change_state(State, Changes, NewState) :-
change_state_loop(Changes, State, NewState).
% Reverse the order of the first two arguments to avoid choice points.
change_state_loop([], State, State).
change_state_loop([Change|Changes], State, NewState) :-
do(Change, State, PartiallyUpdatedState),
change_state_loop(Changes, PartiallyUpdatedState, NewState).
% Use unification to choose the correct operation to perform.
do(del(Fluent), State, NewState) :- subtract(State, [Fluent], NewState).
do(add(Fluent), State, NewState) :- union(State, [Fluent], NewState).