I'd really like to get rid of the wrapper and just use sort within split
Then use findall
with a complex goal such as
split(Edges, NodeSet) :-
findall(Node,
(member(Edge, Edges), (Edge = (Node:_); Edge = (_:Node))),
NodeList),
sort(NodeList, NodeSet).
However, once you start using aggregating predicates, you could just as well skip the sort
and use setof
:
split(Edges, NodeSet) :-
setof(Node, Edge^Pair^(member(Edge, Edges),
Edge =.. [:|Pair],
member(Node,Pair)),
NodeSet).
Read as: get the set of all Node
s.t. there exists Edge
and there exists Pair
s.t. (etc.) and call that NodeSet
.
The =..
("univ") operator deconstructs a pair: Edge =.. [:, Left, Right]
. For better readability, you can write a separate predicate to get nodes from edges:
% 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).
EDIT Before you try this approach, see the discussion below this answer for whether or not this is a better idea than the OP's original code.