给出prolog中的一组断言,这些断言被设计为表示节点之间的有向连接的边缘:
edge(n1, n2).
edge(n2, n3).
edge(n1, n4).
以下查询给出了[n1, n2, n1, n2 ... ]
...
allnodes([]).
allnodes([X | [ Y | Xs]]) :-
edge(X, Y),
allnodes(Xs).
当被问及allnodes(Result)
我正在寻找的是列表[n1, n2, n3, n4]
的某种顺序。
答案 0 :(得分:3)
让我们试着理解你写的条款。第一个子句allnodes([]).
基本上是“没有节点”。除非根本没有定义边缘,否则显然不是这样。
第二个子句可以解释为“如果存在从X到Y的边缘加上所有节点,则所有节点由X和Y组成”。看到这里的递归?该列表包含尾巴!这就是为什么你一遍又一遍地获得相同的节点。
您实际需要的是作为边缘的起始节点或结束节点出现的所有节点的集合。
为了让自己更容易,让我们首先翻译成prolog对于某个节点的意义:
node(N) :- edge(N, _).
node(N) :- edge(_, N).
这很简单。如果某些边缘从那里开始,或某些边缘在那里结束,则某事物是一个节点。
现在我们所要做的就是找到满足上述谓词的所有内容。
allnodes(Nodes) :- setof(N, node(N), Nodes).
请注意,我使用setof/3
而不是findall/3
来删除重复项,因为node/2
的上述定义将在边缘中每次出现节点时成功执行一次,例如对于n1和n2,它将成功两次。
这给出了您正在寻找的结果:
?- allnodes(N).
N = [n1, n2, n3, n4]
答案 1 :(得分:0)
考虑使用现有的库,例如library(ugraphs)。它有很好的文档记录,但为了让您开始,以下是如何从边列表中创建图形,然后显示所有顶点:
?- bagof(A-B, edge(A, B), Edges),
vertices_edges_to_ugraph([], Edges, G),
vertices(G, Vertices).
Edges = [n1-n2, n1-n4, n2-n3],
G = [n1-[n2, n4], n2-[n3], n3-[], n4-[]],
Vertices = [n1, n2, n3, n4].
这也使用bagof/3
来构建From-To
对的列表。另外两个谓词来自图书馆。这个例子是SWI-Prolog的,但是库本身应该适用于任何半体面的Prolog实现,the code is on Github。
获取顶点当然是微不足道的,但对于任何更复杂的库,总是更好。