2.15 The PREDICATE and PREDICATE_NONDET macros (version 2)
AllApplicationManualNameSummaryHelp

  • Documentation
    • Reference manual
    • Packages
      • A C++ interface to SWI-Prolog
        • A C++ interface to SWI-Prolog (Version 2)
          • The PREDICATE and PREDICATE_NONDET macros (version 2)
            • Variations of the PREDICATE macro (version 2)
            • Non-deterministic predicates (version 2)
            • Controlling the Prolog destination module (version 2)

2.15.2 Non-deterministic predicates (version 2)

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
}