### 10.4 Manipulating Prolog terms

- Introduction
- Managing Prolog atoms
- Reading Prolog terms
- Unifying Prolog terms
- Creating Prolog terms
- Testing the type of Prolog terms
- Comparing Prolog terms
- Term processing
- Comparing and evaluating arithmetic expressions

#### 10.4.1 Introduction

In the following we presents a set of functions to manipulate Prolog terms. For simple foreign terms the functions manipulate simple C types (section 10.3.2).

Functions managing lists handle an array of 2 elements (of type PlTerm) containing the terms corresponding to the head and the tail of the list. For the empty list NULL is passed as the array. These functions require to flatten a list in each sub-list. To simplify the management of proper lists (i.e. lists terminated by []) a set of functions is provided that handle the number of elements of the list (an integer) and an array whose elements (of type PlTerm) are the elements of the list. The caller of these functions must provide the array.

Functions managing compound terms handle a functor (the principal functor of the term), an arity N ≥ 0 and an array of N elements (of type PlTerm) containing the sub-terms of the compound term. Since a list is a special case of compound term (functor = ’.’ and arity=2) it is possible to use any function managing compound terms to deal with a list but the error detection is not the same. Indeed many functions check if the Prolog argument is correct. The name of a read or unify function checking the Prolog arguments is of the form Name_Check(). For each of these functions there is a also check-free version called Name(). We then only present the name of checking functions.

#### 10.4.2 Managing Prolog atoms

Each atom has a unique internal key (an integer) which corresponds to its index in the GNU Prolog atom table. It is possible to obtain the information about an atom and to create new atoms using:

      char   *Pl_Atom_Name           (int atom)
      int     Pl_Atom_Length         (int atom)
      PlBool  Pl_Atom_Needs_Quote    (int atom)
      PlBool  Pl_Atom_Needs_Scan     (int atom)
      PlBool  Pl_Is_Valid_Atom       (int atom)
      int     Pl_Create_Atom         (const char *str)
      int     Pl_Create_Allocate_Atom(const char *str)
      int     Pl_Find_Atom           (const char *str)
      int     Pl_Atom_Char           (char c)
      int     Pl_Atom_Nil            (void)
      int     Pl_Atom_False          (void)
      int     Pl_Atom_True           (void)
      int     Pl_Atom_End_Of_File    (void)

The function Pl_Atom_Name(atom) returns the internal string of atom (this string should not be modified). The function Pl_Atom_Length(atom) returns the length (of the name) of atom.

The function Pl_Atom_Needs_Scan(atom) indicates if the canonical form of atom needs to be quoted as done by writeq/2 (section 8.14.6). In that case Pl_Atom_Needs_Scan(atom) indicates if this simply comes down to write quotes around the name of atom or if it necessary to scan each character of the name because there are some non-printable characters (or included quote characters). The function Pl_Is_Valid_Atom(atom) is true only if atom is the internal key of an existing atom.

The function Pl_Create_Atom(str) adds a new atom whose name is the content of str to the system and returns its internal key. If the atom already exists its key is simply returned. The string str passed to the function should not be modified later. The function Pl_Create_Allocate_Atom(str) is provided when this condition cannot be ensured. It simply makes a dynamic copy of str (using strdup(3)).

The function Pl_Find_Atom(str) returns the internal key of the atom whose name is str or -1 if it does not exist.

All atoms corresponding to a single character already exist and their key can be obtained via the function Pl_Atom_Char. For instance Pl_Atom_Char(’.’) is the atom associated with ’.’ (this atom is the functor of lists). The other functions return the internal key of frequently used atoms: [], false, true and end_of_file.

#### 10.4.3 Reading Prolog terms

The name of all functions presented here are of the form Pl_Rd_Name_Check(). They all check the validity of the Prolog term to read emitting appropriate errors if necessary. Each function has a check-free version called Pl_Rd_Name().

