Manipulating Prolog terms

9.2 | 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
- Copying Prolog terms
- Comparing and evaluating arithmetic expressions

9.2.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 9.1.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.

9.2.2 | Managing Prolog atoms

Each atom has a unique internal key 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 *Atom_Name           (int atom)
      int   Atom_Length         (int atom)
      Bool  Atom_Needs_Quote    (int atom)
      Bool  Atom_Needs_Scan     (int atom)
      Bool  Is_Valid_Atom       (int atom)
      int   Create_Atom         (char *str)
      int   Create_Allocate_Atom(char *str)
      int   Find_Atom           (char *str)
      int   ATOM_CHAR           (char c)
      int   atom_nil
      int   atom_false
      int   atom_true
      int   atom_end_of_file

The macro `Atom_Name(atom)` returns the internal string of `atom` (this string should not be modified). The function `Atom_Lengh(atom)` returns the length (of the name) of `atom`.
The function `Atom_Needs_Scan(atom)` indicates if the canonical form of `atom` needs to be quoted as done by `writeq/2` (section 7.14.6). In that case `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 `Is_Valid_Atom(atom)` is true only if `atom` is the internal key of an existing atom.
The function `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 `Create_Allocate_Atom(str)` is provided when this condition cannot be ensured. It simply makes a dynamic copy of `str`.
The function `Find_Atom(str)` returns the internal key of the atom whose name is `str` or `-1` if does not exist.
All atoms corresponding to a single character already exist and their key can be obtained via the macro `ATOM_CHAR`. For instance `ATOM_CHAR('.')` is the atom associated to `'.'` (this atom is the functor of lists). The other variables correspond to the internal key of frequently used atoms: `[]`, `false`, `true` and `end_of_file`.

9.2.3 | Reading Prolog terms

The name of all functions presented here are of the form `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 `Rd_Name()`.
Simple foreign types: for each simple foreign type (section 9.1.2) there is a read function (used by the interface when an input argument is provided):

      long    Rd_Integer_Check  (PlTerm term)
      long    Rd_Positive_Check (PlTerm term)
      double  Rd_Float_Check    (PlTerm term)
      double  Rd_Number_Check   (PlTerm term)
      int     Rd_Atom_Check     (PlTerm term)
      int     Rd_Boolean_Check  (PlTerm term)
      int     Rd_Char_Check     (PlTerm term)
      int     Rd_In_Char_Check  (PlTerm term)
      int     Rd_Code_Check     (PlTerm term)
      int     Rd_In_Code_Check  (PlTerm term)
      int     Rd_Byte_Check     (PlTerm term)
      int     Rd_In_Byte_Check  (PlTerm term)
      char   *Rd_String_Check   (PlTerm term)
      char   *Rd_Chars_Check    (PlTerm term)
      char   *Rd_Codes_Check    (PlTerm term)
      int     Rd_Chars_Str_Check(PlTerm term, char *str)
      int     Rd_Codes_Str_Check(PlTerm term, char *str)

All functions returning a C string (`char *`) use a same buffer. The function `Rd_Chars_Str_Check()` is similar to `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 `Rd_Codes_Str_Check()`.
Complex terms: the following functions return the sub-arguments (terms) of complex terms as an array of `PlTerm` except `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 9.2.1).

      int     Rd_Proper_List_Check(PlTerm term, PlTerm *arg)
      PlTerm *Rd_List_Check       (PlTerm term)
      PlTerm *Rd_Compound_Check   (PlTerm term, int *functor, int *arity)
      PlTerm *Rd_Callable_Check   (PlTerm term, int *functor, int *arity)

9.2.4 | Unifying Prolog terms

The name of all functions presented here are of the form `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 `Un_Name()`.
Simple foreign types: for each simple foreign type (section 9.1.2) there is an unify function (used by the interface when an output argument is provided):

      Bool Un_Integer_Check (long n,    PlTerm term)
      Bool Un_Positive_Check(long n,    PlTerm term)
      Bool Un_Float_Check   (double n,  PlTerm term)
      Bool Un_Number_Check  (double n,  PlTerm term)
      Bool Un_Atom_Check    (int atom,  PlTerm term)
      Bool Un_Boolean_Check (int b,     PlTerm term)
      Bool Un_Char_Check    (int c,     PlTerm term)
      Bool Un_In_Char_Check (int c,     PlTerm term)
      Bool Un_Code_Check    (int c,     PlTerm term)
      Bool Un_In_Code_Check (int c,     PlTerm term)
      Bool Un_Byte_Check    (int b,     PlTerm term)
      Bool Un_In_Byte_Check (int b,     PlTerm term)
      Bool Un_String_Check  (char *str, PlTerm term)
      Bool Un_Chars_Check   (char *str, PlTerm term)
      Bool Un_Codes_Check   (char *str, PlTerm term)

