The SWI-Prolog.h header provides various functions for 
accessing, setting, and unifying terms, atoms and other types. 
Typically, these functions return a 0 (false) 
or
1 (true) value for whether they succeeded or 
not. For failure, there might also be an exception created - this can be 
tested by calling PL_excpetion(0).
There are three major groups of methods:
The “put” operations are typically done on an uninstantiated term (see the PlTerm_var() constructor). These are expected to succeed, and typically raise an exception failure (e.g., resource exception) - for details, see the corresponding PL_put_*() functions in Constructing Terms.
For the “get” and “unify” operations, there are three possible failures:
false return code
Each of these is communicated to Prolog by returning false 
from the top level; exceptions also set a “global” exception 
term (using PL_raise_exception()). The C++ programmer usually 
doesn't have to worry about this; instead they can throw PlFail() 
for failure or throw PlException() (or one of PlException’s 
subclasses) and the C++ API will take care of everything.
These are deprecated and replaced by the various as_*() 
methods.
PlTerm can be converted to the following types:
long if the PlTerm is a Prolog 
integer or float that can be converted without loss to a long. Throws a
type_error exception otherwise.long, but might represent fewer bits.PlTerm represents a 
Prolog integer or float.CVT_ALL|CVT_WRITE|BUF_RING, which implies Prolog atoms and 
strings are converted to the represented text. All other data is handed 
to write/1. If 
the text is static in Prolog, a direct pointer to the string is 
returned. Otherwise the text is saved in a ring of 16 buffers and must 
be copied to avoid overwriting.
In addition, the Prolog type (PL_VARIABLE,
PL_ATOM, ... PL_DICT) can be determined using 
the type() method. There are also boolean methods that check the 
type:
See also section 1.13.1.
*blob==nullptr.
A family of unification methods are defined for the various Prolog 
types and C++ types. Wherever string is shown, you can use:
char*whar_t*std::stringstd::wstring
Here is an example:
PREDICATE(hostname, 1)
{ char buf[256];
  if ( gethostname(buf, sizeof buf) == 0 )
    return A1.unify_atom(buf);
  return false;
}
An alternative way of writing this would use the PlCheckFail() to raise an exception if the unification fails.
PREDICATE(hostname2, 1)
{ char buf[256];
  PlCheckFail(gethostname(buf, sizeof buf) == 0);
  PlCheckFail(A1.unify_atom(buf));
  return true;
}
Of course, in a real program, the failure of
gethostname(buf)sizeof buf should create an error term than 
contains information from errno.
PlTerm to a long and perform standard 
C-comparison between the two long integers. If PlTerm 
cannot be converted a type_error is raised.true if the PlTerm is an atom or string 
representing the same text as the argument, false if the 
conversion was successful, but the strings are not equal and an
type_error exception if the conversion failed.Below are some typical examples. See section 1.11.12.2 for direct manipulation of atoms in their internal representation.
| A1 < 0 | Test A1 to hold a Prolog integer or float that can be transformed lossless to an integer less than zero. | 
| A1 < PlTerm(0)  | A1 
is before the term‘0’in the‘standard order of terms’. 
This means that if A1 represents an atom, this test yields true. | 
| A1 == PlCompound("a(1)")  | Test A1 
to represent the term a(1). | 
| A1 == "now" | Test A1 to be an atom or string holding the text “now” . | 
Compound terms can be viewed as an array of terms with a name and 
arity (length). This view is expressed by overloading the []
A type_error is raised if the argument is not compound 
and a
domain_error if the index is out of range.
In addition, the following functions are defined:
PlTerm is a compound term and arg is 
between 1 and the arity of the term, return a new PlTerm 
representing the arg-th argument of the term. If PlTerm is 
not compound, a
type_error is raised. Id arg is out of range, a
domain_error is raised. Please note the counting from 1 
which is consistent to Prolog's arg/3 
predicate, but inconsistent to C's normal view on an array. See also 
class PlCompound. The following example tests x 
to represent a term with first-argument an atom or string equal to gnat.
   ...,
   if ( x[1] == "gnat" )
     ...
