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?
I guess you could wrap
c
inignore/1
. Consider e.g.But why would you want to continue if
c
fails? What's the use case?I tested this code in SWI-Prolog, I'm not sure if other Prologs have
false/0
andignore/1
. The latter can be defined like this though:If your intention is to define
f(A,X)
such thatg(X)
should be evaluated whether or notc
fails, then either:->
) and/or disjunction (;
), orf(A,X)
doesn't need to be defined in terms ofc
. This assumesc
has 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
c
at all, but it will always executec
(as long asa
andb
succeed). The disjunction (;
) allows PROLOG to backtrack to try executinga, b
again ifc
failed 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 thec
subgoal in the first clause. The cut is placed afterc
because we don't want the interpreter to commit to that choice off(A,X)
clause ifc
had failed, instead, we want the interpreter to fail out of this clause and to try the next one, to effectively ignorec
and to continue processingg(X)
.Also note that this solution relies on
a
andb
having no side-effects, because whenc
fails,a
andb
are executed again. If alla
,b
, andc
have side effects, you can try using implication:This will also effectively always execute
g(X)
whetherc
fails or not, and will not executea
andb
again ifc
fails. This single-clause definition will also not leave a choice-point like the previous suggestion.