我真的很想摆脱包装器,只在 split 中使用 sort
然后使用findall
复杂的目标,例如
split(Edges, NodeSet) :-
findall(Node,
(member(Edge, Edges), (Edge = (Node:_); Edge = (_:Node))),
NodeList),
sort(NodeList, NodeSet).
然而,一旦你开始使用聚合谓词,你也可以跳过sort
and 使用setof
:
split(Edges, NodeSet) :-
setof(Node, Edge^Pair^(member(Edge, Edges),
Edge =.. [:|Pair],
member(Node,Pair)),
NodeSet).
读作:获取所有Node
st 存在Edge
和存在Pair
st (等)的集合并调用它NodeSet
。
( =..
"univ") 运算符解构一对:Edge =.. [:, Left, Right]
。为了更好的可读性,您可以编写一个单独的谓词来从边缘获取节点:
% endpoint(Edge, Node) is true iff Node is an endpoint of Edge
endpoint(Node:_, Node).
endpoint(_:Node, Node).
split(Edges, NodeSet) :-
setof(Node, Edge^(member(Edge, Edges), endpoint(Edge, Node)), NodeSet).
编辑在您尝试这种方法之前,请参阅此答案下方的讨论,了解这是否比 OP 的原始代码更好。