Question

I am trying to get a predicate to relate from 1 fact to another fact and to keep going until a specified stopping point.

For example, let's say I am doing a logistics record where I want to know who got a package from who, and where did they get it from until the end.

Prolog Code

    mailRoom(m).

    gotFrom(annie,brock).
    gotFrom(brock,cara).
    gotFrom(cara,daniel).
    gotFrom(daniel,m).


    gotFrom(X,Y) :- gotFrom(Y,_).

So what I am trying to do with the predicate gotFrom is for it to recursively go down the list from what ever point you start (ex: gotFrom(brock,Who)) and get to the end which is specified by m, which is the mail room.

Unfortunately when I run this predicate, it reads out,

    Who = annie.
    Who = brock.
    Who = cara.
    etc.etc....

I tried stepping through the whole thing but Im not sure where it goes from brock to annie, to cara and all the way down till it cycles through trues for infinity. I have a feeling that it has something to do with the wildcard in the function (_), but Im not sure how else I could express that part of the function in order for the predicate to search for the next fact in the program instead of skipping to the end.

I tried using a backcut (!) in my program but it gives me the same error.

Any help is greatly appreciated. I don't want code I just want to know what I am doing wrong so I can learn how to do it right.

Thanks.

Was it helpful?

Solution

I'm afraid this rule is meaningless:

gotFrom(X,Y) :- gotFrom(Y,_).

There is nothing here to constrain X or Y to any particular values. Also, the presence of singleton variable X and the anonymous variable _ means that basically anything will work. Try it:

?- gotFrom([1,2,3], dogbert).
true ;
true ;

What I think you're trying to establish here is some kind of transitive property. In that case, what you want is probably more like this:

gotFrom(X,Z) :- gotFrom(X, Y), gotFrom(Y, Z).

This produces an interesting result:

?- gotFrom(brock, Who).
Who = cara ;
Who = daniel ;
Who = m ;
ERROR: Out of local stack

The reason for the problem may not be immediately obvious. It's that there is unchecked recursion happening twice in that rule. We recursively unify gotFrom/2 and then we recursively unify it again. It would be better to break this into two predicates so that one of them can be used non-recursively.

got_directly_from(annie,brock).
got_directly_from(brock,cara).
got_directly_from(cara,daniel).
got_directly_from(daniel,m).

gotFrom(X,Y) :- got_directly_from(X, Y).
gotFrom(X,Z) :- got_directly_from(X, Y), gotFrom(Y, Z).

This gives us the desired behavior:

?- gotFrom(brock, Who).
Who = cara ;
Who = daniel ;
Who = m ;
false.

Notice this one is resilient to my attack of meaningless data:

?- gotFrom([1,2,3], dogbert).
false.

Some general advice:

  1. Never ignore singleton variable warnings. They are almost always a bug.
  2. Never introduce a cut when you don't understand what's going on. The cut should be used only where you understand the behavior first and you understand how the cut will affect it. Ideally, you should try to restrict yourself to green cuts—cuts that only affect performance and have no observable effects. If you don't understand what Prolog is up to, adding a red cut is just going to make your problems more complex.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top