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;
}