Simple foreign types: for each simple foreign type (section 10.3.2) there is a read function (used by the interface when an input argument is provided):

      PlLong  Pl_Rd_Integer_Check       (PlTerm term)
      PlLong  Pl_Rd_Positive_Check      (PlTerm term)
      int     Pl_Rd_C_Int_Check         (PlTerm term)
      int     Pl_Rd_C_Int_Positive_Check(PlTerm term)
      double  Pl_Rd_Float_Check         (PlTerm term)
      double  Pl_Rd_Number_Check        (PlTerm term)
      int     Pl_Rd_Atom_Check          (PlTerm term)
      int     Pl_Rd_Boolean_Check       (PlTerm term)
      int     Pl_Rd_Char_Check          (PlTerm term)
      int     Pl_Rd_In_Char_Check       (PlTerm term)
      int     Pl_Rd_Code_Check          (PlTerm term)
      int     Pl_Rd_In_Code_Check       (PlTerm term)
      int     Pl_Rd_Byte_Check          (PlTerm term)
      int     Pl_Rd_In_Byte_Check       (PlTerm term)
      char   *Pl_Rd_String_Check        (PlTerm term)
      char   *Pl_Rd_Chars_Check         (PlTerm term)
      char   *Pl_Rd_Codes_Check         (PlTerm term)
      int     Pl_Rd_Chars_Str_Check     (PlTerm term, char *str)
      int     Pl_Rd_Codes_Str_Check     (PlTerm term, char *str)

The function Pl_Rd_C_Int_Check() is similar to Pl_Rd_Integer_Check() but returns a C int instead of a PlLong. If the Prolog integer does not fit into a C int, a representation_error is raised (this can occur on 64-bits machine with int on 32-bits). Similarly for Pl_Rd_C_Int_Positive_Check().

All functions returning a C string (char *) use a same buffer. The function Pl_Rd_Chars_Str_Check() is similar to Pl_Rd_Chars_Check() but accepts as argument a string to store the result and returns the length of that string (which is also the length of the Prolog list). Similarly for Pl_Rd_Codes_Str_Check().

Complex terms: the following functions return the sub-arguments (terms) of complex terms as an array of PlTerm except Pl_Rd_Proper_List_Check() which returns the size of the list read (and initializes the array element). Refer to the introduction of this section for more information about the arguments of complex functions (section 10.4.1).

      int     Pl_Rd_Proper_List_Check(PlTerm term, PlTerm *arg)
      PlTerm *Pl_Rd_List_Check       (PlTerm term)
      PlTerm *Pl_Rd_Compound_Check   (PlTerm term, int *functor, int *arity)
      PlTerm *Pl_Rd_Callable_Check   (PlTerm term, int *functor, int *arity)

#### 10.4.4 Unifying Prolog terms

The name of all functions presented here are of the form Pl_Un_Name_Check(). They all check the validity of the Prolog term to unify emitting appropriate errors if necessary. Each function has a check-free version called Pl_Un_Name().

Simple foreign types: for each simple foreign type (section 10.3.2) there is an unify function (used by the interface when an output argument is provided):

      PlBool Pl_Un_Integer_Check (PlLong n,        PlTerm term)
      PlBool Pl_Un_Positive_Check(PlLong n,        PlTerm term)
      PlBool Pl_Un_Float_Check   (double n,        PlTerm term)
      PlBool Pl_Un_Number_Check  (double n,        PlTerm term)
      PlBool Pl_Un_Atom_Check    (int atom,        PlTerm term)
      PlBool Pl_Un_Boolean_Check (int b,           PlTerm term)
      PlBool Pl_Un_Char_Check    (int c,           PlTerm term)
      PlBool Pl_Un_In_Char_Check (int c,           PlTerm term)
      PlBool Pl_Un_Code_Check    (int c,           PlTerm term)
      PlBool Pl_Un_In_Code_Check (int c,           PlTerm term)
      PlBool Pl_Un_Byte_Check    (int b,           PlTerm term)
      PlBool Pl_Un_In_Byte_Check (int b,           PlTerm term)
      PlBool Pl_Un_String_Check  (const char *str, PlTerm term)
      PlBool Pl_Un_Chars_Check   (const char *str, PlTerm term)
      PlBool Pl_Un_Codes_Check   (const char *str, PlTerm term)

