2 A C++ interface to SWI-Prolog (Version 2)
AllApplicationManualNameSummaryHelp

  • Documentation
    • Reference manual
    • Packages
      • A C++ interface to SWI-Prolog
        • A C++ interface to SWI-Prolog (Version 2)
          • Summary of changes between Versions 1 and 2
          • Introduction (version 2)
          • The life of a PREDICATE (version 2)
          • Overview (version 2)
          • Examples (version 2)
          • Rational for changes from version 1 (version 2)
          • Porting from version 1 to version 2
          • The class PlFail (version 2)
          • The class PlTerm (version 2)
          • The class PlTermv (version 2)
          • The class PlAtom - Supporting Prolog constants (version 2)
          • Classes for the recorded database: PlRecord and PlRecordExternalCopy
          • Unification and foreign frames (version 2)
          • The class PlRegister (version 2)
          • The class PlQuery (version 2)
          • The PREDICATE and PREDICATE_NONDET macros (version 2)
          • Exceptions (version 2)
          • Embedded applications (version 2)
          • Considerations (version 2)
          • Conclusions (version 2)

2.3 The life of a PREDICATE (version 2)

A foreign predicate is defined using the PREDICATE() macro, pPlus a few variations on this, such as PREDICATE_NONDET(), NAMED_PREDICATE(), and NAMED_PREDICATE_NONDET(). This defines an internal name for the function, registers it with the SWI-Prolog runtime (where it will be picked up by the use_foreign_library/1 directive), and defines the names A1, A2, etc. for the arguments.8You can define your own names for the arguments, for example: auto x=A1, y=A2, result=A3;. If a non-deterministic predicate is being defined, an additional parameter handle is defined (of type PlControl).

The foreign predicate returns a value of true or false to indicate whether it succeeded or failed.9Non-deterministic predicates can also return a "retry" value. If a predicate fails, it could be simple failure (the equivalent of calling the builtin fail/0 predicate) or an error (the equivalent of calling the throw/1 predicate). When a Prolog exception is raised, it is important that a return be made to the calling environment as soon as possible. In C code, this requires checking every call for failure, which can become cumbersome. C++ has exceptions, so instead the code can wrap calls to PL_*() functions with PlCheck_PL() or PlCheckEx(), which will throw a PlException() to exit from the top level of the foreign predicate, and handle the failure or exception appropriately.

The following three snippets do the same thing (for implementing the equivalent of =/2):

PREDICATE(eq, 2)
{ PlCheckFail(A1.unify_term(A2));
  return true;
}
PREDICATE(eq, 2)
{ return A1.unify_term(A2);
}
PREDICATE(eq, 2)
{ return PlWrap<int>(PL_unify(A1.C_, A2.C_));
}