Let's try to understand the clauses you wrote. The first clause allnodes([]).
basically reads "there are no nodes". This is obviously not true unless there are no edges defined at all.
The second clause can be interpreted along the lines of "all nodes consist of X and Y if there is an edge from X to Y, plus all nodes". See the recursion here? The list contains itself as tail! That's why you get the same nodes over and over again.
What you actually want is the set of all nodes which occur as either start or end node for an edge.
To make it easier for ourselves, let's first translate to prolog what it means for something to be a node:
node(N) :- edge(N, _).
node(N) :- edge(_, N).
Simple as that. Something is a node if some edge starts there, or some edge ends there.
Now all we have to do is find everything that satisfies above predicate.
allnodes(Nodes) :- setof(N, node(N), Nodes).
Note that I use setof/3
rather than findall/3
to remove duplicates, as above definition of node/2
will succeed once for each occurrence of a node in an edge, e.g. it will succeed twice for n1 and n2.
This gives the result you're looking for:
?- allnodes(N).
N = [n1, n2, n3, n4]