Did you know ... | Search Documentation: |
![]() | 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_)); }