My Prolog programming conventions Frans A. Meijs

General programming conventions

A general introduction to the Prolog programming language can be found in [Bratko I. 1990]. For describing syntactical categories we will use standard Backus Naur Format (BNF) notation.

The syntactic category

                <common noun >( <identifier> )

has the same meaning as the English sentence:

    There is a <common noun> which is identified by <identifier>

The existence of a concept is identified by a unique identifier, so it is not allowed to write a particular identifier in conjunction with two different common nouns. The syntactic category

 <subject noun>__<predicate verb phrase>_<object noun>
                       ( <identifier 1>, <identifier 2> )

has the same meaning as the English sentence

     <subject noun><identifier 1> 
              <predicate verb phrase> 
                      <object noun><identifier 2> 

Each functor — a word immediately to the left of a left-parenthesis "(" — is kept isomorphic to the English language, in order to minimize the probability that it will be interpreted in another way than intended b y the author. For the English language, the Oxford dictionary is taken as reference. In a functor, the character string "__" (a double underline character) indicates that an identifier has to be read in this place. When doing this, the identifiers should be read in the order as they appear in the argument list.

The verb-phrase _e_ is a shorthand notation for is element of.
The verb-phrase _i_ is a shorthand notation for is instance of.

Exceptions to all these conventions are explicitly documented.

Detail programming conventions

  1. Theories which have input reading as sole purpose have a clause head which starts with subject_, s_, input_ or i_. For avoiding interference with the problem-solving logic of a program they should never fail.
  2. Theories which have writing output as sole purpose have a clause head which starts with object_, output_ or o_. For avoiding interference with the problem solving logic of a program they should never fail.
  3. A term which is argument of a not/1 term should have no output variables: Just input and anonymous variables are allowed [Naish L. 1995].
  4. In the antecedent of a generalization, preserving the order of the arguments of the consequent is preferred.
  5. In the antecedent of a rule, terms have to be written in order of instantiation of their variables, e.g. ..., foo(X, Y), bar(Y, Z),... where X is instantiated first, followed by Y and Z respectively. This increases readability and efficiency.
  6. For computationally expensive theories, exploit the tail-recursion optimization facility of modern Prolog interpreters [Knuutila T. 1992]. A special case of this is the use of difference lists.
  7. Apply the cut only at the end of clauses. Its sole purpose should be to limit searching a solution space up to the first solution. It should be tagged with the comment: "Solution is sufficient".
  8. Avoid the use of composite terms (structures). Lists are preferred over them [Knuutila T. 1992].
  9. Apply assert/1 only in the following cases:
    a. It limits a solution search space by an order of magnitude.
    b. A simulation has to be done.
    c. The program has to learn.
  10. When one of the input arguments of a clause is of a wrong type, it should fail.
  11. When one of the input arguments of a clause is unbound where it should have been, the clause should fail and o_Exception_msg/3 has to be called.
  12. Avoid generalizations which introduce multiple inheritance: They degrade the speed of verification/validation by making duplicate instances.
  13. Define generalizations only in case a constraint is defined in terms of the antecedent term, or when — for searching time reasons — searches have to be localized by expressing them in terms of the antecedent.
  14. When a choice can be made between generating facts as input data, or generating them implicitly by the interpreter, the first method should be chosen. It allows elimination of duplicate facts by sorting the input file.
  15. In each file, clauses with equal heads should be placed adjacently. This prevents inadvertent duplicate clauses.
  16. For terminal terms — terms which have no definition — so-called stubs have to be defined in files with name extension "PRS". A stub is a definition of the type <functor>(_) :- fail.
    This prevents a Prolog interpreter from on-the-fly searching for the missing definition.

Literature

[Bundy A. 1983] [Bratko I. 1990] [Coelho H. 1988] [Goebel R. 1986] [Hogger C. 1990] [ISO/IEC 1982] [Knuutila T. 1992] [Lloyd J. 1990] [Naish L. 1995] [Sterling L. 1986]