The function Pl_Un_Number_Check(n, term) unifies term with an integer if n is an integer, with a floating point number otherwise. The function Pl_Un_String_Check(str, term) creates the atom corresponding to str and then unifies term with it (same as Pl_Un_Atom_Check(Pl_Create_Allocate_Atom(str), term)).

The following functions perform a general unification (between 2 terms). The second one performs a occurs-check test (while the first one does not).

      PlBool Pl_Unif(PlTerm term1, PlTerm term2)
      PlBool Pl_Unif_With_Occurs_Check(PlTerm term1, PlTerm term2)

Complex terms: the following functions accept the sub-arguments (terms) of complex terms as an array of PlTerm. Refer to the introduction of this section for more information about the arguments of complex functions (section 10.4.1).

      PlBool Pl_Un_Proper_List_Check(int size, PlTerm *arg, PlTerm term)
      PlBool Pl_Un_List_Check       (PlTerm *arg, PlTerm term)
      PlBool Pl_Un_Compound_Check   (int functor, int arity, PlTerm *arg,
                                     PlTerm term)
      PlBool Pl_Un_Callable_Check   (int functor, int arity, PlTerm *arg,
                                     PlTerm term)

All these functions check the type of the term to unify and return the result of the unification. Generally if an unification fails the C function returns PL_FALSE to enforce a failure. However if there are several arguments to unify and if an unification fails then the C function returns PL_FALSE and the type of other arguments has not been checked. Normally all error cases are tested before doing any work to be sure that the predicate fails/succeeds only if no error condition is satisfied. So a good method is to check the validity of all arguments to unify and later to do the unification (using check-free functions). Obviously if there is only one to unify it is more efficient to use a unify function checking the argument. For the other cases the interface provides a set of functions to check the type of a term.

Simple foreign types: for each simple foreign type (section 10.3.2) there is check-for-unification function (used by the interface when an output argument is provided):

      void Pl_Check_For_Un_Integer (PlTerm term)
      void Pl_Check_For_Un_Positive(PlTerm term)
      void Pl_Check_For_Un_Float   (PlTerm term)
      void Pl_Check_For_Un_Number  (PlTerm term)
      void Pl_Check_For_Un_Atom    (PlTerm term)
      void Pl_Check_For_Un_Boolean (PlTerm term)
      void Pl_Check_For_Un_Char    (PlTerm term)
      void Pl_Check_For_Un_In_Char (PlTerm term)
      void Pl_Check_For_Un_Code    (PlTerm term)
      void Pl_Check_For_Un_In_Code (PlTerm term)
      void Pl_Check_For_Un_Byte    (PlTerm term)
      void Pl_Check_For_Un_In_Byte (PlTerm term)
      void Pl_Check_For_Un_String  (PlTerm term)
      void Pl_Check_For_Un_Chars   (PlTerm term)
      void Pl_Check_For_Un_Codes   (PlTerm term)

Complex terms: the following functions check the validity of complex terms:

      void Pl_Check_For_Un_List    (PlTerm term)
      void Pl_Check_For_Un_Compound(PlTerm term)
      void Pl_Check_For_Un_Callable(PlTerm term)
      void Pl_Check_For_Un_Variable(PlTerm term)

The function Pl_Check_For_Un_List(term) checks if term can be unified with a list. This test is done for the entire list (not only for the functor/arity of term but also recursively on the tail of the list). The function Pl_Check_For_Un_Variable(term) ensures that term is not currently instantiated. These functions can be defined using functions to test the type of a Prolog term (section 10.4.6) and functions to raise Prolog errors (section 10.5). For instance Pl_Check_For_Un_List(term) is defined as follows:

      void Pl_Check_For_Un_List(PlTerm term)
      {
       if (!Pl_Builtin_List_Or_Partial_List(term))
           Pl_Err_Type(type_list, term);
      }

#### 10.4.5 Creating Prolog terms

These functions are provided to creates Prolog terms. Each function returns a PlTerm containing the created term.

