Next: Variable scoping, Previous: DCG-goals, Up: Semantics [Contents]
Syntactically, an expression is just a term. Semantically, an expression is a variable, a literal, a functor expression, or a special expression. A special expression is a conditional expression, a unification expression, an explicit type qualification, a type conversion expression, a lambda expression, an apply expression, or a field access expression. Note that many terms are interpreted as expressions by Mercury in the same way as in Prolog. Special expressions, however, extend the functionality of Prolog. Both special and non-special expressions are covered in this section.
A literal is an integer, a float, a string, or an implementation-defined literal (note that character literals are a kind of atom; see below).
Implementation-defined literals are symbolic names whose value represents a property of the compilation environment or the context in which it appears. The implementation replaces these symbolic names with actual constants during compilation. Implementation-defined literals can only appear within clauses. The following must be supported by all Mercury implementations:
A string that gives the name of the file that contains the module being compiled. If the name of the file cannot be determined, then it is replaced by an arbitrary string.
The line number (integer) of the goal in which the literal appears, or -1 if it cannot be determined.
A string representation of the fully qualified module name.
A string containing the fully qualified predicate or function name and arity.
The Melbourne Mercury implementation additionally supports the following extension:
The grade (string) in which the module is compiled.
A functor expression is an atom, which is just a name, or a compound expression, which is a compound term that does not match the form of a special expression, and whose arguments are expressions. If a functor expression is not a character literal, its principal functor must be the name of a visible function, predicate, or data constructor (except for field specifiers, for which the corresponding field access function must be visible; see below).
Character literals in Mercury are just atoms with a single character,
possibly quoted.
Since they sometimes require quotes
and sometimes require parentheses,
for code consistency we recommend
writing all character literals with quotes and
(except where used as arguments)
parentheses.
For example, Char = ('+') ; Char = ('''')
.
Special expressions (not including field access expressions, which are covered below) take one of the following forms.
if Goal then ThenExpr else ElseExpr
Goal -> ThenExpr ; ElseExpr
A conditional expression. Goal is a goal; ThenExpr and ElseExpr are both expressions. The two forms are equivalent. The meaning of a conditional expression is that if Goal is true it is equivalent to ThenExpr, otherwise it is equivalent to ElseExpr.
If Goal takes the form some [X, Y, Z] …
then the scope of X, Y, and Z includes ThenExpr.
See the related discussion regarding if-then-else goals.
X @ Y
A unification expression. X and Y are both expressions. The meaning of a unification expression is that the arguments are unified, and the expression is equivalent to the unified value.
The strict sequential operational semantics (see Formal semantics)
of an expression X @ Y
is that the expression is replaced by a fresh variable Z
,
and immediately after Z
is evaluated,
the conjunction Z = X, Z = Y
is evaluated.
For example
p(X @ f(_, _), X).
is equivalent to
p(Z, X) :- Z = X, Z = f(_, _).
Unification expressions are particularly useful when writing switches (see Determinism checking and inference), as the arguments of a unification expression are examined when checking for switches. The arguments of an equivalent user-defined function would not be.
Expr : Type
An explicit type qualification. Expr must be a valid expression, and Type must be a valid type (see Types). These expressions are occasionally useful to resolve ambiguities that can arise from overloading or polymorphic types.
An explicit type qualification constrains the specified expression to have the specified type. Apart from that, the explicit type qualification is equivalent to Expr.
Currently we also support
Expr `with_type` Type
as an alternative syntax for explicit type qualification.
coerce(Expr)
A type conversion expression. Expr must be a valid expression. See Type conversions.
pred(Arg1::Mode1, Arg2::Mode2, …) is Det :- Goal
pred(Arg1::Mode1, Arg2::Mode2, …, DCGMode0, DCGMode1) is Det --> DCGGoal
func(Arg1::Mode1, Arg2::Mode2, …) = (Result::Mode) is Det :- Goal
func(Arg1, Arg2, …) = (Result) is Det :- Goal
func(Arg1, Arg2, …) = Result :- Goal
A lambda expression. Arg1, Arg2, … are zero or more expressions, Result is an expression, Goal is a goal, DCGGoal is a DCG-goal, Mode1, Mode2, …, DCGMode0, and DCGMode1 are modes (see Modes), and Det is a determinism category (see Determinism). The ‘:- Goal’ part is optional; if it is not specified, then ‘:- true’ is assumed.
A lambda expression denotes a higher-order predicate or function term whose value is the predicate or function of the specified arguments determined by the specified goal. See Higher-order.
A lambda expression introduces a new scope: any variables occurring in the arguments Arg1, Arg2, … are locally quantified, i.e. they are distinct from other variables with the same name that occur outside of the lambda expression. For variables which occur in Result or Goal, but not in the arguments, the usual Mercury rules for implicit quantification apply (see Implicit quantification).
The form of lambda expression using ‘-->’ as its top level functor is a syntactic abbreviation. It is equivalent to
pred(Var1::Mode1, Var2::Mode2, …, DCGVar0::DCGMode0, DCGVar1::DCGMode1) is Det :- Goal
where DCGVar0
and DCGVar1
are fresh variables,
and Goal
is transform(DCGVar0, DCGVar1, DCGGoal)
where transform
is the function specified in DCG-goals.
apply(Func, Arg1, Arg2, …, ArgN)
Func(Arg1, Arg2, …, ArgN)
An apply expression (i.e. a higher-order function call). N >= 0, Func is an expression of type ‘func(T1, T2, …, Tn) = T’, and Arg1, Arg2, …, ArgN are expressions of types ‘T1’, ‘T2’, …, ‘Tn’. The type of the apply expression is T. It denotes the result of applying the specified function to the specified arguments. See Higher-order.
Field access expressions provide a convenient way to select or update fields of data constructors, independent of the definition of the constructor. Field access expressions are transformed into sequences of calls to field selection or update functions (see Field access functions).
A field specifier is a functor expression.
A field list is a sequence of field specifiers
separated by ^
(circumflex).
E.g., ‘field’, ‘field1 ^ field2’
and ‘field1(A) ^ field2(B, C)’
are all valid field lists.
If the principal functor of a field specifier is field/N
,
there must be a visible selection function field/(N + 1)
.
If the field specifier occurs in a field update expression,
there must also be a visible update function
named 'field :='/(N + 2)
.
Field access expressions have one of the following forms. There are also DCG goals for field access (see DCG-goals), which provide similar functionality to field access expressions, except that they act on the DCG arguments of a DCG clause.
Expr ^ field_list
A field selection. For each field specifier in field_list, apply the corresponding selection function in turn.
Expr must be a valid expression. field_list must be a valid field list.
A field selection is transformed using the following rules:
transform(Expr ^ Field(Arg1, …)) = Field(Arg1, …, Expr). transform(Expr ^ Field(Arg1, …) ^ Rest) = transform(Field(Arg1, …, Expr) ^ Rest).
Examples:
Expr ^ field
is equivalent to field(Expr)
.
Expr ^ field(Arg)
is equivalent to field(Arg, Expr)
.
Expr ^ field1(Arg1) ^ field2(Arg2, Arg3)
is equivalent
to field2(Arg2, Arg3, field1(Arg1, Expr))
.
Expr ^ field_list := FieldExpr
A field update, returning a copy of Expr with the value of the field specified by field_list replaced with FieldExpr.
Expr and FieldExpr must be valid expressions. field_list must be a valid field list.
A field update is transformed using the following rules:
transform(Expr ^ Field(Arg1, …) := FieldExpr) = 'Field :='(Arg1, …, Expr, FieldExpr)). transform(Expr0 ^ Field(Arg1, …) ^ Rest := FieldExpr) = Expr :- OldFieldValue = Field(Arg1, …, Expr0), NewFieldValue = transform(OldFieldValue ^ Rest := FieldExpr), Expr = 'Field :='(Arg1, …, Expr0, NewFieldValue).
Examples:
Expr ^ field := FieldExpr
is equivalent to 'field :='(Expr, FieldExpr)
.
Expr ^ field(Arg) := FieldExpr
is equivalent to 'field :='(Arg, Expr, FieldExpr)
.
Expr ^ field1(Arg1) ^ field2(Arg2) := FieldExpr
is equivalent to the code
OldField1 = field1(Arg1, Expr), NewField1 = 'field2 :='(Arg2, OldField1, FieldExpr), Result = 'field1 :='(Arg1, Expr, NewField1)
Next: Variable scoping, Previous: DCG-goals, Up: Semantics [Contents]