<p>In old-fashioned Prolog code, the following pattern arises rather frequently:</p>

<pre>
predicate([], ...).
predicate([L|Ls], ...) :-
        <b>condition(L)</b>,
        then(Ls, ...).
predicate([L|Ls], ...) :-
        <b>\+ condition(L)</b>,
        else(Ls, ...).
</pre>

<p>I am using lists here as an example where this occurs (see for example <code>include/3</code>, <code>exclude/3</code> etc.), although the pattern of course also occurs elsewhere.</p>

<p>The tragic is the following:</p>

<ul>
<li>For an <strong>instantiated</strong> list, pattern matching can distinguish the first clause from the remaining&nbsp;two, but it cannot distinguish the second one from the last&nbsp;one because they <em>both</em> have <code>'.'(_, _)</code> as the primary functor and arity of their first argument.</li>
<li>The conditions in which the last two clauses apply are obviously <strong>mutually exclusive</strong>.</li>
<li>Thus, when everything is known, we want to obtain an efficient, <strong>deterministic</strong> predicate that <em>does not leave choice points</em>, and ideally does not even <em>create</em> choice points.</li>
<li><em>However</em>, as long as not everything can be safely determined, we want to benefit from <strong>backtracking</strong> to see <strong>all solutions</strong>, so we cannot afford to commit to either of the clauses.</li>
</ul>

<p>In summary, the existing constructs and language features all fall short in some way to express a pattern that often occurs in practice. Therefore, for decades, it seemed necessary to&nbsp;<em>compromise</em>. And you can make a pretty good guess in which direction the "compromises" usually go in the Prolog community: Almost invariably, <em>correctness is sacrificed for efficiency</em> in case of doubt. After all, who cares about correct results as long as your programs are fast, right? Therefore, until the invention of <code>if_/3</code>, this was frequently <em>wrongly</em> written as:</p>

<pre>
predicate([], ...).
predicate([L|Ls], ...) :-
        (    <b>condition(L)</b> ->
             then(Ls, ...).
        ;    else(Ls, ...).
        )
</pre>

<p>The <strong>mistake</strong> in this is of course that when the elements are <em>not</em> sufficiently instantiated, then this may <em>incorrectly</em> commit to one branch even though <em>both</em> alternatives are logically possible. For this reason, using if-then-else is almost always declaratively wrong, and stands massively in the way of declarative debugging approaches due to its violation of the most elementary properties we expect from pure Prolog programs.</p>

<hr>

<p>Using <code>if_/3</code>, you can write this as:</p>

<pre>
predicate([], ...).
predicate([L|Ls], ...) :-
        if_(<b>condition(L)</b>,
            then(Ls, ...),
            else(Ls, ...)).
</pre>

<p>and <strong>retain all desirable aspects</strong>. This is:</p>

<ul>
<li><strong>deterministic</strong> if everything can be <em>safely</em> decided</li>
<li><strong>efficient</strong> in that it does not even create choice points</li>
<li><strong>complete</strong> in that you never <em>incorrectly</em> commit to one particular branch.</li>
</ul>

<p>The <strong>price</strong> of this is rather affordable: As Boris mentioned in the comments, you need to implement a <strong>reification</strong>. I have now some experience with this and found it rather easy with some practice.</p>

<p><strong>Good news everyone</strong>: In many cases, <code>condition</code> is of the form <code>(=)/2</code>, or <code>(#=)/2</code>, and the first even ships with <a href="http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/sicstus/reif.pl" rel="noreferrer"><strong><code>library(reif)</code></strong></a> <strong>for&nbsp;free</strong>.</p>

<p>For more information, see <a href="https://arxiv.org/abs/1607.01590" rel="noreferrer"><strong>Indexing dif/2</strong></a> by Ulrich Neumerkel and Stefan&nbsp;Kral!</p>
What use does if_/3 have?
<p>The predicate <strong><a href="https://stackoverflow.com/questions/27358456/prolog-union-for-a-u-b-u-c/27358600#27358600"><code>if_/3</code></a></strong> seems to be <a href="https://stackoverflow.com/search?q=%5Bprolog%5D+if_">fairly popular</a> among the few main contributors in the Prolog part of Stack Overflow.</p>

<p>This predicate is implemented as such, courtesy of @false:</p>

<pre><code>if_(If_1, Then_0, Else_0) :-
   call(If_1, T),
   (  T == true -&gt; call(Then_0)
   ;  T == false -&gt; call(Else_0)
   ;  nonvar(T) -&gt; throw(error(type_error(boolean,T),_))
   ;  /* var(T) */ throw(error(instantiation_error,_))
   ).
</code></pre>

<p>However, I have been unable to find a <strong>clear, simple, and concise</strong> explanation of what this predicate does, and what use it has compared to e.g. the classical if-then-else construct of Prolog <code>if -&gt; then ; else</code>. </p>

<p>Most links I have found directly use this predicate and provide little explanation as to why it gets used, that a non-expert in Prolog could understand easily.</p>