Simple foreign types: for each simple foreign type (section 10.3.2) there is a creation function:

      PlTerm Pl_Mk_Integer (PlLong n)
      PlTerm Pl_Mk_Positive(PlLong n)
      PlTerm Pl_Mk_Float   (double n)
      PlTerm Pl_Mk_Number  (double n)
      PlTerm Pl_Mk_Atom    (int atom)
      PlTerm Pl_Mk_Boolean (int b)
      PlTerm Pl_Mk_Char    (int c)
      PlTerm Pl_Mk_In_Char (int c)
      PlTerm Pl_Mk_Code    (int c)
      PlTerm Pl_Mk_In_Code (int c)
      PlTerm Pl_Mk_Byte    (int b)
      PlTerm Pl_Mk_In_Byte (int b)
      PlTerm Pl_Mk_String  (const char *str)
      PlTerm Pl_Mk_Chars   (const char *str)
      PlTerm Pl_Mk_Codes   (const char *str)

The function Pl_Mk_Number(n, term) initializes term with an integer if n is an integer, with a floating point number otherwise. The function Pl_Mk_String(str) first creates an atom corresponding to str and then returns that Prolog atom (i.e. equivalent to Pl_Mk_Atom(Pl_Create_Allocate_Atom(str))).

Complex terms: the following functions accept the sub-arguments (terms) of complex terms as an array of PlTerm. Refer to the introduction of this section for more information about the arguments of complex functions (section 10.4.1).

      PlTerm Pl_Mk_Proper_List(int size, const PlTerm *arg)
      PlTerm Pl_Mk_List       (PlTerm *arg)
      PlTerm Pl_Mk_Compound   (int functor, int arity, const PlTerm *arg)
      PlTerm Pl_Mk_Callable   (int functor, int arity, const PlTerm *arg)

#### 10.4.6 Testing the type of Prolog terms

The following functions test the type of a Prolog term. Each function corresponds to a type testing built-in predicate (section 8.1.1).

      PlBool Pl_Builtin_Var                 (PlTerm term)
      PlBool Pl_Builtin_Non_Var             (PlTerm term)
      PlBool Pl_Builtin_Atom                (PlTerm term)
      PlBool Pl_Builtin_Integer             (PlTerm term)
      PlBool Pl_Builtin_Float               (PlTerm term)
      PlBool Pl_Builtin_Number              (PlTerm term)
      PlBool Pl_Builtin_Atomic              (PlTerm term)
      PlBool Pl_Builtin_Compound            (PlTerm term)
      PlBool Pl_Builtin_Callable            (PlTerm term)
      PlBool Pl_Builtin_List                (PlTerm term)
      PlBool Pl_Builtin_Partial_List        (PlTerm term)
      PlBool Pl_Builtin_List_Or_Partial_List(PlTerm term)
      PlBool Pl_Builtin_Fd_Var              (PlTerm term)
      PlBool Pl_Builtin_Non_Fd_Var          (PlTerm term)
      PlBool Pl_Builtin_Generic_Var         (PlTerm term)
      PlBool Pl_Builtin_Non_Generic_Var     (PlTerm term)
      int    Pl_Type_Of_Term                (PlTerm term)
      PlLong   Pl_List_Length                 (PlTerm list)

The function Pl_Type_Of_Term(term) returns the type of term, the following constants can be used to test this type (e.g. in a switch instruction):

- PL_PLV: Prolog variable.
- PL_FDV: finite domain variable.
- PL_INT: integer.
- PL_FLT: floating point number.
- PL_ATM: atom.
- PL_LST: list.
- PL_STC: structure

The tag PL_LST means a term whose principal functor is ’.’ and whose arity is 2 (recall that the empty list is the atom []). The tag PL_STC means any other compound term.

The function Pl_List_Length(list) returns the number of elements of the list (0 for the empty list). If list is not a list this function returns -1.

#### 10.4.7 Comparing Prolog terms

The following functions compares Prolog terms. Each function corresponds to a comparison built-in predicate (section 8.3.2).

      PlBool Pl_Builtin_Term_Eq (PlTerm term1, PlTerm term2)
      PlBool Pl_Builtin_Term_Neq(PlTerm term1, PlTerm term2)
      PlBool Pl_Builtin_Term_Lt (PlTerm term1, PlTerm term2)
      PlBool Pl_Builtin_Term_Lte(PlTerm term1, PlTerm term2)
      PlBool Pl_Builtin_Term_Gt (PlTerm term1, PlTerm term2)
      PlBool Pl_Builtin_Term_Gte(PlTerm term1, PlTerm term2)

