Term I/O and operators
Term Input and Output
The term Input/Output predicates read and write any valid Prolog term. Terms follow a standard format, both when entered by the user and when returned by the program:
- When a term is read by Arity/Prolog32, a period followed either by white space (such as <space>, <tab> or <cr>) or by the end of the file marks the end of the term. However, these characters are not interpreted as part of the term.
- Atoms and functor names may be quoted with either a single quote character (') or with a dollar sign ($). The character being used for quoting must be doubled if it occurs within the atom or functor name.
- You must place quotes around an atom or functor name that begins with an upper-case letter or that contains a period character or white space.
- If the term being read ends with an atom consisting entirely of symbolic characters you must either quote the atom or leave white space after the atom and before the terminating period.
- When the program writes a term, uninstantiated variables are written as an underscore followed by a hexadecimal number. This corresponds to the variable's memory location, not the name that you assigned the variable.
During input and output, expressions involving operators can be entered and are returned according to their operator definitions. Operator definitions allow you to use a more conventional notation for reading and writing these expressions. For example, the addition operator, +, is an infix operator, which means the operator appears between its operands. Therefore, the addition of two terms can be input as
3 + 2
rather than as its internal representation as prefix notation:
+(3, 2)
Of course, the use of parentheses to group subterms can override the effect of operators.
Arity/Prolog32 defines a set of operators that are convenient for program construction, arithmetic expressions, and common operations. Unlike most languages, these operator definitions are not fixed - you are free to add and modify operator definitions. The predicates for reading terms and some of the predicates for writing terms automatically adapt to changes in operator definitions.
By creating sets of operator definitions you can create your own operator precedence parsers. While not as powerful as some other formalisms, they are easy to construct and highly efficient.
More detail concerning operators and their use follows the descriptions of term I/O predicates.
Term I/O predicates
read(-Term)
read(+Handle, -Term)
You use the read/1 and read/2 predicates to read a term from the standard input device or from a specified file Handle, respectively.
The read/1 and read/2 predicates understand the syntax of the operator definitions (see the op/3 predicate). Thus, you can input an expression involving an operator according to its operator definition, and read will translate the expression to prefix notation. Prefix notation is the form that is understood internally by Arity/Prolog32.
The read/1 and read/2 predicates are used by the consult and reconsult predicates which load Prolog predicate definitions into the database from files.
write(+Term)
write(+Handle, +Term)
You use the write/1 and write/2 predicates to write a term to the standard output device or the specified file Handle, respectively. Any uninstantiated variables are written as an underscore followed by a hexadecimal number which corresponds to a memory location. A variable that is shared with another variable also shares this number when it is written.
The write/1 and write/2 predicates understand the syntax of operator definitions and uses those definitions when the term is written. When it writes an expression involving an operator to the terminal, write/n converts the term from prefix notation to the notation defined in its operator definition. However, the write/1 and write/2 predicates do not quote atoms according to the rules required for read/1 and read/2. This enhances human readability but in general should not be used when terms will be read back into Arity/Prolog32.
writeq(+Term)
writeq(+Handle, +Term)
The writeq/1 and writeq/2 predicates are the same as the write/1 and write/2 predicates except that they enclose each atom and functor name in quotes as necessary for that term to be in a form acceptable by the read/1 and read/2 predicates.
display(+Term)
display(+Handle, +Term)
The display/1 and display/2 predicates write terms in prefix notation to the standard output device or the specified file Handle, respectively. Operator definitions are ignored but each atom and functor name is enclosed in quotes as necessary for the displayed term to be in a form acceptable by the read/1 and read/2 predicates.
For example:
?- display( (1 + 2) * 3).
'*'('+'(1,2),3))
yes
Operators
Operator definitions are used by the read/1, read/2, write/1, write/2, writeq/1, and writeq/2 predicates and by the predicates that consult code into the database or that are used to compile code. No other operations within Arity/Prolog32 rely on operator definitions. The default operator definitions for Arity/Prolog32 are presented in a table at the end of this section.
Operators in Arity/Prolog32 may be occur in three different positions:
Prefix
A prefix operator occurs before its single argument. In ordinary arithmetic, unary minus is denoted as a prefix operator.
Infix
An infix operator occurs between its two arguments. In ordinary arithmetic, addition and multiplication are denoted as infix operators.
Postfix
A postifx operator occurs after its single argument. Postfix operators are less commonly used and no postfix operators are defined in the default set of Arity/Prolog32 operators. The most well known use of postfix operators is for Reverse Polish Notation (RPN).
Each operator has two qualities that determine its effect: Precedence and Associativity.
Precedence
The precedence of an operator is specified by an integer in the range 0 to 1200. Precedence determines the order in which operators are translated; that is, which operator is outermost in prefix notation when parentheses are not used to explicitly override the effect of the operator in the expression. For example, the multiplication operator has a lower precedence than the addition operator. Thus, the addition operator becomes the principal functor. The precedence rules ensure that an expression such as:
a * b + c
is translated to:
+(*(a,b),c)
Since the multiplication operator is lower precedence (400) than the addition operator (500) , the term *(a,b) becomes the first argument to the principal functor, +.
Expressions involving operators with precedence of 1000 or higher cannot be used as arguments to a functor unless they are enclosed in parentheses; those with precedence below 1000 can. If you assign an operator a precedence of 0, that operator is disabled.
Associativity
Associativity determines the order in which operators are translated when two or more operators of the same precedence are used and parentheses do not break the ambiguity. The associativity of an operator can be left-to-right associative, right-to-left associative, or non-associative. A left-to-right associative operator is one in which the leftmost arguments are grouped first. A right-to-left associative operator is one in which the rightmost arguments are grouped first. If an operator is non-associative, it means that operators with the same precedence as the non-associative operator cannot appear in the same expression without the use of parentheses.
Parentheses are often used in situations to make explicit or to clarify the intended interpretation of terms even where the precedence and associativity of operators is unambiguous.
The operator's position and associativity are expressed using Prolog atoms. These atoms are made up of the letters x, f, and y. The letter f stands for the operator; the letters x and y stand for the operands and indicate the associativity and the position of the operands in relation to the operator. An x indicates that an expression in that position must have a precedence lower than the operator's precedence. A y indicates that an expression in that position can have a precedence either equal to or higher than the operator's precedence.
The following is a complete list of the atoms used for operator associativity.
atom | meaning |
---|---|
fx | Prefix, non-associative |
fy | Prefix, left-to-right |
xfx | Infix, non-associative |
xfy | Infix, right-to-left |
yfx | Infix, left-to-right |
xf | Postfix, non-associative |
yf | Postfix, right-to-left |
Operator predicates
op(+Precedence, +Associativity, +Operator)
You use the op predicate to define the precedence, position, and associativity of an operator. A Precedence of 0 disables the operator.
current_op(?Prec, -Assoc, -Op)
The current_op/3 predicate returns through backtracking the operator definitions that are currently defined in the runtime system.
reset_op
The reset_op/0 predicate returns the operator definitions to their default values as displayed in the table below.
Arity/Prolog32 built-in operators
Operator(s) | Precedence | Associativity |
---|---|---|
:- ?- | 1200 | fx |
:- := –> | 1200 | xfx |
define extrn mode module public visible | 1150 | fy |
; | 1100 | xfy |
, | 1000 | xfy |
case | 900 | fx |
not \+ nospy spy | 900 | fy |
-> & | 800 | xfy |
is @>= @> @=< @< \== \= == =.. | 700 | xfx |
= | 700 | xfy |
or | 675 | yfx |
and | 670 | yfx |
\/ | 665 | yfx |
+/ | 660 | yfx |
/\ | 655 | yfx |
=:= =\= | 650 | xfx |
< =< > >= | 600 | xfx |
<< >> | 550 | yfx |
+ - | 500 | fx |
: | 500 | xfy |
+ - | 500 | yfx |
* / mod // | 400 | yfx |
* & \ | 300 | fy |
^ | 300 | xfy |
.. | 200 | yfx |