Have a curiosity related to Prolog predicate control.
Supposedly I have a predicate f(A,X) and g(B).
f(A,X):- a,b,c, g(X).
g(B):- true.
a - returns true
b - returns true.
c - returns false.
where a,b and c are random predicates.
How can I continue to evaluate g(X) in the predicate f(A,X) if c returns false?
If your intention is to define
f(A,X)such thatg(X)should be evaluated whether or notcfails, then either:->) and/or disjunction (;), orf(A,X)doesn’t need to be defined in terms ofc. This assumeschas no side-effects (e.g., asserting database facts usingassert, or printing IO to a stream) which alter the environment and which cannot be undone on failure ofc, in which case the first option is preferable.There are several alternatives for using disjunction, such as:
This definition (above) doesn’t depend on
cat all, but it will always executec(as long asaandbsucceed). The disjunction (;) allows PROLOG to backtrack to try executinga, bagain ifcfailed at all, and to continue ontog(X). Note that this is equivalent to:In order for PROLOG not to backtrack to evaluate
f(A,X)twice because of the second (identical) head predicatef(A,X)for every evaluation, you may choose to place a cut (!), if your implementation supports it, immediately after thecsubgoal in the first clause. The cut is placed aftercbecause we don’t want the interpreter to commit to that choice off(A,X)clause ifchad failed, instead, we want the interpreter to fail out of this clause and to try the next one, to effectively ignorecand to continue processingg(X).Also note that this solution relies on
aandbhaving no side-effects, because whencfails,aandbare executed again. If alla,b, andchave side effects, you can try using implication:This will also effectively always execute
g(X)whethercfails or not, and will not executeaandbagain ifcfails. This single-clause definition will also not leave a choice-point like the previous suggestion.