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