The function `Un_Number_Check(n, term)` unifies `term` with an integer if `n` is an integer, with a floating point number otherwise. The function `Un_String_Check(str, term)` creates the atom corresponding to `str` and then unifies term with it (same as `Un_Atom_Check(Create_Allocate_Atom(str), term)`).
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 9.2.1).

      Bool Un_Proper_List_Check(int size, PlTerm *arg, PlTerm term)
      Bool Un_List_Check       (PlTerm *arg, PlTerm term)
      Bool Un_Compound_Check   (int functor, int arity, PlTerm *arg,
                                PlTerm term)
      Bool 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 `FALSE` to enforce a failure. However if there are several arguments to unify and if an unification fails then the C function returns `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 if 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 9.1.2) there is check-for-unification function (used by the interface when an output argument is provided):

      void Check_For_Un_Integer (PlTerm term)
      void Check_For_Un_Positive(PlTerm term)
      void Check_For_Un_Float   (PlTerm term)
      void Check_For_Un_Number  (PlTerm term)
      void Check_For_Un_Atom    (PlTerm term)
      void Check_For_Un_Boolean (PlTerm term)
      void Check_For_Un_Char    (PlTerm term)
      void Check_For_Un_In_Char (PlTerm term)
      void Check_For_Un_Code    (PlTerm term)
      void Check_For_Un_In_Code (PlTerm term)
      void Check_For_Un_Byte    (PlTerm term)
      void Check_For_Un_In_Byte (PlTerm term)
      void Check_For_Un_String  (PlTerm term)
      void Check_For_Un_Chars   (PlTerm term)
      void Check_For_Un_Codes   (PlTerm term)

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

      void Check_For_Un_List    (PlTerm term)
      void Check_For_Un_Compound(PlTerm term)
      void Check_For_Un_Callable(PlTerm term)
      void Check_For_Un_Variable(PlTerm term)

The function `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 `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 9.2.6) and functions to raise Prolog errors (section 9.3). For instance `Check_For_Un_List(term)` is defined as follows:

      void Check_For_Un_List(PlTerm term)
      {
       if (!Blt_List_Or_Partial_List(term))
           Pl_Err_Type(type_list, term);
      }

9.2.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 9.1.2) there is a creation function:

      PlTerm Mk_Integer (long n)
      PlTerm Mk_Positive(long n)
      PlTerm Mk_Float   (double n)
      PlTerm Mk_Number  (double n)
      PlTerm Mk_Atom    (int atom)
      PlTerm Mk_Boolean (int b)
      PlTerm Mk_Char    (int c)
      PlTerm Mk_In_Char (int c)
      PlTerm Mk_Code    (int c)
      PlTerm Mk_In_Code (int c)
      PlTerm Mk_Byte    (int b)
      PlTerm Mk_In_Byte (int b)
      PlTerm Mk_String  (char *str)
      PlTerm Mk_Chars   (char *str)
      PlTerm Mk_Codes   (char *str)

The function `Mk_Number(n, term)` initializes `term` with an integer if `n` is an integer, with a floating point number otherwise. The function `Mk_String(str)` first creates an atom corresponding to `str` and then returns that Prolog atom (i.e. equivalent to `Mk_Atom(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 9.2.1).

      PlTerm Mk_Proper_List(int size, PlTerm *arg)
      PlTerm Mk_List       (PlTerm *arg)
      PlTerm Mk_Compound   (int functor, int arity, PlTerm *arg)
      PlTerm Mk_Callable   (int functor, int arity, PlTerm *arg)

9.2.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 7.1.1).

      Bool Blt_Var                 (PlTerm term)
      Bool Blt_Non_Var             (PlTerm term)
      Bool Blt_Atom                (PlTerm term)
      Bool Blt_Integer             (PlTerm term)
      Bool Blt_Float               (PlTerm term)
      Bool Blt_Number              (PlTerm term)
      Bool Blt_Atomic              (PlTerm term)
      Bool Blt_Compound            (PlTerm term)
      Bool Blt_Callable            (PlTerm term)
      Bool Blt_List                (PlTerm term)
      Bool Blt_Partial_List        (PlTerm term)
      Bool Blt_List_Or_Partial_List(PlTerm term)
      Bool Blt_Fd_Var              (PlTerm term)
      Bool Blt_Non_Fd_Var          (PlTerm term)
      Bool Blt_Generic_Var         (PlTerm term)
      Bool Blt_Non_Generic_Var     (PlTerm term)
      int  Type_Of_Term            (PlTerm term)
      int  List_Length             (PlTerm list)

The function `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):

- `PLV`: Prolog variable.
- `FDV`: finite domain variable.
- `INT`: integer.
- `FLT`: floating point number.
- `ATM`: atom.
- `LST`: list.
- `STC`: structure

The tag `LST` means a term whose principal functor is `'.'` and whose arity is 2 (recall that the empty list is the atom `[]`). The tag `STC` means any other compound term.
The function `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`.

9.2.7 | Comparing Prolog terms

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

      Bool Blt_Term_Eq (PlTerm term1, PlTerm term2)
      Bool Blt_Term_Neq(PlTerm term1, PlTerm term2)
      Bool Blt_Term_Lt (PlTerm term1, PlTerm term2)
      Bool Blt_Term_Lte(PlTerm term1, PlTerm term2)
      Bool Blt_Term_Gt (PlTerm term1, PlTerm term2)
      Bool Blt_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:

      int Term_Compare(PlTerm term1, PlTerm term2)

9.2.8 | Copying Prolog terms

The following functions make a copy of a Prolog term:

      void Copy_Term           (PlTerm *dst_adr, PlTerm *src_adr)
      void Copy_Contiguous_Term(PlTerm *dst_adr, PlTerm *src_adr)
      int  Term_Size           (PlTerm term)

The function `Copy_Term(dst_adr, src_adr)` makes a copy of the term located at `src_adr` and stores it from the address given by `dst_adr`. 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 `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_adr`). The function `Term_Size(term)` returns the number of `PlTerm` needed by `term`.

9.2.9 | Comparing and evaluating arithmetic expressions

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

      Bool Blt_Eq (PlTerm expr1, PlTerm expr2)
      Bool Blt_Neq(PlTerm expr1, PlTerm expr2)
      Bool Blt_Lt (PlTerm expr1, PlTerm expr2)
      Bool Blt_Lte(PlTerm expr1, PlTerm expr2)
      Bool Blt_Gt (PlTerm expr1, PlTerm expr2)
      Bool Blt_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 Math_Load_Value(PlTerm expr, PlTerm *result)

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

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