I often find myself using the (P -> Q; true) formulation, when I need to do an extra check or take an extra action but only when a certain precondition is true; when it isn’t, the clause can proceed as it would otherwise. Why isn’t there a built-in operator or predicate that does this? Perhaps something that binds tighter than ,/2, like say:
:- op(800, xfy, ?).
% Whenever P succeeds, then Q must succeed, but \+P is fine
P ? Q :- P *-> Q; true.
% Match *or* generate "(At)" in text, when At is an atom
parenthesized_atom(At) -->
`(`,
{ground(At) ? atom_codes(At,AC)},
string(AC),
`)`,
{atom_codes(At,AC)}.
Note that this isn’t a “how can I do this, please” - I have a number of ways I can implement this, and it’s not all that cumbersome (and more to the point, I want to make sure that I am writing idiomatic Prolog). It’s more of a “why was Prolog designed this way?” combined with some amount of “are there hidden pitfalls to doing this kind of thing that I’m not aware of?”
I don’t know the reason (I have a couple of theories), but I do know that Logtalk’s linter complains about (P->Q) but doesn’t complain about (P->Q;fail).
Paulo Moura (author of Logtalk) doesn’t seem to be in this discussion group, but maybe somebody knows the reason?
I think the reason is that from a logical point of view, P -> Q is seen as (in logic) P implies Q.
Now, when P implies Q (in logic), you are not saying anything at all about what happens if not P (you could still have Q even if not P), and therefore I think it would be sensible from this point of view to always specify what happens if not P when you are implementing a programming language.
(bad_input(X)->throw(error(bad_input(X), _));true) … this is similar to must_be/2 or domain_error/2.
Although there’s been a long discussion about failure vs throwing an exception.
Another useful case: In a DCG: ({some_test(X)}->[X];[]).
Ooh fun, I’ll play! Let’s see. I’ll mark the trues that get executed with %%%%
?- ((true->true),true;true).
% %%%% %%%% %%%%^ Choice point here, this isn't a ->; construct
?- ((true->true);true).
% %%%% %%%% No choice points, the -> cuts the ; choice
?- ((true->true);true;(true->true)).
% %%%% %%%% ^ Choice point here, the second ; doesn't get cut
?- (((true->true);true);(true->true)).
% %%%% %%%% ^ Choice point here, syntactically equivalent to the above
I think these are correct. Not so sure about #3, but I’m pretty sure the precedence rules group on the left ;/2, so only that one gets cut by the ->/2.