I am trying to create a rule that recursively calls itself, and finds all possible paths to traverse a directed graph. I am using a findall()
to do so. The functions is traverse(Start,End)
.
I have:
traverse(Start,End,[li]) :-
node(Start,End),
append(End,Li).
traverse(Start,End,[Li]) :-
node(Start,Z),
traverse(Z,End),
append(Start,Li).
/*here I would like to check that Z is not a member of Li before
I call traverse(Z,End), I know I can check that it is a member
using member(Z,Li) but how to I check it is not a member in
prolog*/
findalltraverses(Start,End,[list]) :-
findall(_,traverse(Start,End).
Before we start: this language is called prolog.
Your code has several mistakes/errors in different levels. Here is a (not complete) list of them:
findall
needs a closing bracket.findall
needs 3 parameters. At first position is what you are interested in, second is how to optain the data (which call) and third one is a container for your answers. You are interested in the container, so findalltraverses
should have it as attribute.L
is unified with a list you don't have to state it like [L]
, because for the example L=[1,2,3]
[L]
would become [[1,2,3]]
which is a list containing a list which contains 1
, 2
and 3
.append
has 3 arguments: the lists L1
, L2
and L3
, where L1
and L2
appended is L3
.traverse/3
has 3 attributes. There is no predicate traverse/2
defined for 2 attributes.N
and want to increment it, you need to use a different variable to hold the result: N1 is N+1
.E
to a list L
as head elements (meaning to put it at first position) can be done with the head-tails writing: [E|L]
. For E=1
and L=[2,3]
, [E|L]
becomes [1,2,3]
.Start
to End
you somehow need to forward the path somehow. It is not possible to use the list with visited nodes only since this knowledge is not preserved when stepping back through the recursion. So your traverse
predicate should have had 4 attributes.\+
which means as much as "cannot be proven".Ok, here is a working code snipped. The recursion end part is a bit different because it does not check if there is a edge from Start
to End
but asks if Start
and End
are the same. If so then the resulting path contains only this node. This is important because in the code snipped the path will be build when going back trough the recursion ([Start|Path]
) while the list containing visited nodes grows when going into the recursion ([Start|Visited]
).
edge(a,b).
edge(b,c).
edge(c,d).
edge(a,d).
traverse(End,End,_,[End]).
traverse(Start,End,Visited,[Start|Path]) :-
edge(Start,Tmp),
\+ member(Tmp,Visited),
traverse(Tmp,End,[Start|Visited],Path).
findalltraverses(Start,End,Out):-
findall(List,traverse(Start,End,[],List),Out).
Let's test it!
?- findalltraverses(a,d,Out).
Out = [[a, b, c, d], [a, d]].
Looks good.