Before going into a detailed description of the C++ classes we present a few examples illustrating the “feel” of the interface.
This simple example shows the basic definition of the predicate hello/1 and how a Prolog argument is converted to C-data:
PREDICATE(hello, 1)
{ cout << "Hello " << A1.as_string() << endl;
return true;
}
The arguments to PREDICATE()
are the name and arity of the predicate. The macros A<n>
provide access to the predicate arguments by position and are of the
type PlTerm. The C or C++ string for a PlTerm
can be extracted using as_string(),
or as_wstring() methods;25The
C-string values can be extracted from std::string by using c_str(),
but you must be careful to not return a pointer to a local/stack value,
so this isn't recommende. and similar access methods
provide an easy type-conversion for most Prolog data-types, using the
output of write/1
otherwise:
?- hello(world). Hello world Yes ?- hello(X) Hello _G170 X = _G170
This example shows arithmetic using the C++ interface, including unification, type-checking, and conversion. The predicate add/3 adds the two first arguments and unifies the last with the result.
PREDICATE(add, 3)
{ return A3.unify_integer(A1.as_long() + A2.as_long());
}
You can use your own variable names instead of A1,
A2, etc.:
PREDICATE(add, 3) // add(+X, +Y, +Result)
{ PlTerm x(A1);
PlTerm y(A2);
PlTerm result(A3);
return result.unify_integer(x.as_long() + y.as_long());
}
or more compactly:
PREDICATE(add, 3) // add(+X, +Y, +Result)
{ auto x = A1, y = A2, result = A3;
return result.unify_integer(x.as_long() + y.as_long());
}
The as_long() method for a PlTerm performs a PL_get_long_ex()
and throws a C++ exception if the Prolog argument is not a Prolog
integer or float that can be converted without loss to a
long. The unify_integer() method of PlTerm
is defined to perform unification and returns true or false
depending on the result.
?- add(1, 2, X). X = 3. ?- add(a, 2, X). [ERROR: Type error: `integer' expected, found `a'] Exception: ( 7) add(a, 2, _G197) ?
This example is a bit harder. The predicate average/3 is defined to take the template average(+Var, :Goal, -Average) , where Goal binds Var and will unify Average with average of the (integer) results.
PlQuery takes the name of a predicate and the
goal-argument vector as arguments. From this information it deduces the
arity and locates the predicate. The method PlQuery::next_solution()
yields
true if there was a solution and false
otherwise. If the goal yields a Prolog exception, it is mapped into a
C++ exception. A return to Prolog does an implicit “cut” (PL_cut_query());
this can also be done explicitly by the PlQuery::cut()
method.
PREDICATE(average, 3) /* average(+Templ, :Goal, -Average) */
{ long sum = 0;
long n = 0;
PlQuery q("call", PlTermv(A2));
while( q.next_solution() )
{ sum += A1.as_long();
n++;
}
return A3.unify_float(double(sum) / double(n));
}
?- [user]. |: p(1). |: p(10). |: p(20). |: % user://1 compiled 0.00 sec, 3 clauses true. ?- average(X, p(X), Average). Average = 10.333333333333334.