const char * holding the name of the functor of 
the compound term. Raises a type_error if the argument is 
not compound.type_error 
if the argument is not compound.
t.is_null() is the 
same as t.unwrap() == PlTerm::nullt.not_null() is the 
same as t.unwrap() != PlTerm::nullt.reset() is the same 
as t.unwrap() = PlTerm::nullt.reset(x) is the same as t.unwrap() = xPL_VARIABLE, PL_FLOAT, PL_INTEGER,
PL_ATOM, PL_STRING or PL_TERM
To avoid very confusing combinations of constructors and therefore 
possible undesirable effects a number of subclasses of PlTerm 
have been defined that provide constructors for creating special Prolog 
terms. These subclasses are defined below.
A SWI-Prolog string represents a byte-string on the global stack. Its 
lifetime is the same as for compound terms and other data living on the 
global stack. Strings are not only a compound representation of text 
that is garbage-collected, but as they can contain 0-bytes, they can be 
used to contain arbitrary C-data structures. However, it is generally 
preferred to use blobs for storing arbitrary C-data structures (see also PlTerm_pointer(void 
*ptr)).
Character lists are compliant to Prolog's atom_chars/2 predicate.
The PlCompound class is a convenience class for creating 
a term from a string; it is similar to (=..)/2
syntax_error exception is raised. Otherwise a new 
term-reference holding the parsed text is created.PlTermv for details. The example below 
creates the Prolog term hello(world).
PlCompound("hello", PlTermv(PlAtom("world")))
The class PlTerm_tail27This 
was named PlTail in version 1 of the API. is 
both for analysing and constructing lists. It is called PlTerm_tail 
as enumeration-steps make the term-reference follow the “tail” of 
the list.
PlTerm_tail is created by making a new term-reference 
pointing to the same object. As PlTerm_tail is used to 
enumerate or build a Prolog list, the initial list 
term-reference keeps pointing to the head of the list.PlTerm_tail 
reference point to the new variable tail. If A is a variable, 
and this function is called on it using the argument "gnat", 
a list of the form [gnat|B] is created and the PlTerm_tail 
object now points to the new variable B.
This function returns true if the unification succeeded 
and
false otherwise. No exceptions are generated.
The example below translates the main() argument vector to Prolog and calls the prolog predicate entry/1 with it.
int
main(int argc, char *argv[])
{ PlEngine e(argv[0]);
  PlTermv av(1);
  PlTerm_tail l(av[0]);
  for(int i=0; i<argc; i++)
    PlCheckFail(l.append(PlTerm_string(argv[i])));
  PlCheckFail(l.close());
  PlQuery q("writeln", av);
  try
  { return q.next_solution() ? 0 : 1;
  } catch ( PlException &ex )
  { std::cerr << ex.what() << std::endl;
    return 1;
  }
}
[]PlTerm_tail 
and advance
PlTerm_tail. Returns true on success and false 
if
PlTerm_tail represents the empty list. If PlTerm_tail 
is neither a list nor the empty list, a type_error is 
thrown. The example below prints the elements of a list.
PREDICATE(write_list, 1)
{ PlTerm_tail tail(A1);
  PlTerm_var e;
  while(tail.next(e))
    cout << e.as_string() << endl;
  return tail.close();
}
The class PlTermv represents an array of 
term-references. This type is used to pass the arguments to a foreign 
defined predicate, construct compound terms (see
PlTerm::PlTerm(const char *name)PlTermv arguments ), and to 
create queries (see PlQuery).
The only useful member function is the overloading of []domain_error exception.
The constructors for this class are below. Note that these can be 
error-prone because there's no distinction between term_t 
and
size_t; the form of the constructor is determined by 
whether the first argument is an integer (term_t or size_t) 
or
PlTerm.
load_file(const char *file)
{ return PlCall("compile", PlTermv(PlAtom(file)));
}
If the vector has to contain more than 5 elements, the following construction should be used:
{ PlTermv av(10);
  av[0].put_term(PlTerm_atom("hello"));
  av[1].put_term(PlTerm_integer(666));
  ...
}
Important: be sure that all the arguments are of type
PlTerm - PlTermv(i) is not the same as
PlTermv(PlTerm_integer(i)), and will result in a 
runtime error.
Both for quick comparison as for quick building of lists of atoms, it is desirable to provide access to Prolog's atom-table, mapping handles to unique string-constants. If the handles of two atoms are different it is guaranteed they represent different text strings.
Suppose we want to test whether a term represents a certain atom, this interface presents a large number of alternatives:
Example:
PREDICATE(test, 1)
{ if ( A1 == "read" )
    ...;
}
This writes easily and is the preferred method is performance is not critical and only a few comparisons have to be made. It validates A1 to be a term-reference representing text (atom, string, integer or float) extracts the represented text and uses strcmp() to match the strings.
Example:
static PlAtom ATOM_read("read");
PREDICATE(test, 1)
{ if ( A1 == ATOM_read )
    ...;
}
This case raises a type_error if A1 is not an 
atom. Otherwise it extacts the atom-handle and compares it to the 
atom-handle of the global PlAtom object. This approach is 
faster and provides more strict type-checking.
Example:
static PlAtom ATOM_read("read");
PREDICATE(test, 1)
{ PlAtom a1(A1);
  if ( a1 == ATOM_read )
    ...;
}
This approach is basically the same as section 1.11.12.2, but in nested if-then-else the extraction of the atom from the term is done only once.
Example:
PREDICATE(test, 1)
{ PlAtom a1(A1);
  if ( a1 == "read" )
    ...;
}
This approach extracts the atom once and for each test extracts the represented string from the atom and compares it. It avoids the need for global atom constructors.
atom_t). Used 
internally and for integration with the C-interface.type_error is thrown.true if the atom represents text, false 
otherwise. Performs a strcmp() or similar for this.true or
false. Because atoms are unique, there is no need to use strcmp() 
for this.==true.char* from a function, you should not 
do return t.as_string().c_str() 
because that will return a pointer into the stack (Gnu C++ or Clang 
options -Wreturn-stack-address or -Wreturn-local-addr) 
can sometimes catch this, as can the runtime address sanitizer 
when run with detect_stack_use_after_return=1. 
This does not quote or escape any characters that would need to be 
escaped if the atom were to be input to the Prolog parser. The possible 
values for enc are:
EncLatin1 - throws an exception if cannot be 
represented in ASCII.EncUTF8EncLocale - uses the locale to determine the 
representation.
The recorded database is has two wrappers, for supporting the internal records and external records.
Currently, the interface to internal records requires that 
the programmer explicitly call the dupicate() and erase() 
methods - in future, it is intended that this will be done automatically 
by a new
PlRecord class, so that the internal records behave like “smart 
pointers” ; in the meantime, the PlRecord provides a 
trivial wrapper around the various recorded database functions.
The class PlRecord supports the following methods:
PlRecord object.
The class PlRecord provides direct access to the 
reference counting aspects of the recorded term (through the duplicate() 
and
erase() methods), but does not 
connect these with C++'s copy constructor, assignment operator, or 
destructor. If the recorded term is encapsulated within an object, then 
the containing object can use the duplicate() 
and erase() methods in its copy and 
move constructors and assignment operators (and the erase() 
method in the destructor).29The 
copy constructor and assignment use the duplicate() 
method; the move constructor and assignment use the duplicate() 
method to assign to the destination and the erase() 
method on the source; and the destructor uses erase().
Alternatively, the std::shared_ptr or std::unique_ptr 
can be used with the supplied PlrecordDeleter, which calls 
the
erase() method when the shared_ptr 
reference count goes to zero or when the std::unique_ptr 
goes out of scope.
For example:
std::shared_ptr<PlRecord> r(new PlRecord(t.record()), PlRecordDeleter()); assert(t.unify_term(r->term()));
The class PlRecordExternalCopy keeps the external 
record as an uninterpreted string (which may contain nulls). It 
supports the following methods.