The class PlFrame
provides an interface to discard
unused term-references as well as rewinding unifications (data-backtracking).
Reclaiming unused term-references is automatically performed after a
call to a C++-defined predicate has finished and returns control to
Prolog. In this scenario PlFrame
is rarely of any use. This
class comes into play if the toplevel program is defined in C++ and
calls Prolog multiple times. Setting up arguments to a query requires
term-references and using PlFrame
is the only way to
reclaim them.
A typical use for PlFrame
is
the definition of C++ functions that call Prolog and may be called
repeatedly from C++. Consider the definition of assertWord(), adding a
fact to word/1:
void assertWord(const char *word) { PlFrame fr; PlTermv av(1); av[0] = PlCompound("word", PlTermv(word)); PlQuery q("assert", av); PlCheckFail(q.next_solution()); }
This example shows the most sensible use of PlFrame
if
it is used in the context of a foreign predicate. The predicate's
thruth-value is the same as for the Prolog unification (=/2), but has no
side effects. In Prolog one would use double negation to achieve this.
PREDICATE(can_unify, 2) { PlFrame fr; int rval = (A1=A2); fr.rewind(); return rval; }
PlRewindOnFail(f) is a convenience function that does a frame
rewind if unification fails. Here is an example, where name_to_term
contains a map from names to terms (which are made global by using the
PL_record() function):
static const std::map<const std::string, record_t> name_to_term = { {"a", PlTerm(...).record()}, ...}; bool lookup_term(const std::string name, PlTerm result) { const auto it = name_to_term.find(name); if ( it == name_to_term.cend() ) return false; PlTerm t = PlTerm_recorded(it->second); return PlRewindOnFail([result,t]() -> bool { return result.unify_term(t); }); }