External predicates are either tests, which only take input arguments and succeed or fail, or they yield a result by unifying one or more arguments with some terms. In ECLiPSe externals, the unification is always performed outside of the external predicate, after returning to the system. Depending on its result, the external predicate either succeeds or fails.
If the external predicate unifies only one pair of terms, which is the most common case, the Return_Unify macro family is used, e.g.
which requests that the Prolog term with value val and tag tag is unified with the atom atom. This macro causes as well the return from the external predicate.Return_Unify_Atom(val, tag, atom)
When there are several terms to be unified in the external predicate, the Request_Unify macro family is to be used, e.g.
Each of them remembers which term pair has to be unified, and after the return to the system using the Return_Unify macro, all of them are subsequently unified. If all these unifications succeed, so does the external predicate, otherwise it fails. At the beginning of the external predicate, after the declarations, the macroRequest_Unify_List(val, tag, list_ptr)
must appear, which sets up a variable that counts how many requests there will be. It must appear at the beginning of a block since it contains a C declaration.Prepare_Requests
The concepts introduced so far can be illustrated in the following example.
int p_sincos(val_arg, tag_arg, val_sin, tag_sin, val_cos, tag_cos) value val_arg, val_sin, val_cos; type tag_arg, tag_sin, tag_cos; { extern void sincos(); /* from the math library */ double s, c; Prepare_Requests; Error_If_Ref(tag_arg); Check_Output_Float(tag_sin); Check_Output_Float(tag_cos); if (IsFloat(tag_arg) || IsDouble(tag_arg)) sincos(FloatVal(val_arg), &s, &c); else if (IsInteger(tag_arg)) sincos((double) val_arg.nint, &s, &c); else { Error(TYPE_ERROR); } Request_Unify_Float(val_sin, tag_sin, s); Request_Unify_Float(val_cos, tag_cos, c); Return_Unify; }
This external implements the Prolog procedure sincos/2, whose first argument is an integer or a float and which computes simultaneously the sine and cosine of a given number. The second and third arguments are the result arguments. They may be variables or floating point numbers.
The first argument must be instantiated; hence the first statement is a call of Error_If_Ref. The next two lines check the other arguments for being variables or floats. Then it must be checked if the argument is an integer or a float, since they have different representations. In the integer case, a type conversion is necessary before calling the library function sincos(). If the argument is not a number, the external is exited with a type error. The last statements illustrate how unification is done: without any further testing of the second argument we just request its unification with a given value and the rest is done by the system. Note that if the Check_Output_Float() statements at the beginning are omitted, the result unification would just fail when the external is called with the second or third argument instantiated to non-floats.