All these functions are based on a general comparison function returning a negative integer if term1 is less than term2, 0 if they are equal and a positive integer otherwise:

      PlLong Term_Compare(PlTerm term1, PlTerm term2)

Finally, the following function gives an access to the compare/3 built-in (section 8.3.3) unifying cmp with the atom <, = or > depending on the result of the comparison of term1 and term2.

      PlBool Pl_Builtin_Compare(PlTerm cmp, PlTerm term1, PlTerm term2)

#### 10.4.8 Term processing

The following functions give access to the built-in predicates: functor/3 (section 8.4.1), arg/3 (section 8.4.2) and (=..)/2 (section 8.4.3).

      PlBool Pl_Builtin_Functor(PlTerm term, PlTerm functor, PlTerm arity)

      PlBool Pl_Builtin_Arg(PlTerm arg_no, PlTerm term, PlTerm sub_term)

      PlBool Pl_Builtin_Univ(PlTerm term, PlTerm list)

The following functions make a copy of a Prolog term:

      void Pl_Copy_Term           (PlTerm *dst_term, const PlTerm *src_term)
      void Pl_Copy_Contiguous_Term(PlTerm *dst_term, const PlTerm *src_term)
      int  Pl_Term_Size           (PlTerm term)

The function Pl_Copy_Term(dst_term, src_term) makes a copy of the term located at src_term and stores it from the address given by dst_term. The result is a contiguous term. If it can be ensured that the source term is a contiguous term (i.e. result of a previous copy) the function Pl_Copy_Contiguous_Term() can be used instead (it is faster). In any case, sufficient space should be available for the copy (i.e. from dst_term). The function Pl_Term_Size(term) returns the number of PlTerm needed by term.

The following function is an utility to display a term to the console, similarly to the built-in predicate write/1 (section 8.14.6).

      void Pl_Write(PlTerm term)

This Pl_Write function can be used for debugging purpose. However, it is more flexible to receive the content of the write/1 as a C string. This can be achieved by the following functions (using repectively write/1, writeq/1, write_canonical/1 and display/1 (section 8.14.6) to obtain a textual representation of the term). These functions return a dynamically allocated C string (using malloc(3)) which can be freed by the user when no longer needed.

      char *Pl_Write_To_String(PlTerm term)

      char *Pl_Writeq_To_String(PlTerm term)

      char *Pl_Write_Canonical_To_String(PlTerm term)

      char *Pl_Display_To_String(PlTerm term)

Finally the following function performs the opposite converstion: given a C string it returns the associated Prolog term. It uses read_term/2 (section 8.14.1) with the option end_of_term(eof) (thus the C string does not need to terminate by a dot).

      PlTerm Pl_Read_From_String(const char *str)

#### 10.4.9 Comparing and evaluating arithmetic expressions

The following functions compare arithmetic expressions. Each function corresponds to a comparison built-in predicate (section 8.6.3).

      PlBool Pl_Builtin_Eq (PlTerm expr1, PlTerm expr2)
      PlBool Pl_Builtin_Neq(PlTerm expr1, PlTerm expr2)
      PlBool Pl_Builtin_Lt (PlTerm expr1, PlTerm expr2)
      PlBool Pl_Builtin_Lte(PlTerm expr1, PlTerm expr2)
      PlBool Pl_Builtin_Gt (PlTerm expr1, PlTerm expr2)
      PlBool Pl_Builtin_Gte(PlTerm expr1, PlTerm expr2)

The following function evaluates the expression expr and stores its result as a Prolog number (integer or floating point number) in result:

      void Pl_Math_Evaluate(PlTerm expr, PlTerm *result)

This function can be followed by a read function (section 10.4.3) to obtain the result.

Copyright (C) 1999-2021 Daniel Diaz Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved. More about the copyright