A break through in if-then-else could be a new annotation.
By annotation I understand things like mode declarations,
determinancy declarations, etc.. For an if then else, a
complete declaration would be nice. Lets assume we could
declare a predicate or built-in p/n complete. This would
mean it has the property for ground arguments t1,..,tn:
T |- p(t1,..,tn)
- or -
T |- ~p(t1,..,tn)
Or in short it would be a decidable predicate if the theory T is recursively enumerable. If we then recall that if-then-else is logically:
ITE(A,B,C) == (A => B) & (~A => C)
We could then use the complete annotation as follows. Lets
assume A = p(t1,..,tn). Because of the annotation the Prolog
system would try to prove A. If it doesn't succeed, because
of the complete annotation, the Prolog system can infer that
~A would succeed. And therefore it can use the else branch
without a proof attempt of ~A.
But interestingly this is already what the ISO core
standard if-then-else does, (A->B;C) does also only prove
A once. So whats the problem? I guess the problem is
that A might be more complex and not necessarily ground.
Or even that a predicate p/n might be incomplete, or
we even don't know whether it is complete. And in all
these cases the ISO core standard nevertheless allows
us to use the (A->B;C).
The groundness problem can sometimes be solved by using a runtime
groundness checks. This is probably what Mercury refers to:
when(ground(A), (A->B;C))
SWI-Prolog even applies a trick to make the groundness
check cheaper, see also some further discussion on Discourse:
%! trigger_ground(@Term, :Goal)
%
% Trigger Goal when Term becomes ground. The current implementation
% uses nonground/2, waiting for an atribtrary variable and re-check
% Term when this variable is bound. Previous version used
% term_variables and suspended on a term constructed from these
% variables. It is clear that either approach performs better on
% certain types of terms. The term_variables/2 based approach wins on
% large terms that are almost ground. Possibly we need a nonground
% that also returns the number of tests performed and switch to the
% term_variables/2 based approach if this becomes large.
trigger_ground(X, Goal) :-
( nonground(X, V)
-> '$suspend'(V, when, trigger_ground(X, Goal))
; call(Goal)
).