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)
          • 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.6Plus 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.7You 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 control_t).

The foreign predicate returns a value of true or false to indicate whether it succeeded or failed.8Non-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) or an error (the equivalent of calling throw/1). When an 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 to check for failure, which can become cumbersome. C++ has exceptions, so instead the code can wrap calls to PL_*() functions with PlCheck(), which will do throw PlFail() 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)
{ PlCheck(A1.unify_term(A2));
  return true;
}
PREDICATE(eq, 2)
{ return A1.unify_term(A2);
}
PREDICATE(eq, 2)
{ PlCheck(PL_unify(A1.C_, A2.C_));
  return true;
}