Implementing often-occuring determinism patterns in Prolog
You should experiment with double negation as failure. Yes a ground goal can only be true or false, so it should not leave any choice points. Lets assume we have an acyclic graph, to make matters simple:
If I use this code:
edge(a, b). edge(a, c).
edge(a, d). edge(b, c).
edge(c, d). edge(c, e).
edge(d, e).
path(X,X).
path(X,Y) :- edge(X,Z), path(Z,Y).
The Prolog system will now leave choice points for closed queries:
?- path(a, e).
true ;
true ;
true ;
true ;
true ;
false.
In my opinion the recommended approach, to eliminate these choice points and nevertheless have a multi-moded predicate, is to use so called meta-programming in Prolog.
meta-programming is also sometimes derogeratively called non-logical programming, since it is based on non-logical predicates such as ground/1, !/0 or (+)/1. But lets call it meta-programming when declarativity is not impacted.
You could write a wrapper smart/1 as follows, doing the same as your call_ground_as_semidet/1, but with a small nuance:
smart(G) :- ground(G), !, \+ \+ G.
smart(G) :- G.
The Prolog system will not anymore leave a choice point for closed queries:
?- smart(path(a,e)).
true.
The advantage of \+ \+ over once, is that the former does not only leave no choice points, but also removes the trail. It is sometimes called the garbage collection meta-predicate of Prolog.