Search code examples
prolog

Prolog - Recursion returns to initial state after finding desired solution


I'm new to Prolog and I can't figure out what's wrong with my predicates. I'm trying to write a predicate that iterates over a list of vertices, like [a,b,d,f,k], and return the activities described in edge(X, vertex1, vertex2). The desired result for list [a,b,d,f,k] would be [jump, jump, fly, wow].

Because edges are bound between two vertices, I made a predicate call_act/2 that takes the first two items of a list. call_act/2 gives act/3 the full list, the second item and then awaits the result. act/3 looks for an edge between the first item in the list and the second item and then appends it to the result.

edge(jump,a,b).
edge(run,a,c).
edge(jump,b,d).
edge(fly,d,f).
edge(jump,b,e).
edge(fly,c,f).
edge(run,c,g).
edge(go,d,h).
edge(sprint,e,i).
edge(flip,e,j).
edge(wow,f,k).

call_act([_|[]], _).
call_act([H,H2|T], Result) :-
    act([H,H2|T], H2, Result).

act(_,[],[_|_]).
act([H|T], Next, Result) :-
    findall(X, edge(X,H,Next), Result1),
    append(Result, Result1, ResultN),
    write(ResultN),
    nl,
    call_act(T, ResultN).

If you run the code like this, it will find the correct solution, but afterwards it goes back to an empty list. Like this.

I have tried a couple things. I tried to stop the recursion when ResultN has a length of the full list -1, but this did not seem to work. I've tried making a modified version of act/3 that includes the final vertex as a parameter, in hopes that I could make a base case like act([FinalVertex|_],_,_,FinalVertex).. But I've not figured out a solution yet.

I've also written a version of this code that merges the two predicates into one:

act([_|[]],_).
act([H,H2|T], Result) :-
    findall(X, edge(X,H,H2), Result1),
    append(Result, Result1, ResultN),
    write(ResultN),
    nl,
    act([H2|T], ResultN).

But this has the same issue.


Solution

  • Try doing the following:

    act([], []).
    act([_], []).
    act([V1,V2|Vs], [A|As]) :-
        edge(A, V1, V2),
        act([V2|Vs], As).
    

    Example:

    ?- act([a,b,d,f,k], L).
    L = [jump, jump, fly, wow] ;
    false.