How can I call a predicate if all calls to another predicate failed?
I have:
foo(A, B, C, D) :-
(bar1(Y,Z); bar2(L, K, M)),
foo(A, B, C, D).
What I want :
- at any time, If
bar1/2
has succeded,bar2/3
will never be executed. - if all
bar1/2
calls failed, thenbar2/3
will eventually be executed.
Sample Backtracting tree
root root
|
/ \ |
/ \ all bar1 failed |
/ \ |
/ | \ \ ===>>>======>>>> |
/ | \ \ |
F F F F E
time 0 1 2 3 4
Abbreviation:
Bar1 failed : F
Bar2 executed : E
You're looking for what's known as "soft cut",
This is equivalent to
(A,B) ; (\+A,C)
: ifA
succeeds at least once, the above is equivalent toA,B
. If not, it's equivalent to justC
. The goalA
is not retried.Simple
if
construct allows the test predicate to succeed only once:is equivalent (almost - see you manual for details) to
(once(A),B) ; (\+A,C)
, except that the goalA
isn't retried.Thus your case shall be
addition: Some Prolog implementations might not have this construct
*->
available (e.g. gprolog). In that case I see two possibilities. Eitheralthough it would retry
A
, or (writinggoal(X)
for A)Of course the order of side-effects will be changed by this. The name
L
of the variable should be chosen such that it does not appear free inB
.