Prolog 序言-迭代时跳过某些事实

Prolog 序言-迭代时跳过某些事实,prolog,graph-theory,directed-graph,Prolog,Graph Theory,Directed Graph,我有以下表示有向图的知识库: edge(1, 2). edge(2, 3). edge(2, 4). edge(3, 3). edge(3, 4). edge(3, 5). edge(4, 3). 我想打印每个节点的传入和传出边数之间的差异。以下是我到目前为止的情况: outgoing(E) :- edge(E, _). ingoing(E) :- edge(_, E). count_outgoing(E, Count) :- findall(E, outgoing(E), Bag), le

我有以下表示有向图的知识库:

edge(1, 2).
edge(2, 3).
edge(2, 4).
edge(3, 3).
edge(3, 4).
edge(3, 5).
edge(4, 3).
我想打印每个节点的传入和传出边数之间的差异。以下是我到目前为止的情况:

outgoing(E) :- edge(E, _).
ingoing(E) :- edge(_, E).

count_outgoing(E, Count) :- findall(E, outgoing(E), Bag), length(Bag, Count).
count_ingoing(E, Count) :- findall(E, ingoing(E), Bag), length(Bag, Count).

count(E, D) :- count_outgoing(E, OC), count_ingoing(E, IC), D is IC - OC.

count :- edge(E, _), count(E, D), write(E), write(' '), write(D), nl, fail; true.

但是,此解决方案会重复具有多个传出边缘的节点。我怎样才能修好它?(让我们跳过这样一个事实:如果一个节点没有任何输出边,它现在就不会被打印出来)。

问题是
count\u outing/2
count\u incoming/2
都隐式地查找您的节点。如果你明确地这样做,你就会拥有你需要的控制权。最简单的方法是获取一组节点并进行迭代。像这样:

node(N) :- edge(N, _) ; edge(_, N).
all_nodes(Nodes) :- setof(N, node(N), Nodes).
然后,主节点可以使用
member/2
生成节点:

count :- 
  all_nodes(Nodes), 
  forall(member(N, Nodes), 
    (count(N, D), 
     format('node ~a has a difference of ~a~n', [N, D]))).