Next: , Previous: , Up: Syntax   [Contents]


2.2 Terms

Terms are the basic construct used by most syntactic forms in Mercury: declarations, clauses, and their sub-components, all adhere to the syntax rules for terms. Thus, the set of syntactically valid declarations is a subset of the set of syntactically valid terms, and likewise for the set of syntactically valid clauses, etc.

The term syntax is summarized by the following rules. (All of this information can be found in the descriptions below the rules.)

term = core-term | special-term

core-term = variable | constant | functor-term

constant = integer | float | string | implementation-defined-literal

functor-term = name | name open-ct functor-args close

functor-args = functor-arg | functor-arg,functor-args

functor-arg = arg | arg::arg

args = arg | arg,args

arg = term, where the term is not an operator term with priority >= 1000

special-term = operator-term | list-term | tuple-term | apply-term | paren-term

operator-term = term operator term | operator term | operator term term,
    where the term is constructed according to the requirements of the operator
    (see Builtin operators)

list-term = ‘[list-body? ‘]list-body = arg | arg,list-body | arg ht-sep term

tuple-term = ‘{args? ‘}apply-term = term open-ct args close,
    where the term is not a name or operator term

paren-term = ‘(term)

Valid terms can be described in the following way.

term

A term is either a core term or a special term. A term normalization procedure, given below, translates terms that may contain special terms into terms that are only constructed from core terms; two terms are considered syntactically equivalent if they translate to the same term. Syntactically equivalent terms can be used interchangeably anywhere in a module (e.g. operator syntax can be used in declarations and clauses, in particular those that define an operator).

Note that there can be further equivalences in some contexts, e.g. an if-then-else can be written in either of two equivalent forms. Such equivalences will be covered in the relevant chapters.

core-term

A core term is a variable, a constant, or a functor-term.

constant

A constant is an integer, a float, a string, or an implementation-defined-literal.

functor-term

A functor term is either a name or a compound term. A compound term is a name followed without any intervening whitespace by an open parenthesis (i.e. an open-ct token), then followed by a functor argument list and a close parenthesis. E.g., ‘foo(X,Y)’ is a compound term, whereas ‘foo (X,Y)’ and ‘foo()’ are not (the first because the space after ‘foo’ is not allowed, the second because the parentheses must be omitted if there are no arguments).

The principal functor of a functor term is the name and arity of the term, separated by a slash, where the arity is the number of arguments (or zero if there are no arguments). For example, the principal functor of ‘foo(bar,baz)’ is ‘foo/2’, while the principal functor of ‘foo’ is ‘foo/0’. The principal functor of a special term is determined after normalization.

Note that the word “functor” has a number of definitions, but in Mercury it just means a symbol to which arguments can be applied, and which has no intrinsic meaning of its own. It is a syntactic concept that applies to all functor terms. In specific contexts functors may also be referred to as type constructors, data constructors (or just constructors), predicates, functions, etc. The principal functor may also be referred to as the “top-level constructor”.

functor-args

A functor argument list is a sequence of one or more functor arguments, separated by commas.

functor-arg

A functor argument is either a single argument or two arguments separated by a ‘::’ operator (the latter form is for mode qualifiers; see Different clauses for different modes).

args

An argument list is a sequence of one or more arguments, separated by commas.

arg

An argument is any term, except operator terms where the operator does not bind more tightly than comma (i.e., where the priority is greater than or equal to 1000). In such a situation parentheses can be used, e.g. ‘f((A,B))’ is a compound term with one argument that is a parenthesized operator term, whereas ‘f(A,B)’ is a compound term with two arguments (and no operators).

special-term

A special term is an operator term, a list term, a tuple term, an apply term, or a parenthesized term. The term normalization procedure, below, defines how these terms are represented internally as core terms.

operator-term

An operator term is a term constructed using an operator, which complies with the rules for constructing terms using that operator (see Builtin operators). Operator terms can be infix, such as ‘A + B’, unary-prefix, such as ‘not P’, or binary-prefix, such as ‘some Vars Goal’.

list-term

A list term is an open square bracket (an open-list token), followed by an optional list body, followed by a close square bracket (a close-list token). If the list body is omitted it is the empty list. If present, the list body is an argument list, optionally followed by a vertical bar (a ht-sep token) followed by a term. E.g., ‘[]’, ‘[X]’, and ‘[1, 2 | Tail]’ are all valid list terms. The argument list gives the elements appearing at the front of the list. The term following the vertical bar, if present, gives the tail of the list (i.e. the remaining elements), otherwise the tail is the empty list. Note that technically the tail does not have to be a list for this to be syntactically valid, although generally it would need to be in order to be type correct.

tuple-term

A tuple term is an open curly bracket (an open-curly token), followed by an optional argument list, followed by a close curly bracket (a close-curly token). If the argument list is omitted it is the empty tuple, otherwise the arguments give the components of the tuple. E.g., {} and {1,'2',"three"} are valid tuple terms.

apply-term

An apply-term is a “closure” term, which can be any term other than a name or an operator term, followed without any intervening whitespace by an open parenthesis (an open-ct token), an argument list, and a close parenthesis (a close token). E.g., ‘A(B,C)’ is a valid apply-term. An apply-term represents the closure (i.e. a higher-order value) applied to the arguments.

Note that although the closure term cannot be an operator term, it can be a parenthesized term. Thus ‘(Var ^ foo)(Arg1, Arg2)’ is a valid apply-term, whereas ‘Var ^ foo(Arg1, Arg2)’ is not (it is an operator term whose second argument is a compound term).

paren-term

A parenthesized term is just a term enclosed in parentheses. E.g., (X-Y) is a valid parenthesized term.

The term normalization procedure works by rewriting special terms that occur anywhere within a term (i.e. at the top level or as some descendant) according to a set of rewriting rules, and repeating until no rules can be further applied. The rules are as follows.

term1 `name` term2name(term1, term2)
term1 `var` term2var(term1, term2)
term1 operator term2 → 'operator'(term1, term2)
operator term → 'operator'(term)
operator term1 term2 → 'operator'(term1, term2)

[ ] → '[]'
[ arg ] → '[|]'(arg, '[]')
[ arg , list-body ] → '[|]'(arg, [list-body])
[ arg | term ] → '[|]'(arg, term)

{ } → '{}'
{ args } → '{}'(args)

term(args) → ''(term, args)

( term ) → term

For example, the following terms are all syntactically equivalent (i.e. they are equal after normalization). The last is constructed from core terms; the others all normalize to this term. From the last one it can be seen that the principal functor of all of them is '[|]'/2.

[1, 2, 3]
[1, 2, 3 | []]
[1, 2 | [3]]
[1 | [2, 3]]
'[|]'(1, '[|]'(2, '[|]'(3, '[]')))

Similarly, the following terms are all syntactically equivalent. The principal functor in this case is '+'/2.

A * B + C
(A * B) + C
'+'('*'(A, B), C)

Next: , Previous: , Up: Syntax   [Contents]