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 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 (the context is nullptr
on the
first call). To simplify this, a template helper function
PlControl::context_unique_ptr<ContextType>() provides a
"smart pointer" that frees the context on normal return or an exception;
when used with PL_retry_address(), the context's std:unique_ptr<ContextType>::release()
is used to pass the context to Prolog for the next retry, and to prevent
the context from being freed. If the predicate is called with PL_PRUNE
,
the normal return true
will implicitly free the context.
The skeleton for a typical non-deterministic predicate is:
struct PredContext { ... }; // The "context" for retries PREDICATE_NONDET(pred, <arity>) { auto ctxt = handle.context_unique_ptr<PredContext>(); switch( PL_foreign_control(handle) ) { case PL_FIRST_CALL: ctxt.reset(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) ... PL_retry_address(ctxt.release()); // Succeed with a choice point }