As a pair of predicates, one for nodes, one for edges:
:- pred asg_nodes(asg, node).
:- mode asg_nodes(in, out) is nondet.
:- mode asg_nodes(in, in) is semidet.
:- pred asg_edges(asg, node, node).
:- mode asg_edges(in, out, out) is nondet.
:- mode asg_edges(in, in, in) is semidet.
Underlying are traditional sets or what-have-you but you never have to deal with these at high levels of coding. You could then do fancy stuff like defining ancestry as:
:- pred asg_ancestor(asg, node, node).
:- mode asg_ancestor(in, out, out) is nondet.
:- mode asg_ancestor(in, in, in) is semidet.
asg_ancestor(ASG, A, A).
asg_ancestor(ASG, A, B) :- asg_edge(A, C), asg_ancestor(C, B).
Of course you'd want to wrap this stuff up in a typeclass or some such and give them useful names.
:- pred asg_nodes(asg, node).
:- mode asg_nodes(in, out) is nondet.
:- mode asg_nodes(in, in) is semidet.
:- pred asg_edges(asg, node, node).
:- mode asg_edges(in, out, out) is nondet.
:- mode asg_edges(in, in, in) is semidet.
Underlying are traditional sets or what-have-you but you never have to deal with these at high levels of coding. You could then do fancy stuff like defining ancestry as:
:- pred asg_ancestor(asg, node, node).
:- mode asg_ancestor(in, out, out) is nondet.
:- mode asg_ancestor(in, in, in) is semidet.
asg_ancestor(ASG, A, A).
asg_ancestor(ASG, A, B) :- asg_edge(A, C), asg_ancestor(C, B).
Of course you'd want to wrap this stuff up in a typeclass or some such and give them useful names.