I want to express a transitive relationship. If A references B and B references C then A references C. I have this:
proj(A).
proj(B).
proj(C).
ref(A,B).
ref(B,C).
When I query using proj(A)
I obtain:
[46] ?-proj(A).
A = _639
What does "_639" mean? I expected a yes or no and got that strangeness. I need to add a rule to say:
ref(A,C).
and get YES. Ideally, if possible, I would like to show how this relationship came about: (A => B => C).
The _639
is an uninstantiated, anonymous variable. Your "facts" have variables rather than atoms. For example:
proj(A). % This has a variable A and means "any A is a project"
So if I query:
:- proj(X).
X = _blah % anonymous variable: anything is a project!
You need atoms:
proj(a).
proj(b).
Which results in the query:
:- proj(X).
X = a ;
X = b
If you have:
ref(a,b).
ref(b,c).
Then, the simplest way in Prolog to express a transitive property is by declaring a rule (or what's known as a predicate in Prolog):
ref(A,C) :- ref(A,B), ref(B,C).
This says that, ref(A,C)
is true if ref(A,B)
is true, AND ref(B,C)
is true.. Running the query:
:- ref(a,c).
true ;
Out of stack
Or:
:- ref(a,X).
X = b ;
X = c ;
Out of stack
So it sounds logical but has an issue: you can get into a loop due to the self-reference. A simple way around that is to make the rule name different than the fact:
refx(A, B) :- ref(A, B).
refx(A, C) :- ref(A, B), refx(B, C).
Now if I query:
:- refx(a, b).
true ;
no
:- refx(a, c).
yes
:- refx(a, X).
X = b ;
X = c
yes
Etc.
There are still cases where this could have termination issues, however, if the facts contain reflexive or commutative relationships. For example:
ref(a,b).
ref(b,a).
ref(b,c).
In this case, a query to refx(a, b)
yields:
| ?- refx(a, b).
true ? ;
true ? ;
true ? ;
...
As @lambda.xy.x points out, this could be resolved by tracking where we've been and avoiding repeat "visits":
refx(X, Y) :-
refx(X, Y, []).
refx(X, Y, A) :-
ref(X, Y),
\+ memberchk((X, Y), A). % Make sure we haven't visited this case
refx(X, Y, A) :-
ref(X, Z),
\+ memberchk((X, Z), A), % Make sure we haven't visited this case
refx(Z, Y, [(X,Z)|A]).
Now we terminate with refx(a,b)
and succeed once:
| ?- refx(a,b).
true ? ;
no
| ?-
And refx(X, Y)
produces all of the solutions (albeit, some repeats due to succeeding more than once):
| ?- refx(X, Y).
X = a
Y = b ? ;
X = b
Y = a ? ;
X = b
Y = c ? ;
X = a
Y = a ? ;
X = a
Y = c ? ;
X = b
Y = b ? ;
X = b
Y = c ? ;
(2 ms) no