Non-deterministic predicates are defined using PREDICATE_NONDET(plname, cname, arity) or NAMED_PREDICATE_NONDET(plname, cname, arity).
A non-deterministic predicate returns a "context", which is passed to
a a subsequent retry. Typically, this context is allocated on the first
call to the predicate and freed when the predicate either fails or does
its last successful return. To simplify this, a template helper class
PlForeignContextPtr<ContextType> provides a
"smart pointer" that frees the context on normal return or an exception;
if PlForeignContextPtr<ContextType>::keep() is called, the
pointer isn't freed on return or exception.
The skeleton for a typical non-deterministic predicate is:
struct PredContext { ... }; // The "context" for retries
PREDICATE_NONDET(pred, <arity>)
{ PlForeignContextPtr<PredContext> ctxt(handle);
switch( PL_foreign_control(handle) )
{ case PL_FIRST_CALL:
ctxt.set(new PredContext(...));
...
break;
case PL_REDO:
break;
case PL_PRUNED:
return true;
}
if ( ... )
return false; // Failure (and no more solutions)
// or throw PlFail();
if ( ... )
return true; // Success (and no more solutions)
...
ctxt.keep();
PL_retry_address(ctxt.get()); // Succeed with a choice point
}