0

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?

4
  • change_state(State, [H|T], NewState) :- ... shouldn't that be change_state(State, [H|T], X) :- ... considering your almost-tail-recursive call change_state(NewState, T, X)? Commented Dec 16, 2021 at 12:23
  • @RuudHelderman just tried it but now my return list is empty. Commented Dec 16, 2021 at 12:28
  • 1
    Clause change_state(X, [], []). must be replaced with change_state(X, [], X). Commented Dec 16, 2021 at 12:38
  • Combining both of your answers worked! Thank you very much!! Commented Dec 16, 2021 at 12:43

1 Answer 1

1

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).
Sign up to request clarification or add additional context in comments.

2 Comments

Or in the presence of foldl, change_state(State, Changes, NewState) :- foldl(do, Changes, State, NewState).
@RuudHelderman Nice! I really like the solution based on foldl/4. However, I think using foldl/4 makes the code more concise, not necessarily clearer (for beginners, of course).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.