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.6You can define
your own names for the arguments, for example: auto dir=A1, db=A2;
or PlTerm 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
- successfalse
- failure or an error (see section
1.15 and Prolog
exceptions in foreign code).The C++ API provides Plx_*() functions that are the same as the PL_*() functions except that where appropriate they check for exceptions and thrown a PlException().
Addditionally, the function PlCheckFail()
can be used to check for failure and throw a PlFail
exception that is handled before returning to Prolog with failure.
The following three snippets do essentially the same thing (for
implementing the equivalent of =/2); however the first version (with
PlTerm::unify_term())
and second version (with Plx_unify()) throw a C++ PlExceptionFail
exception if there's an error and otherwise return true
or false
;
the third version (with PlCheckFail())
throws a PlFail
exception for failure (and PlExceptionFail
for 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) { return Plx_unify(A1.unwrap(), A2.unwrap())); }
PREDICATE(eq, 2) { PlCheckFail(A1.unify_term(A2)); return true; }