• Places
    • Home
    • Graphs
    • Prefixes
  • Admin
    • Users
    • Settings
    • Plugins
    • Statistics
  • Repository
    • Load local file
    • Load from HTTP
    • Load from library
    • Remove triples
    • Clear repository
  • Query
    • YASGUI SPARQL Editor
    • Simple Form
  • Help
    • Documentation
    • Tutorial
    • Roadmap
    • HTTP Services
  • Login

2 A C++ interface to SWI-Prolog (Version 2)
All Application Manual Name SummaryHelp

  • 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
          • Sample code (version 2)
          • Introduction (version 2)
          • The life of a PREDICATE (version 2)
          • Overview (version 2)
          • Examples (version 2)
          • Rationale 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.4 The life of a PREDICATE (version 2)

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

The foreign predicate returns a value:

  • true - success
  • false - failure or an error (see section 2.18 and Prolog exceptions in foreign code).
  • "retry" - for non-deterministic predicates, gives a "context" for backtracking / redoing the call for the next solution.
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 PlCheckFail() 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 essentially the same thing (for implementing the equivalent of =/2); however the forst option (with PlTerm::unify_term()) and third option (with Plx_unify()) throw a C++ PlExceptionFail exception if there's an error and return true or false; the second option (with PlCheckFail()) throws a PlFail exception for both failure and an error and otherwise returns true - the PREDICATE() wrapper handles all of these appropriately and reports the same result back to Prolog; but you might wish to distinguish the two situations in more complex code.

PREDICATE(eq, 2)
{ return A1.unify_term(A2);
}
PREDICATE(eq, 2)
{ PlCheckFail(A1.unify_term(A2));
  return true;
}
PREDICATE(eq, 2)
{ return Plx_unify(A1.C_, A2.C_));
}

ClioPatria (version V3.1.1-48-gf653ce4)