mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-14 13:23:53 +00:00
Estimated hours taken: 0.25 doc/reference_manual.texi: Fix an inconsistency in the manual, which was using `multidet' and `multi' inconsistently: s/multidet/multi/g library/string.m: Use `multi' rather than `multidet', to match the language reference manual.
6745 lines
248 KiB
Plaintext
6745 lines
248 KiB
Plaintext
\input texinfo
|
|
@setfilename mercury_ref.info
|
|
@settitle The Mercury Language Reference Manual
|
|
|
|
@c --- texi2html doesn't support the @dir commands yet
|
|
@c @dircategory The Mercury Programming Language
|
|
@c @direntry
|
|
@c * Mercury Language: (mercury_ref). The Mercury Language Reference Manual.
|
|
@c @end direntry
|
|
|
|
@c Uncomment the line below to enable documentation of the Aditi interface.
|
|
@c @set aditi
|
|
|
|
@c @smallbook
|
|
@c @cropmarks
|
|
@finalout
|
|
@setchapternewpage off
|
|
@ifinfo
|
|
This file documents the Mercury programming language.
|
|
|
|
Copyright (C) 1995-2000 The University of Melbourne.
|
|
|
|
Permission is granted to make and distribute verbatim copies of
|
|
this manual provided the copyright notice and this permission notice
|
|
are preserved on all copies.
|
|
|
|
@ignore
|
|
Permission is granted to process this file through Tex and print the
|
|
results, provided the printed document carries copying permission
|
|
notice identical to this one except for the removal of this paragraph
|
|
(this paragraph not being relevant to the printed manual).
|
|
|
|
@end ignore
|
|
Permission is granted to copy and distribute modified versions of this
|
|
manual under the conditions for verbatim copying, provided also that
|
|
the entire resulting derived work is distributed under the terms of a
|
|
permission notice identical to this one.
|
|
|
|
Permission is granted to copy and distribute translations of this manual
|
|
into another language, under the above conditions for modified versions.
|
|
@end ifinfo
|
|
|
|
@titlepage
|
|
@title The Mercury Language Reference Manual
|
|
@author Fergus Henderson
|
|
@author Thomas Conway
|
|
@author Zoltan Somogyi
|
|
@author David Jeffery
|
|
@author Peter Schachte
|
|
@author Simon Taylor
|
|
@author Chris Speirs
|
|
@page
|
|
@vskip 0pt plus 1filll
|
|
Copyright @copyright{} 1995-2000 The University of Melbourne.
|
|
|
|
Permission is granted to make and distribute verbatim copies of
|
|
this manual provided the copyright notice and this permission notice
|
|
are preserved on all copies.
|
|
|
|
Permission is granted to copy and distribute modified versions of this
|
|
manual under the conditions for verbatim copying, provided also that
|
|
the entire resulting derived work is distributed under the terms of a
|
|
permission notice identical to this one.
|
|
|
|
Permission is granted to copy and distribute translations of this manual
|
|
into another language, under the above conditions for modified versions.
|
|
@end titlepage
|
|
@page
|
|
@c ---------------------------------------------------------------------------
|
|
|
|
@ifinfo
|
|
@node Top,,, (mercury)
|
|
@top
|
|
@end ifinfo
|
|
@c XXX Move to after Determinism
|
|
@c * Assertions:: Assertion declarations allow you to declare laws
|
|
@c that hold.
|
|
@menu
|
|
* Introduction:: A brief introduction to Mercury.
|
|
* Syntax:: Mercury's syntax is similar to ISO Prolog.
|
|
* Types:: Mercury has a strong parametric polymorphic type system.
|
|
* Modes:: Modes allow you to specify the direction of data flow.
|
|
* Unique modes:: Unique modes allow you to specify when there is only one
|
|
reference to a particular value, so the compiler can
|
|
safely use destructive update to modify that value.
|
|
* Determinism:: Determinism declarations let you specify that a predicate
|
|
should never fail or should never succeed more than once.
|
|
* Equality preds:: User-defined types can have user-defined equality
|
|
predicates.
|
|
* Higher-order:: Mercury supports higher-order predicates and functions,
|
|
with closures, lambda expressions, and currying.
|
|
* Modules:: Modules allow you to divide a program into smaller parts.
|
|
* Type classes:: Constrained polymorphism.
|
|
* Existential types:: Support for data abstraction and heterogeneous
|
|
collections.
|
|
* Semantics:: Declarative and operational semantics of Mercury
|
|
programs.
|
|
* C interface:: The C interface allows C code to be called
|
|
from Mercury code, and vice versa.
|
|
* Impurity:: Users can write impure Mercury code.
|
|
* Pragmas:: Various compiler directives, used for example to
|
|
control optimization.
|
|
* Implementation-dependent extensions::
|
|
The University of Melbourne Mercury implementation
|
|
supports several extensions to the Mercury language.
|
|
* Bibliography:: References for further reading.
|
|
@end menu
|
|
|
|
@node Introduction
|
|
@chapter Introduction
|
|
|
|
Mercury is a new general-purpose programming language, designed
|
|
and implemented by a small group of researchers at the University
|
|
of Melbourne, Australia. Mercury is based on the paradigm of
|
|
purely declarative programming, and was designed to be
|
|
useful for the development of large and robust ``real-world'' applications.
|
|
It improves on existing logic programming languages by providing
|
|
increased productivity, reliability and efficiency, and by avoiding the
|
|
need for non-logical program constructs. Mercury provides the
|
|
traditional logic programming syntax, but also allows the
|
|
syntactic convenience of user-defined functions, smoothly integrating
|
|
logic and functional programming into a single paradigm.
|
|
|
|
Mercury requires programmers to supply
|
|
type, mode and determinism declarations for the predicates
|
|
and functions they write.
|
|
The compiler checks these declarations,
|
|
and rejects the program if it cannot prove
|
|
that every predicate or function satisfies its declarations.
|
|
This improves reliability,
|
|
since many kinds of errors simply cannot happen
|
|
in successfully compiled Mercury programs.
|
|
It also improves productivity,
|
|
since the compiler pinpoints many errors
|
|
that would otherwise require manual debugging to locate.
|
|
The fact that declarations are checked by the compiler
|
|
makes them much more useful than comments
|
|
to anyone who has to maintain the program.
|
|
The compiler also exploits the guaranteed correctness of the declarations
|
|
for significantly improving the efficiency of the code it generates.
|
|
|
|
To facilitate programming-in-the-large, to allow separate compilation,
|
|
and to support encapsulation, Mercury has a simple module system.
|
|
Mercury's standard library has a variety of pre-defined modules
|
|
for common programming tasks --- see the Mercury Library Reference Manual.
|
|
|
|
@node Syntax
|
|
@chapter Syntax
|
|
|
|
@menu
|
|
* Syntax Overview::
|
|
* Tokens::
|
|
* Terms::
|
|
* Items::
|
|
* Declarations::
|
|
* Facts::
|
|
* Rules::
|
|
* Goals::
|
|
* DCG-rules::
|
|
* DCG-goals::
|
|
* Data-terms::
|
|
* Implicit quantification::
|
|
* Elimination of double negation::
|
|
@end menu
|
|
|
|
@node Syntax Overview
|
|
@section Syntax overview
|
|
|
|
Mercury's syntax is similar to the syntax of Prolog, with some
|
|
additional declarations for types, modes, determinism, the module system,
|
|
and pragmas, and with the distinction that function symbols may stand also
|
|
for invocations of user-defined functions as well as for data constructors.
|
|
|
|
A Mercury program consists of a set of modules. Each module is a file
|
|
containing a sequence of items (declarations and clauses). Each item
|
|
is a term followed by a period. Each term is composed of a sequence
|
|
of tokens, and each token is composed of a sequence of characters.
|
|
Like Prolog, Mercury has the Definite Clause Grammar (DCG) notation
|
|
for clauses.
|
|
|
|
@node Tokens
|
|
@section Tokens
|
|
|
|
Tokens in Mercury are the same as in ISO Prolog.
|
|
The only differences are the @samp{#@var{line}} token, which
|
|
is used as a line number directive (see below) and the
|
|
backquote (@samp{`}) token.
|
|
|
|
The different tokens are as follows. Tokens may be separated by
|
|
whitespace or line number directives.
|
|
|
|
@table @emph
|
|
|
|
@item line number directive
|
|
A line number directive consists of the character @samp{#},
|
|
a positive integer specifying the line number, and then a newline.
|
|
A @samp{#@var{line}} directive's only role is to
|
|
specifying the line number; it is otherwise ignored by the syntax.
|
|
Line number directives may occur anywhere a token may occur.
|
|
They are used in conjunction with the @samp{pragma source_file}
|
|
declaration to indicate that the Mercury code following was
|
|
generated by another tool; they serve to associate each line
|
|
in the Mercury code with the source file name and line number of
|
|
the original source from which the Mercury code was derived,
|
|
so that the Mercury compiler can issue more informative error
|
|
messages using the original source code locations.
|
|
A @samp{#@var{line}} directive specifies the line number
|
|
for the immediately following line. Line numbers for lines
|
|
after that are incremented as usual, so the second line
|
|
after a @samp{#100} directive would be considered to be line
|
|
number 101.
|
|
|
|
@item string
|
|
A string is a sequence of characters enclosed in double quotes (@code{"}).
|
|
Within a string, two adjacent double quotes stand for a single double quote.
|
|
For example, the string @samp{ """" } is a string of length one, containing
|
|
a single double quote: the outermost pair of double quotes encloses the
|
|
string, and the innermost pair stand for a single double quote.
|
|
Strings may also contain backslash escapes. @samp{\a} stands for ``alert''
|
|
(a beep character), @samp{\b} for backspace, @samp{\r} for carriage-return,
|
|
@samp{\f} for form-feed, @samp{\t} for tab, @samp{\n} for newline,
|
|
@samp{\v} for vertical-tab. An escaped backslash, single-quote, or
|
|
double-quote stands for itself. The sequence @samp{\x} introduces
|
|
a hexadecimal escape; it must be followed by a sequence of hexadecimal
|
|
digits and then a closing backslash. It is replaced
|
|
with the character whose character code is identified by the hexadecimal
|
|
number. Similarly, a backslash followed by an octal digit is the
|
|
beginning of an octal escape; as with hexadecimal escapes, the sequence
|
|
of octal digits must be terminated with a closing backslash.
|
|
A backslash followed immediately by a newline is deleted; thus an
|
|
escaped newline can be used to continue a string over more than one
|
|
source line. (String literals may also contain embedded newlines.)
|
|
|
|
@item name
|
|
A name is either an unquoted name or a quoted name.
|
|
An unquoted name is a lowercase letter followed by zero or more letters,
|
|
underscores, and digits. A quoted name is any sequence of zero or more
|
|
characters enclosed in single quotes (@code{'}).
|
|
Within a quoted name, two adjacent single quotes stand for a single
|
|
single quote. Quoted names can also contain
|
|
backslash escapes of the same form as for strings.
|
|
|
|
@item variable
|
|
A variable is an uppercase letter or underscore followed by zero or
|
|
more letters, underscores, and digits.
|
|
A variable token consisting of single underscore is treated
|
|
specially: each instance of @samp{_} denotes a distinct variable.
|
|
(In addition, variables starting with an underscore are presumed to be
|
|
``don't-care'' variables; the compiler will issue a warning if a
|
|
variable that does not start with an underscore occurs only once, or if
|
|
a variable starting with an underscore occurs more than once in the
|
|
same scope.)
|
|
|
|
@item integer
|
|
An integer is either a decimal, binary, octal, hexadecimal, or character-code
|
|
literal.
|
|
A decimal literal is any sequence of decimal digits.
|
|
A binary literal is @samp{0b} followed by any sequence of binary digits.
|
|
An octal literal is @samp{0o} followed by any sequence of octal digits.
|
|
A hexadecimal literal is @samp{0x} followed by any sequence of hexadecimal
|
|
digits.
|
|
A character-code literal is @samp{0'} followed by any single character.
|
|
|
|
@item float
|
|
A floating point literal consists of a sequence of decimal digits,
|
|
a decimal point and a sequence of digits (the fraction part), and
|
|
the letter @samp{E} and another sequence of decimal digits (the exponent).
|
|
The fraction part or the exponent (but not both) may be omitted.
|
|
|
|
@item open_ct
|
|
A left parenthesis, @samp{(}, that is not preceded by whitespace.
|
|
|
|
@item open
|
|
A left parenthesis, @samp{(}, that is preceded by whitespace.
|
|
|
|
@item close
|
|
A right parenthesis, @samp{)}.
|
|
|
|
@item open_list
|
|
A left square bracket, @samp{[}.
|
|
|
|
@item close_list
|
|
A right square bracket, @samp{]}.
|
|
|
|
@item open_curly
|
|
A left curly bracket, @samp{@{}.
|
|
|
|
@item close_curly
|
|
A right curly bracket, @samp{@}}.
|
|
|
|
@item ht_sep
|
|
A ``head-tail separator'', i.e. a vertical bar, @samp{|}.
|
|
|
|
@item comma
|
|
A comma, @samp{,}.
|
|
|
|
@item end
|
|
A full stop (period), @samp{.}.
|
|
|
|
@item eof
|
|
The end of file.
|
|
|
|
@end table
|
|
|
|
@node Terms
|
|
@section Terms
|
|
|
|
Syntactically, terms in Mercury are exactly the same as in ISO Prolog,
|
|
except that as extensions we permit higher-order terms and the
|
|
introduction of infix operators by the use of grave accents (backquotes),
|
|
as described below.
|
|
However, the meaning of some terms in Mercury is different to that
|
|
in Prolog. @xref{Data-terms}.
|
|
|
|
A term is either a variable or a functor.
|
|
|
|
A functor is an integer, a float, a string, a name, a compound term,
|
|
or a higher-order term.
|
|
|
|
A compound term is a simple compound term, an operator term,
|
|
or a parenthesized term.
|
|
|
|
A simple compound term is a name followed without any intervening
|
|
whitespace by an open parenthesis (i.e. an open_ct token),
|
|
a sequence of argument terms separated by commas, and a close
|
|
parenthesis.
|
|
|
|
An operator term is a term specified using operator notation, as in Prolog.
|
|
Operators can also be formed by enclosing a variable or name between grave
|
|
accents (backquotes). Any variable or name may
|
|
be used as an operator in this way. If @var{fun} is a variable or name,
|
|
then a term of the form @code{@var{X} `@var{fun}` @var{Y}} is equivalent to
|
|
@code{@var{fun}(@var{X}, @var{Y})}. The operator is treated as having the
|
|
highest precedence possible and is left associative.
|
|
|
|
A parenthesized term is just an open parenthesis
|
|
followed by a term and a close parenthesis.
|
|
|
|
A higher-order 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 (i.e. an open_ct token),
|
|
a sequence of argument terms separated by commas, and a close
|
|
parenthesis. A higher-order term is equivalent to a simple compound term
|
|
whose functor is the empty name, and whose arguments are the
|
|
closure term followed by the argument terms of the higher-order term.
|
|
That is, a term such as @code{Term(Arg1, @dots{}, ArgN)} is
|
|
parsed as @code{''(Term, Arg1, @dots{}, ArgN)}.
|
|
Note that the closure term can be a parenthesized
|
|
term; for example, @code{(Term^FieldName)(Arg1, Arg2)}
|
|
is a higher-order term, and so it gets parsed as
|
|
if it were @code{''((Term^FieldName), Arg1, Arg2)}.
|
|
|
|
@node Items
|
|
@section Items
|
|
|
|
Each item in a Mercury module is either a declaration or a clause.
|
|
If the top-level functor of the term is @samp{:-/1},
|
|
the item is a declaration, otherwise it is a clause.
|
|
There are three types of clauses.
|
|
If the top-level functor of the item is @samp{:-/2}, the item is a rule.
|
|
If the top-level functor is @samp{-->/2}, the item is a DCG rule.
|
|
Otherwise, the item is a fact.
|
|
There are two types of rules and facts.
|
|
If the top-level functor of the head of a rule is @samp{=/2}, the rule
|
|
is a function rule, otherwise it is a predicate rule.
|
|
If the top-level functor of the head of a fact is @samp{=/2}, the fact
|
|
is a function fact, otherwise it is a predicate fact.
|
|
|
|
@node Declarations
|
|
@section Declarations
|
|
|
|
The allowed declarations are:
|
|
|
|
@example
|
|
:- type
|
|
:- pred
|
|
:- func
|
|
:- inst
|
|
:- mode
|
|
:- typeclass
|
|
:- instance
|
|
:- pragma
|
|
:- promise
|
|
:- module
|
|
:- interface
|
|
:- implementation
|
|
:- import_module
|
|
:- use_module
|
|
:- include_module
|
|
:- end_module
|
|
@end example
|
|
|
|
The @samp{type}, @samp{pred} and @samp{func} declarations are used for the
|
|
type system,
|
|
the @samp{inst} and @samp{mode} declarations are for the mode system,
|
|
the @samp{pragma} declarations are for the C interface, and for
|
|
compiler hints about inlining, and the remainder are for the module system.
|
|
They are described in more detail in their respective chapters.
|
|
|
|
(The current implementation also allows @samp{when/2} declarations,
|
|
but ignores them.
|
|
This helps when one wants to write a program
|
|
that is both a Mercury program and an NU-Prolog program.)
|
|
|
|
@node Facts
|
|
@section Facts
|
|
|
|
A function fact is an item of the form @samp{@var{Head} = @var{Result}}.
|
|
A predicate fact is an item of the form @samp{@var{Head}},
|
|
where the top-level functor of @var{Head}
|
|
is not @code{:-/1}, @code{:-/2}, @code{-->/2}, or @code{=/2}.
|
|
In both cases, the @var{Head} term must not be a variable.
|
|
The top-level functor of the @var{Head}
|
|
determines which predicate or function the fact belongs to;
|
|
the predicate or function must have been declared
|
|
in a preceding @samp{pred} or @samp{func} declaration in this module.
|
|
The arguments of the head must be valid data-terms.
|
|
A fact is equivalent to a rule whose body is @samp{true}.
|
|
|
|
@node Rules
|
|
@section Rules
|
|
|
|
A function rule is an item of the form
|
|
@samp{@var{Head} = @var{Result} :- @var{Body}}.
|
|
A predicate rule is an item of the form
|
|
@samp{@var{Head} :- @var{Body}} where the top-level
|
|
functor of @samp{Head} is not @code{=/2}.
|
|
In both cases, the @var{Head} term must not be a variable.
|
|
The top-level functor of the @var{Head} determines which predicate or
|
|
function the clause belongs to; the predicate or function must have
|
|
been declared in a preceding @samp{pred} or @samp{func} declaration in
|
|
this module.
|
|
The arguments of the head must be valid data-terms.
|
|
The @var{Body} must be a valid goal.
|
|
|
|
@node Goals
|
|
@section Goals
|
|
|
|
A goal is a term of one of the following forms:
|
|
|
|
@table @asis
|
|
@item @code{some @var{Vars} @var{Goal}}
|
|
An existential quantification.
|
|
@var{Vars} must be a list of variables.
|
|
@var{Goal} must be a valid goal.
|
|
|
|
Each existential quantification introduces a new scope.
|
|
The variables in @var{Vars} are local to the goal @var{Goal}:
|
|
for each variable named in @var{Vars},
|
|
any occurrences of variables with that name in @var{Goal}
|
|
are considered to name a different variable than any
|
|
variables with the same name that occur outside of the
|
|
existential quantification.
|
|
|
|
Operationally, existential quantification has no effect,
|
|
so apart from its effect on variable scoping,
|
|
@samp{some @var{Vars} @var{Goal}} is the
|
|
same as @samp{@var{Goal}}.
|
|
|
|
Mercury's rules for implicit quantification (@pxref{Implicit quantification})
|
|
mean that variables are often implicitly existentially quantified.
|
|
There is usually no need to write existential quantifiers explicitly.
|
|
|
|
@item @code{all @var{Vars} @var{Goal}}
|
|
A universal quantification.
|
|
@var{Vars} must be a list of variables.
|
|
@var{Goal} must be a valid goal.
|
|
This is an abbreviation for @samp{not (some @var{Vars} not @var{Goal})}.
|
|
|
|
@item @code{@var{Goal1}, @var{Goal2}}
|
|
A conjunction.
|
|
@var{Goal1} and @var{Goal2} must be valid goals.
|
|
|
|
@item @code{@var{Goal1} ; @var{Goal2}}
|
|
where @var{Goal1} is not of the form @samp{Goal1a -> Goal1b}:
|
|
a disjunction.
|
|
@var{Goal1} and @var{Goal2} must be valid goals.
|
|
|
|
@item @code{true}
|
|
The empty conjunction.
|
|
Always succeeds.
|
|
|
|
@item @code{fail}
|
|
The empty disjunction.
|
|
Always fails.
|
|
|
|
@item @code{not @var{Goal}}
|
|
@itemx @code{\+ @var{Goal}}
|
|
A negation.
|
|
The two different syntaxes have identical semantics.
|
|
@var{Goal} must be a valid goal.
|
|
Both forms are equivalent to @samp{if @var{Goal} then fail else true}.
|
|
|
|
@item @code{@var{Goal1} => @var{Goal2}}
|
|
An implication.
|
|
This is an abbreviation for @samp{not (@var{Goal1}, not @var{Goal2})}.
|
|
|
|
@item @code{@var{Goal1} <= @var{Goal2}}
|
|
A reverse implication.
|
|
This is an abbreviation for @samp{not (@var{Goal2}, not @var{Goal1})}.
|
|
|
|
@item @code{@var{Goal1} <=> @var{Goal2}}
|
|
A logical equivalence.
|
|
This is an abbreviation for
|
|
@samp{(@var{Goal1} => @var{Goal2}), (@var{Goal1} <= @var{Goal2}}).
|
|
|
|
@item @code{if @var{CondGoal} then @var{ThenGoal} else @var{ElseGoal}}
|
|
@itemx @code{@var{CondGoal} -> @var{ThenGoal} ; @var{ElseGoal}}
|
|
An if-then-else.
|
|
The two different syntaxes have identical semantics.
|
|
@var{CondGoal}, @var{ThenGoal}, and @var{ElseGoal} must be valid goals.
|
|
Note that the ``else'' part is @emph{not} optional.
|
|
|
|
The declarative semantics of an if-then-else is given by
|
|
@code{( @var{CondGoal}, @var{ThenGoal} ; not(@var{CondGoal}), @var{ElseGoal})},
|
|
but the operational semantics are different, and it is treated
|
|
differently for the purposes of determinism inference (@pxref{Determinism}).
|
|
Operationally, it executes the @var{CondGoal}, and if that succeeds, then
|
|
execution continues with the @var{ThenGoal}; otherwise, i.e. if @var{CondGoal}
|
|
fails, it executes the @var{ElseGoal}. Note that @var{CondGoal} can be
|
|
nondeterministic -- unlike Prolog, Mercury's if-then-else does not commit
|
|
to the first solution of the condition if the condition succeeds.
|
|
|
|
@item @code{@var{Term1} = @var{Term2}}
|
|
A unification.
|
|
@var{Term1} and @var{Term2} must be valid data-terms.
|
|
|
|
@item @code{@var{Term1} \= @var{Term2}}
|
|
An inequality.
|
|
@var{Term1} and @var{Term2} must be valid data-terms.
|
|
This is an abbreviation for @samp{not (@var{Term1} = @var{Term2})}.
|
|
|
|
@item @code{call(Closure)}
|
|
@itemx @code{call(Closure1, Arg1)}
|
|
@itemx @code{call(Closure2, Arg1, Arg2)}
|
|
@itemx @code{call(Closure3, Arg1, Arg2, Arg3)}
|
|
@itemx @dots{}
|
|
A higher-order predicate call.
|
|
The closure and arguments must be valid data-terms.
|
|
@samp{call(Closure)} just calls
|
|
the specified closure. The other forms append the specified
|
|
arguments onto the argument list of the closure before calling it.
|
|
@xref{Higher-order}.
|
|
|
|
@item @code{Var}
|
|
@itemx @code{Var(Arg1)}
|
|
@itemx @code{Var(Arg2)}
|
|
@itemx @code{Var(Arg2, Arg3)}
|
|
@itemx @dots{}
|
|
A higher-order predicate call.
|
|
@var{Var} must be a variable.
|
|
The semantics are exactly the same as for the corresponding
|
|
higher-order call using the @code{call/N} syntax, i.e.
|
|
@samp{call(Var)}, @samp{call(Var, Arg1)}, etc.
|
|
|
|
@ifset aditi
|
|
|
|
@item @code{aditi_bulk_delete(@dots{})}
|
|
@item @code{aditi_bulk_insert(@dots{})}
|
|
@item @code{aditi_delete(@dots{})}
|
|
@item @code{aditi_insert(@dots{})}
|
|
@item @code{aditi_modify(@dots{})}
|
|
These goal forms are used for the Aditi database interface.
|
|
@xref{Aditi update syntax}.
|
|
|
|
@end ifset
|
|
@c aditi
|
|
|
|
@item @code{@var{Call}}
|
|
Any goal which does not match any of the above forms
|
|
must be a predicate call.
|
|
The top-level functor of the term
|
|
determines the predicate called;
|
|
the predicate must be declared in a @code{pred} declaration
|
|
in the module or in the interface of an imported module.
|
|
The arguments must be valid data-terms.
|
|
|
|
@end table
|
|
|
|
@node DCG-rules
|
|
@section DCG-rules
|
|
|
|
DCG-rules in Mercury have identical syntax and semantics to
|
|
DCG-rules in Prolog.
|
|
|
|
A DCG-rule is an item of the form @samp{@var{Head} --> @var{Body}}.
|
|
The @var{Head} term must not be a variable.
|
|
A DCG-rule is an abbreviation for an ordinary rule with two
|
|
additional implicit arguments appended to the arguments of @var{Head}.
|
|
These arguments are fresh variables which we shall call
|
|
@var{V_in} and @var{V_out}.
|
|
The @var{Body} must be a valid DCG-goal,
|
|
and is an abbreviation for an ordinary goal.
|
|
The next section defines a mathematical function
|
|
@samp{DCG-transform(@var{V_in}, @var{V_out}, @var{DCG-goal})}
|
|
which specifies the semantics of how DCG goals are transformed into
|
|
ordinary goals. (The @samp{DCG-transform} function is purely for the
|
|
purposes of exposition, to define the semantics --- it is not part of the
|
|
language.)
|
|
|
|
@node DCG-goals
|
|
@section DCG-goals
|
|
|
|
A DCG-goal is a term of one of the following forms:
|
|
|
|
@table @code
|
|
@item some @var{Vars} @var{DCG-goal}
|
|
A DCG existential quantification.
|
|
@var{Vars} must be a list of variables.
|
|
@var{DCG-goal} must be a valid DCG-goal.
|
|
|
|
Semantics:
|
|
@example
|
|
transform(V_in, V_out, some Vars DCG_goal) =
|
|
some Vars transform(V_in, V_out, DCG_goal)
|
|
@end example
|
|
|
|
@item all @var{Vars} @var{DCG-goal}
|
|
A DCG universal quantification.
|
|
@var{Vars} must be a list of variables.
|
|
@var{DCG-goal} must be a valid DCG-goal.
|
|
|
|
Semantics:
|
|
@example
|
|
transform(V_in, V_out, all Vars DCG_goal) =
|
|
all Vars transform(V_in, V_out, DCG_goal)
|
|
@end example
|
|
|
|
@item @var{DCG-goal1}, @var{DCG-goal2}
|
|
A DCG sequence.
|
|
Intuitively, this means ``parse DCG-goal1 and then parse DCG-goal2''
|
|
or ``do DCG-goal1 and then do DCG-goal2''.
|
|
(Note that the only way this construct actually forces the desired sequencing
|
|
is by the modes of the implicit DCG arguments.)
|
|
@var{DCG-goal1} and @var{DCG-goal2} must be valid DCG-goals.
|
|
|
|
Semantics:
|
|
@c XXX too indented
|
|
@example
|
|
transform(V_in, V_out, (DCG-goal1, DCG-goal2)) =
|
|
(transform(V_in, V_new, DCG_goal1),
|
|
transform(V_new, V_out, DCG_goal2))
|
|
@end example
|
|
where V_new is a fresh variable.
|
|
|
|
@item @var{DCG-goal1} ; @var{DCG-goal2}
|
|
A disjunction. @var{DCG-goal1} and @var{DCG-goal2} must be valid goals.
|
|
@var{DCG-goal1} must not be of the form @samp{DCG-goal1a -> DCG-goal1b}.
|
|
(If it is, then the goal is an if-then-else, not a disjunction.)
|
|
|
|
Semantics:
|
|
@c XXX too indented
|
|
@example
|
|
transform(V_in, V_out, (DCG_goal1 ; DCG_goal2)) =
|
|
( transform(V_in, V_out, DCG_goal1)
|
|
; transform(V_in, V_out, DCG_goal2) )
|
|
@end example
|
|
|
|
@item @{ @var{Goal} @}
|
|
A brace-enclosed ordinary goal.
|
|
@var{Goal} must be a valid goal.
|
|
|
|
Semantics:
|
|
@example
|
|
transform(V_in, V_out, @{ Goal @}) = (Goal, V_out = V_in)
|
|
@end example
|
|
|
|
@itemx [@var{Term}, @dots{}]
|
|
A DCG input match.
|
|
Unifies the implicit DCG input variable V_in,
|
|
which must have type @samp{list(_)},
|
|
with a list whose initial elements are the terms specified
|
|
and whose tail is the implicit DCG output variable V_out.
|
|
The terms must be valid data-terms.
|
|
|
|
Semantics:
|
|
@example
|
|
transform(V_in, V_out, [Term1, @dots{}]) = (V_in = [Term, @dots{} | V_Out])
|
|
@end example
|
|
|
|
@item []
|
|
The null DCG goal (an empty DCG input match).
|
|
Equivalent to @samp{@{ true @}}.
|
|
|
|
Semantics:
|
|
@example
|
|
transform(V_in, V_out, []) = (V_out = V_in)
|
|
@end example
|
|
|
|
@item not @var{DCG-goal}
|
|
@itemx \+ @var{DCG-goal}
|
|
A DCG negation.
|
|
The two different syntaxes have identical semantics.
|
|
@var{Goal} must be a valid goal.
|
|
|
|
Semantics:
|
|
@example
|
|
transform(V_in, V_out, not DCG_goal) =
|
|
(not transform(V_in, V_new, DCG_goal), V_out = V_in)
|
|
@end example
|
|
where V_new is a fresh variable.
|
|
|
|
@item if @var{CondGoal} then @var{ThenGoal} else @var{ElseGoal}
|
|
@itemx @var{CondGoal} -> @var{ThenGoal} ; @var{ElseGoal}
|
|
A DCG if-then-else.
|
|
The two different syntaxes have identical semantics.
|
|
@var{CondGoal}, @var{ThenGoal}, and @var{ElseGoal} must be valid DCG-goals.
|
|
|
|
Semantics:
|
|
@example
|
|
transform(V_in, V_out, if CondGoal then ThenGoal else ElseGoal) =
|
|
if transform(V_in, V_cond, CondGoal) then
|
|
transform(V_cond, V_out, ThenGoal)
|
|
else
|
|
transform(V_in, V_out, ElseGoal)
|
|
@end example
|
|
|
|
@item =(@var{Term})
|
|
A DCG unification. Unifies @var{Term} with the implicit DCG argument.
|
|
@var{Term} must be a valid data-term.
|
|
|
|
Semantics:
|
|
@example
|
|
transform(V_in, V_out, =(Term)) = (Term = V_in, V_out = V_in)
|
|
@end example
|
|
|
|
@item :=(@var{Term})
|
|
A DCG output unification. Unifies @var{Term} with the implicit DCG output
|
|
argument, ignoring the input DCG argument.
|
|
@var{Term} must be a valid data-term.
|
|
|
|
Semantics:
|
|
@example
|
|
transform(V_in, V_out, :=(Term)) = (V_out = Term)
|
|
@end example
|
|
|
|
@item @var{Term} =^ @var{field1} ^ @dots{} ^ @var{fieldN}
|
|
A DCG field selection.
|
|
Unifies @var{Term} with the result of applying the functions
|
|
@var{field1} @dots{} @var{fieldN} to the implicit DCG argument.
|
|
@var{Term} must be a valid data-term.
|
|
For each @var{field} in @w{@var{field1} @dots{} @var{fieldN}} there must be
|
|
a visible function named @samp{@var{field}/1}.
|
|
@xref{Record syntax}.
|
|
|
|
Semantics:
|
|
@example
|
|
transform(V_in, V_out, Term =^ field1 ^ @dots{} ^ fieldN) =
|
|
(Term = V_in ^ field1 ^ @dots{} ^ fieldN, V_out = V_in)
|
|
@end example
|
|
|
|
@item ^ @var{field} := @var{Term}
|
|
A DCG field update.
|
|
Replaces a field in the implicit DCG argument.
|
|
@var{Term} must be a valid data-term.
|
|
For each @var{field} in @w{@var{field1} @dots{} @var{fieldN}} there must be
|
|
visible functions named @samp{@var{field}/1} and @samp{'@var{field}:='/2}.
|
|
@xref{Record syntax}.
|
|
|
|
Semantics:
|
|
@example
|
|
transform(V_in, V_out, ^ field1 ^ @dots{} ^ fieldN := Term) =
|
|
(V_out = V_in ^ field1 ^ @dots{} ^ fieldN := Term)
|
|
@end example
|
|
|
|
@item @var{DCG-call}
|
|
Any term which does not match any of the above forms
|
|
must be a DCG predicate call.
|
|
If the term is a variable @var{Var},
|
|
it is treated as if it were @samp{call(@var{Var})}.
|
|
Then, the two implicit DCG arguments are appended to the specified arguments.
|
|
|
|
Semantics:
|
|
@example
|
|
transform(V_in, V_out, p(A1, @dots{}, AN)) =
|
|
p(A1, @dots{}, AN, V_in, V_out)
|
|
@end example
|
|
|
|
@end table
|
|
|
|
@node Data-terms
|
|
@section Data-terms
|
|
|
|
Syntactically, a data-term is just a term.
|
|
|
|
There are a couple of differences from Prolog.
|
|
The first one is that double-quoted strings are atomic in
|
|
Mercury, they are not abbreviations for lists of character codes.
|
|
The second is that Mercury terms may contain function applications,
|
|
higher-order function applications, and lambda expressions.
|
|
|
|
A data-term is either a variable, a data-functor,
|
|
a conditional expression, a lambda expression,
|
|
or a higher-order function application.
|
|
|
|
@menu
|
|
* Data-functors::
|
|
* Record syntax::
|
|
* Conditional expressions::
|
|
* Lambda expressions::
|
|
* Higher-order function applications::
|
|
@end menu
|
|
|
|
@node Data-functors
|
|
@subsection Data-functors
|
|
|
|
A data-functor is an integer, a float, a string, a character literal
|
|
(any single-character name), a name, or a compound data-term.
|
|
A compound data-term is a compound term whose form
|
|
does not match the form of a lambda expression or higher-order
|
|
function application and whose arguments are data-terms.
|
|
If a data-functor is a name or a compound data-term, its top-level functor
|
|
must name a function, predicate, or data constructor declared
|
|
in the program or in the interface of an imported module.
|
|
|
|
@node Record syntax
|
|
@subsection Record syntax
|
|
|
|
Record syntax provides a convenient way to select or update fields
|
|
of data constructors, independent of the definition of the constructor.
|
|
|
|
Record syntax expressions are transformed into sequences of calls
|
|
to field selection or update functions (@pxref{Field access functions}).
|
|
|
|
@table @code
|
|
@item @var{Term} ^ @var{field}
|
|
|
|
A field selection, equivalent to @code{@var{field}(@var{Term})}.
|
|
|
|
@var{Term} must be a valid data-term.
|
|
@var{field} must be the name of a visible unary function, possibly a
|
|
function generated for a labelled field of a data constructor.
|
|
|
|
Field selections may be chained, as in @code{Term ^ field1 ^ field2},
|
|
which is equivalent to @code{field2(field1(Term))}.
|
|
|
|
@item @var{Term} ^ @var{field1} ^ @dots{} ^ @var{fieldN} := @var{FieldValue}
|
|
|
|
A field update.
|
|
|
|
@var{Term} must be a valid data-term.
|
|
For each @var{field} in @w{@var{field1} @dots{} @var{fieldN}} there must be
|
|
visible functions named @samp{@var{field}/1} and @samp{'@var{field}:='/2}.
|
|
Typically, these functions will be automatically generated by the compiler
|
|
for a labelled field of a data constructor, although they may be supplied
|
|
by the user.
|
|
|
|
The term @code{Term ^ field := FieldValue} is equivalent
|
|
to @code{'field:='(Term, FieldValue)}.
|
|
|
|
The general case above is equivalent to the code:
|
|
@example
|
|
OldField1 = @var{field1}(Term),
|
|
OldField2 = @var{field2}(OldField1),
|
|
@dots{}
|
|
OldField_N_Minus_1 = @var{field_N_Minus_2}(OldField_N_Minus_2),
|
|
NewField_N_Minus_1 = '@var{fieldN}:='(OldField_N_Minus_1, FieldValue),
|
|
@dots{}
|
|
NewField1 = '@var{field2}:='(OldField1, NewField2),
|
|
Result = '@var{field1}:='(Term, NewField1)
|
|
@end example
|
|
|
|
@end table
|
|
|
|
@node Conditional expressions
|
|
@subsection Conditional expressions
|
|
|
|
A conditional expression is an expression of either of the two following
|
|
forms
|
|
|
|
@example
|
|
(if @var{Goal} then @var{Expression1} else @var{Expression2})
|
|
(@var{Goal} -> @var{Expression1} ; @var{Expression2})
|
|
@end example
|
|
|
|
@noindent
|
|
@var{Goal} is a goal; @var{Expression1} and @var{Expression2} are
|
|
both data-terms. The semantics of a conditional expression is that
|
|
if @var{Goal} is true, then the expression has the meaning of
|
|
@var{Expression1}, else the expression has the meaning of @var{Expression2}.
|
|
|
|
@node Lambda expressions
|
|
@subsection Lambda expressions
|
|
|
|
A lambda expression is a compound term of one of the following forms
|
|
|
|
@example
|
|
lambda([Arg1::Mode1, Arg2::Mode2, @dots{}] is Det, Goal)
|
|
pred(Arg1::Mode1, Arg2::Mode2, @dots{}) is Det :- Goal
|
|
pred(Arg1::Mode1, Arg2::Mode2, @dots{}, DCGMode0, DCGMode1) is Det --> DCGGoal
|
|
func(Arg1::Mode1, Arg2::Mode2, @dots{}) = (Result::Mode) is Det :- Goal
|
|
func(Arg1, Arg2, @dots{}) = (Result) is Det :- Goal
|
|
func(Arg1, Arg2, @dots{}) = Result :- Goal
|
|
@end example
|
|
|
|
@noindent
|
|
where Arg1, Arg2, @dots{} are zero or more data-terms,
|
|
Result is a data-term,
|
|
Mode1, Mode2, @dots{} are zero or more modes (@pxref{Modes}),
|
|
DCGMode0 and DCGMode1 are modes (@pxref{Modes}),
|
|
Det is a determinism (@pxref{Determinism}),
|
|
Goal is a goal (@pxref{Goals}),
|
|
and DCGGoal is a DCG Goal (@pxref{DCG-goals}).
|
|
The @samp{:- Goal} part is optional;
|
|
if it is not specified, then @samp{:- 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. @xref{Higher-order}.
|
|
|
|
A lambda expression introduces a new scope: any variables occurring in
|
|
the arguments Arg1, Arg2, ... are locally quantified, i.e.
|
|
any occurrences of variables with that name in the lambda
|
|
expression are considered to name a different variable than any
|
|
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 (@pxref{Implicit quantification}).
|
|
|
|
The form of lambda expression using @samp{lambda} as its top level functor
|
|
is deprecated; please use the form using @samp{pred} instead.
|
|
|
|
The form of lambda expression using @samp{-->} as its top level functor
|
|
is a syntactic abbreviation: an expression of the form
|
|
|
|
@example
|
|
pred(Var1::Mode1, Var2::Mode2, @dots{}, DCGMode0, DCGMode1) is Det --> DCGGoal
|
|
@end example
|
|
|
|
@noindent
|
|
is equivalent to
|
|
|
|
@example
|
|
pred(Var1::Mode1, Var2::Mode2, @dots{},
|
|
DCGVar0::DCGMode0, DCGVar1::DCGMode1) is Det :- Goal
|
|
@end example
|
|
|
|
@noindent
|
|
where DCGVar0 and DCGVar1 are fresh variables,
|
|
and Goal is the result of @samp{DCG-transform(DCGVar0, DCGVar1, DCGGoal)}
|
|
where DCG-transform is the function specified in @ref{DCG-goals}.
|
|
|
|
@node Higher-order function applications
|
|
@subsection Higher-order function applications
|
|
|
|
A higher-order function application is a compound term of one
|
|
of the following two forms
|
|
|
|
@example
|
|
apply(@var{Func}, @var{Arg1}, @var{Arg2}, @dots{}, @var{ArgN})
|
|
@var{FuncVar}(@var{Arg1}, @var{Arg2}, @dots{}, @var{ArgN})
|
|
@end example
|
|
|
|
@noindent
|
|
where @var{N} >= 0, @var{Func} is a term of type
|
|
@samp{func(T1, T2, @dots{}, Tn) = T}, @var{FuncVar} is a variable
|
|
of that type, and
|
|
@var{Arg1}, @var{Arg2}, @dots{}, @var{ArgN} are terms of types
|
|
@samp{T1}, @samp{T2}, @dots{}, @samp{Tn}.
|
|
The type of the higher-order function application term is @var{T}.
|
|
It denotes the result of applying the specified function to the
|
|
specified arguments. @xref{Higher-order}.
|
|
|
|
@node Implicit quantification
|
|
@section Implicit quantification
|
|
|
|
The rule for implicit quantification in Mercury
|
|
is not the same as the usual one in mathematical logic.
|
|
In Mercury, variables that do not occur in the head of a clause
|
|
are implicitly existentially quantified around their closest enclosing scope
|
|
(in a sense to be made precise in the following paragraphs).
|
|
This allows most existential quantifiers to be omitted,
|
|
and leads to more concise code.
|
|
|
|
An occurrence of a variable is @dfn{in a negated context}
|
|
if it is in a negation,
|
|
in a universal quantification,
|
|
in the condition of an if-then-else,
|
|
in an inequality,
|
|
or in a lambda expression.
|
|
|
|
Two goals are @dfn{parallel}
|
|
if they are different disjuncts of the same disjunction,
|
|
or if one is the ``else'' part of an if-then-else
|
|
and the other goal is either the ``then'' part or the condition
|
|
of the if-then-else,
|
|
or if they are the goals of disjoint (distinct and non-overlapping)
|
|
lambda expressions.
|
|
|
|
If a variable occurs in a negated context
|
|
and does not occur outside of that negated context other than in parallel goals
|
|
(and in the case of a variable in the condition of an if-then-else,
|
|
other than in the ``then'' part of the if-then-else),
|
|
then that variable is implicitly existentially quantified inside the negation.
|
|
|
|
@node Elimination of double negation
|
|
@section Elimination of double negation
|
|
|
|
The treatment of inequality, universal quantification,
|
|
implication, and logical equivalence as abbreviations
|
|
can cause the introduction of double negations
|
|
which could make otherwise well-formed code mode-incorrect.
|
|
To avoid this problem, the language specifies that
|
|
after syntax analysis, and before mode analysis is performed,
|
|
the implementation must delete any double negations
|
|
and must replace any negations of conjunctions of negations
|
|
with disjunctions. (Both of these transformations
|
|
preserve the logical meaning and type-correctness of the code,
|
|
and they preserve or improve mode-correctness:
|
|
they never transform code fragments that would be
|
|
well-moded into ones that would be ill-moded.)
|
|
|
|
@node Types
|
|
@chapter Types
|
|
|
|
The type system is based on many-sorted logic, and supports polymorphism,
|
|
type classes (@pxref{Type classes}), and existentially quantified types
|
|
(@pxref{Existential types}).
|
|
|
|
@menu
|
|
* Builtin types::
|
|
* User-defined types::
|
|
* Predicate and function type declarations::
|
|
* Field access functions::
|
|
@end menu
|
|
|
|
@node Builtin types
|
|
@section Builtin types
|
|
|
|
Certain special types are builtin, or are defined in the Mercury library:
|
|
|
|
@table @asis
|
|
@item Primitive types: @code{char}, @code{int}, @code{float}, @code{string}.
|
|
There is a special syntax for constants of type @code{int}, @code{float},
|
|
and @code{string}. (For @code{char}, the standard syntax suffices.)
|
|
|
|
@item Predicate types: @code{pred}, @code{pred(T)}, @code{pred(T1, T2)}, @dots{}
|
|
@itemx Function types: @code{(func) = T}, @code{func(T1) = T},
|
|
@itemx @code{func(T1, T2) = T}, @dots{}
|
|
These higher-order function and predicate types are used to pass procedure
|
|
addresses and closures to other predicates. @xref{Higher-order}.
|
|
|
|
@item The universal type: @code{univ}.
|
|
The type @code{univ} is defined in the standard library module @code{std_util},
|
|
along with the predicates @code{type_to_univ/2} and @code{univ_to_type/2}.
|
|
With those predicates, any type can be converted to the universal type
|
|
and back again.
|
|
The universal type is useful for situations
|
|
where you need heterogeneous collections.
|
|
|
|
@item The ``state-of-the-world'' type: @code{io__state}.
|
|
The type @code{io__state} is defined in the standard library module @code{io},
|
|
and represents the state of the world.
|
|
Predicates which perform I/O are passed the old state of the world
|
|
and produce a new state of the world.
|
|
In this way, we can give a declarative semantics to code that performs I/O.
|
|
|
|
@end table
|
|
|
|
@node User-defined types
|
|
@section User-defined types
|
|
|
|
New types can be introduced with @samp{:- type} declarations.
|
|
There are several categories of derived types:
|
|
|
|
@menu
|
|
* Discriminated unions::
|
|
* Equivalence types::
|
|
* Abstract types::
|
|
@end menu
|
|
|
|
@node Discriminated unions
|
|
@subsection Discriminated unions
|
|
|
|
These encompass both enumeration and record types in other languages.
|
|
A derived type is defined using @samp{:- type @var{type} ---> @var{body}}.
|
|
(Note there are @emph{three} dashes in that arrow.
|
|
It should not be confused with the two-dash arrow used for DCGs
|
|
or the one-dash arrow used for if-then-else.)
|
|
If the @var{type} term is a functor of arity zero
|
|
(i.e. one having zero arguments),
|
|
it names a monomorphic type.
|
|
Otherwise, it names a polymorphic type;
|
|
the arguments of the functor must be distinct type variables.
|
|
The @var{body} term is defined as
|
|
a sequence of constructor definitions separated by semi-colons.
|
|
|
|
Ordinarily, each constructor definition must be a functor whose arguments
|
|
(if any) are types. Ordinary discriminated union definitions must be
|
|
@dfn{transparent}: all type variables occurring in the @var{body} must
|
|
also occur in the @var{type}.
|
|
|
|
However, constructor definitions can optionally be existentially typed.
|
|
In that case, the functor will be preceded by an existential type
|
|
quantifier and can optionally be followed by an existential type
|
|
class constraint. For details, see @ref{Existential types}.
|
|
Existentially typed discriminated union definitions need not be
|
|
transparent.
|
|
|
|
The arguments of constructor definitions may be labelled.
|
|
These labels cause the compiler to generate functions which can
|
|
be used to conveniently select and update fields of a term
|
|
in a manner independent of the definition of the type
|
|
(@pxref{Field access functions}). A labelled argument is of the
|
|
form @w{@code{@var{fieldname} :: @var{Type}}}. It is an error for
|
|
two fields in the same module to have the same label.
|
|
|
|
Here are some examples of discriminated union definitions:
|
|
|
|
@example
|
|
:- type fruit
|
|
---> apple
|
|
; orange
|
|
; banana
|
|
; pear.
|
|
|
|
:- type strange
|
|
---> foo(int)
|
|
; bar(string).
|
|
|
|
:- type employee
|
|
---> employee(
|
|
name :: string,
|
|
age :: int,
|
|
department :: string
|
|
).
|
|
|
|
:- type tree
|
|
---> empty
|
|
; leaf(int)
|
|
; branch(tree, tree).
|
|
|
|
:- type list(T)
|
|
---> []
|
|
; [T | list(T)].
|
|
|
|
:- type pair(T1, T2)
|
|
---> T1 - T2.
|
|
@end example
|
|
|
|
If the body of a discriminated union type definition
|
|
contains a term whose top-level functor is @code{';'/2},
|
|
the semi-colon is normally assumed to be a separator.
|
|
This makes it difficult to define a type
|
|
whose constructors include @code{';'/2}.
|
|
To allow this, curly braces can be used to quote the semi-colon.
|
|
It is then also necessary to quote curly braces.
|
|
The following example illustrates this:
|
|
|
|
@example
|
|
:- type tricky
|
|
---> @{ int ; int @}
|
|
; @{ @{ int @} @}.
|
|
@end example
|
|
|
|
This defines a type with two constructors, @code{';'/2} and @code{'@{@}'/1},
|
|
whose argument types are all @code{int}.
|
|
|
|
Each discriminated union type definition introduces a distinct type.
|
|
Mercury considers two discriminated union types that have the same bodies
|
|
to be distinct types (name equivalence).
|
|
Having two different definitions of a type with the same name and arity in
|
|
the same module is an error.
|
|
|
|
Constructors may be overloaded among different types:
|
|
there may be any number of constructors with a given name and arity,
|
|
so long as they all have different types.
|
|
However, there must not be more than one constructor
|
|
with the same name, arity, and result type in the same module.
|
|
(There is no particularly good reason for this restriction;
|
|
in the future we may allow several such functors
|
|
as long as they have different argument types.)
|
|
Note that excessive overloading of constructors can slow down type checking
|
|
and can make the program confusing for human readers,
|
|
so overloading should not be over-used.
|
|
|
|
@node Equivalence types
|
|
@subsection Equivalence types
|
|
|
|
These are type abbreviations.
|
|
They are defined using @samp{==} as follows.
|
|
They may be polymorphic.
|
|
|
|
@example
|
|
:- type money == int.
|
|
:- type assoc_list(KeyType, ValueType)
|
|
== list(pair(KeyType, ValueType)).
|
|
@end example
|
|
|
|
Equivalence type definitions must be transparent.
|
|
Unlike discriminated union type definitions,
|
|
equivalence type definitions must not be cyclic;
|
|
that is, the type on the left hand side of the @samp{==}
|
|
(@samp{assoc_list} and @samp{money} in the examples above)
|
|
must not occur on the right hand side of the @samp{==}.
|
|
|
|
Mercury treats an equivalence type
|
|
as an abbreviation for the type on the right hand side of the definition;
|
|
the two are equivalent in all respects
|
|
in scopes where the equivalence type is visible.
|
|
|
|
@node Abstract types
|
|
@subsection Abstract types
|
|
|
|
These are types whose implementation is hidden.
|
|
The type declarations
|
|
|
|
@example
|
|
:- type t1.
|
|
:- type t2(T1, T2).
|
|
@end example
|
|
|
|
@noindent
|
|
declare types @code{t1/0} and @code{t2/2} to be abstract types.
|
|
Such declarations are only useful in the interface section of a module.
|
|
This means that the type names will be exported,
|
|
but the constructors (functors) for these types will not be exported.
|
|
The implementation section of a module
|
|
must have give the definition of all the abstract types
|
|
named in the interface section of the module.
|
|
Abstract types may be defined as either discriminated union types
|
|
or as equivalence types.
|
|
|
|
@node Predicate and function type declarations
|
|
@section Predicate and function type declarations
|
|
|
|
The argument types of each predicate
|
|
must be explicitly declared with a @samp{:- pred} declaration.
|
|
The argument types and return type of each function must be
|
|
explicitly declared with a @samp{:- func} declaration.
|
|
For example:
|
|
|
|
@example
|
|
:- pred is_all_uppercase(string).
|
|
|
|
:- func strlen(string) = int.
|
|
@end example
|
|
|
|
Predicates and functions can be polymorphic; that is, their
|
|
declarations can include type variables. For example:
|
|
|
|
@example
|
|
:- pred member(T, list(T)).
|
|
|
|
:- func length(list(T)) = int.
|
|
@end example
|
|
|
|
Type variables in predicate and function declarations
|
|
are implicitly universally quantified by default;
|
|
that is, the predicate or function may be called with arguments
|
|
and (in the case of functions) return value
|
|
whose actual types are any instance of the types
|
|
specified in the declaration. For example,
|
|
the function @samp{length/1} declared above
|
|
could be called with the argument having
|
|
type @samp{list(int)}, or @samp{list(float)},
|
|
or @samp{list(list(int))}, etc.
|
|
|
|
Type variables in predicate and function declarations can
|
|
also be existentially quantified; this is discussed in
|
|
@ref{Existential types}.
|
|
|
|
There must only be one predicate with a given name and arity in each module,
|
|
and only one function with a given name and arity in each module.
|
|
It is an error to declare the same predicate or function twice.
|
|
|
|
Note that a predicate defined using DCG notation (@pxref{DCG-rules})
|
|
will appear to be defined with two fewer arguments than it is declared
|
|
with. It will also appear to be called with two fewer arguments when
|
|
called from predicates defined using DCG notation. However, when called
|
|
from an ordinary predicate or function, it must have all the arguments
|
|
it was declared with.
|
|
|
|
The compiler infers the types of data-terms, and in particular the types
|
|
of variables and overloaded constructors, functions, and predicates.
|
|
A @dfn{type assignment} is an assignment of a type
|
|
to every variable and of a particular constructor, function, or predicate
|
|
to every name in a clause.
|
|
A type assignment is @dfn{valid} if it satisfies the following conditions.
|
|
|
|
Each constructor in a clause
|
|
must have been declared in at least one visible type declaration.
|
|
The type assigned to each constructor term
|
|
must match one of the type declarations for that constructor,
|
|
and the types assigned to the arguments of that constructor
|
|
must match the argument types specified in that type declaration.
|
|
|
|
The type assigned to each function call term
|
|
must match the return type of one of the @samp{:- func} declarations
|
|
for that function, and the types assigned to the arguments of that function
|
|
must match the argument types specified in that type declaration.
|
|
|
|
The type assigned to each predicate argument must match
|
|
the type specified in one of the @samp{:- pred} declarations for that predicate.
|
|
The type assigned to each head argument in a predicate clause must exactly match
|
|
the argument type specified in the corresponding @samp{:- pred} declaration.
|
|
|
|
The type assigned to each head argument in a function clause must exactly match
|
|
the argument type specified in the corresponding @samp{:- func} declaration,
|
|
and the type assigned to the result term in a function clause must exactly
|
|
match the result type specified in the corresponding @samp{:- func} declaration.
|
|
|
|
(Here ``match'' means to be an instance of,
|
|
i.e. to be identical to for some substitution of the type parameters,
|
|
and ``exactly match'' means to be identical up to renaming of type parameters.)
|
|
|
|
One type assignment @var{A} is said to be
|
|
@dfn{more general} than another type assignment @var{B}
|
|
if there is a binding of the type parameters in A
|
|
that makes it identical (up to renaming of parameters) to B.
|
|
If there is more than one valid type assignment,
|
|
the compiler must choose the most general one.
|
|
If there are two valid type assignments which are not identical up to renaming
|
|
and neither of which is more general than the other,
|
|
then there is a type ambiguity, and compiler must report an error.
|
|
A clause is @dfn{type-correct}
|
|
if there is a unique (up to renaming) most general valid type assignment.
|
|
Every clause in a Mercury program must be type-correct.
|
|
|
|
@node Field access functions
|
|
@section Field access functions
|
|
|
|
Fields of constructors of discriminated union types may be
|
|
labelled (@pxref{Discriminated unions}). These labels cause the
|
|
compiler to generate functions which can be used to select and update
|
|
fields of a term in a manner independent of the definition of the type.
|
|
|
|
The Mercury language includes syntactic sugar to make it more convenient
|
|
to select and update fields inside nested terms (@pxref{Record syntax})
|
|
and to select and update fields of the DCG arguments of a
|
|
clause (@pxref{DCG-goals}).
|
|
|
|
@menu
|
|
* Field selection::
|
|
* Field update::
|
|
* User-supplied field access function declarations::
|
|
* Field access examples::
|
|
@end menu
|
|
|
|
@node Field selection
|
|
@subsection Field selection
|
|
|
|
@example
|
|
@var{field}(@var{Term})
|
|
@end example
|
|
|
|
Each field label @samp{@var{field}} in a constructor causes generation
|
|
of a field selection function @samp{@var{field}/1}, which takes a data-term
|
|
of the same type as the constructor and returns the value of the
|
|
labelled field, failing if the top-level constructor of the argument
|
|
is not the constructor containing the field.
|
|
|
|
If the declaration of the field is in the interface section of the module,
|
|
the corresponding field selection function is also exported from the module.
|
|
|
|
By default, this function has no declared modes --- the modes are inferred at
|
|
each call to the function. However, the modes of this function may be
|
|
explicitly declared, in which case it will have only the declared modes.
|
|
|
|
To create a higher-order term from a field selection function, an
|
|
explicit lambda expression must be used, unless a single mode
|
|
declaration is supplied for the field selection function.
|
|
|
|
@node Field update
|
|
@subsection Field update
|
|
|
|
@example
|
|
'@var{field}:='(@var{Term}, @var{ValueTerm})
|
|
@end example
|
|
|
|
Each field label @samp{@var{field}} in a constructor causes generation
|
|
of a field update function @samp{'@var{field}:='/2}.
|
|
The first argument of this function is a data-term of the same type as the
|
|
constructor. The second argument is a data-term of the same type as the
|
|
labelled field. The return value is a copy of the first argument with
|
|
value of the labelled field replaced by the second argument.
|
|
@samp{'@var{field}:='/2} fails if the top-level constructor of the
|
|
first argument is not the constructor containing the labelled field.
|
|
|
|
If the declaration of the field is in the interface section of the module,
|
|
the corresponding field update function is also exported from the module.
|
|
|
|
By default, this function has no declared modes --- the modes are inferred at
|
|
each call to the function. However, the modes of this function may be
|
|
explicitly declared, in which case it will have only the declared modes.
|
|
|
|
To create a higher-order term from a field update function, an
|
|
explicit lambda expression must be used, unless a single mode
|
|
declaration is supplied for the field update function.
|
|
|
|
Some fields cannot be updated using field update functions.
|
|
For the constructor @samp{unsettable/2} below, neither field may be updated
|
|
because the resulting term would not be well-typed. A future release
|
|
may allow multiple fields to be updated by a single expression to avoid
|
|
this problem.
|
|
|
|
@example
|
|
:- type unsettable
|
|
---> some [T] unsettable(
|
|
unsettable1 :: T,
|
|
unsettable2 :: T
|
|
).
|
|
@end example
|
|
|
|
@node User-supplied field access function declarations
|
|
@subsection User-supplied field access function declarations
|
|
|
|
Type and mode declarations for compiler-generated field access functions
|
|
for fields of constructors local to a module may be placed in the interface
|
|
section of the module. This allows the implementation of a type to be hidden
|
|
while still allowing client modules to use record syntax to manipulate values
|
|
of the type. Supplying a single mode declaration also allows higher-order
|
|
terms to be created from a field access function without using explicit
|
|
lambda expressions.
|
|
|
|
Declarations for field access functions for fields occurring in the interface
|
|
section of a module must also occur in the interface section.
|
|
|
|
Declarations and clauses for field access functions can also be supplied
|
|
for fields which are not a part of any type. This is useful when the data
|
|
structures of a program change so that a value which was previously stored
|
|
as part of a type is now computed each time it is requested. It also
|
|
allows record syntax to be used for type class methods.
|
|
|
|
@node Field access examples
|
|
@subsection Field access examples
|
|
|
|
The examples make use of the following type declarations:
|
|
|
|
@example
|
|
:- type type1
|
|
---> type1(
|
|
field1 :: type2,
|
|
field2 :: string
|
|
).
|
|
|
|
:- type type2
|
|
---> type2(
|
|
field3 :: int,
|
|
field4 :: int
|
|
).
|
|
|
|
@end example
|
|
|
|
The compiler generates some field access functions for @samp{field1}.
|
|
The functions generated for the other fields are similar.
|
|
|
|
@example
|
|
:- func field1(type1) = type2.
|
|
field1(type1(Field1, _)) = Field1.
|
|
|
|
:- func 'field1:='(type1, type2) = type1.
|
|
'field1:='(type1(_, Field2), Field1) = type1(Field1, Field2).
|
|
@end example
|
|
|
|
Using these functions and the syntactic sugar described in
|
|
@ref{Record syntax}, programmers can write code such as
|
|
|
|
@example
|
|
:- func increment_field3(type1) = type1.
|
|
|
|
increment_field3(Term0) =
|
|
Term0^field1^field3 := Term0^field1^field3 + 1.
|
|
@end example
|
|
|
|
The compiler expands this into
|
|
|
|
@example
|
|
incremental_field3(Term0) = Term :-
|
|
OldField3 = field3(field1(Term0)),
|
|
|
|
OldField1 = field1(Term0),
|
|
NewField1 = 'field3:='(OldField1, OldField3 + 1),
|
|
Term = 'field1:='(Term0, NewField1).
|
|
@end example
|
|
|
|
@node Modes
|
|
@chapter Modes
|
|
|
|
The @dfn{mode} of a predicate, or function, is a mapping
|
|
from the initial state of instantiation of the arguments of the predicate,
|
|
or the arguments and result of a function,
|
|
to their final state of instantiation.
|
|
To describe states of instantiation,
|
|
we use information provided by the type system.
|
|
Types can be viewed as regular trees with two kinds of nodes:
|
|
or-nodes representing types
|
|
and and-nodes representing constructors.
|
|
The children of an or-node are the constructors
|
|
that can be used to construct terms of that type;
|
|
the children of an and-node are the types
|
|
of the arguments of the constructors.
|
|
We attach mode information to the or-nodes of type trees.
|
|
|
|
An @dfn{instantiatedness tree} is an assignment
|
|
of an @dfn{instantiatedness} --- either @dfn{free} or @dfn{bound} ---
|
|
to each or-node of a type tree,
|
|
with the constraint that all descendants of a free node must be free.
|
|
|
|
A term is @dfn{approximated by} an instantiatedness tree
|
|
if for every node in the instantiatedness tree,
|
|
|
|
@itemize @bullet
|
|
@item
|
|
if the node is ``free'',
|
|
then the corresponding node in the term (if any)
|
|
is a free variable that does not share with any other variable
|
|
(we call such variables @dfn{distinct});
|
|
|
|
@item
|
|
if the node is ``bound'',
|
|
then the corresponding node in the term (if any)
|
|
is a function symbol.
|
|
|
|
@end itemize
|
|
|
|
When an instantiatedness tree tells us that a variable is bound,
|
|
there may be several alternative function symbols to which it could be bound.
|
|
The instantiatedness tree does not tell us which of these it is bound to;
|
|
instead for each possible function symbol it tells us exactly
|
|
which arguments of the function symbol will be free and which will be bound.
|
|
The same principle applies recursively to these bound arguments.
|
|
|
|
Mercury's mode system allows users
|
|
to declare names for instantiatedness trees using declarations such as
|
|
|
|
@example
|
|
:- inst listskel = bound( [] ; [free | listskel] ).
|
|
@end example
|
|
|
|
This instantiatedness tree describes lists
|
|
whose skeleton is known but whose elements are distinct variables.
|
|
As such, it approximates the term @code{[A,B]}
|
|
but not the term @code{[H|T]} (only part of the skeleton is known),
|
|
the term @code{[A,2]} (not all elements are variables),
|
|
or the term @code{[A,A]} (the elements are not distinct variables).
|
|
|
|
As a shorthand, the mode system provides @samp{free} and @samp{ground}
|
|
as names for instantiatedness trees
|
|
all of whose nodes are free and bound respectively.
|
|
The shape of these trees is determined by
|
|
the type of the variable to which they apply.
|
|
|
|
As execution proceeds, variables may become more instantiated.
|
|
A @dfn{mode mapping} is a mapping
|
|
from an initial instantiatedness tree to a final instantiatedness tree,
|
|
with the constraint that no node of the type tree
|
|
is transformed from bound to free.
|
|
Mercury allows the user to specify mode mappings directly
|
|
by expressions such as @code{inst1 -> inst2},
|
|
or to give them a name using declarations such as
|
|
|
|
@example
|
|
:- mode m :: inst1 -> inst2.
|
|
@end example
|
|
|
|
Two standard shorthand modes are provided,
|
|
corresponding to the standard notions of inputs and outputs:
|
|
|
|
@example
|
|
:- mode in :: ground -> ground.
|
|
:- mode out :: free -> ground.
|
|
@end example
|
|
|
|
Prolog fans who want to use the symbols @samp{+} and @samp{-}
|
|
can do so by simply defining them using a mode declaration:
|
|
|
|
@example
|
|
:- mode (+) :: in.
|
|
:- mode (-) :: out.
|
|
@end example
|
|
|
|
These two modes are enough for most functions and predicates.
|
|
Nevertheless, Mercury's mode system is sufficiently
|
|
expressive to handle more complex data-flow patterns,
|
|
including those involving partially instantiated data structures.
|
|
(The current implementation does not handle
|
|
partially instantiated data structures yet.)
|
|
|
|
For example, consider an
|
|
interface to a database that associates data with keys, and provides
|
|
read and write access to the items it stores. To represent accesses to
|
|
the database over a network, you would need declarations such as
|
|
|
|
@example
|
|
:- type operation
|
|
---> lookup(key, data)
|
|
; set(key, data).
|
|
:- inst request =
|
|
bound( lookup(ground, free)
|
|
; set(ground, ground)
|
|
).
|
|
:- mode create_request :: free -> request.
|
|
:- mode satisfy_request :: request -> ground.
|
|
@end example
|
|
|
|
@samp{inst} and @samp{mode} declarations can be parametric.
|
|
For example, the following declaration
|
|
|
|
@example
|
|
:- inst listskel(Inst) = bound( [] ; [Inst | listskel(Inst)] ).
|
|
@end example
|
|
|
|
@noindent
|
|
defines the inst @samp{listskel(Inst)} to be a list skeleton
|
|
whose elements have inst @samp{Inst}; you can the use insts
|
|
such as @samp{listskel(listskel(free))}, which represents
|
|
the instantiation state of a list of lists of free variables.
|
|
The standard library provides the parametric modes
|
|
|
|
@example
|
|
:- mode in(Inst) :: Inst -> Inst.
|
|
:- mode out(Inst) :: free -> Inst.
|
|
@end example
|
|
|
|
@noindent
|
|
so that for example the mode @samp{create_request} defined above
|
|
could have be defined as
|
|
|
|
@example
|
|
:- mode create_request :: out(request).
|
|
@end example
|
|
|
|
There must not be more than one inst definition with the same name
|
|
and arity in the same module. Similarly, there must not be more
|
|
than one mode definition with the same name and arity in the same module.
|
|
|
|
A @dfn{predicate mode declaration}
|
|
assigns a mode mapping to each argument of a predicate.
|
|
A @dfn{function mode declaration}
|
|
assigns a mode mapping to each argument of a function,
|
|
and a mode mapping to the function result.
|
|
Each mode of a predicate or function is called a @dfn{procedure}.
|
|
For example, given the mode names defined by
|
|
|
|
@example
|
|
:- mode out_listskel ::
|
|
free -> listskel.
|
|
:- mode in_listskel ::
|
|
listskel -> listskel.
|
|
@end example
|
|
|
|
the (type and) mode declarations of the function length and predicate append
|
|
are as follows:
|
|
|
|
@example
|
|
:- func length(list(T)) = int.
|
|
:- mode length(in_listskel) = out.
|
|
:- mode length(out_listskel) = in.
|
|
|
|
:- pred append(list(T), list(T), list(T)).
|
|
:- mode append(in, in, out).
|
|
:- mode append(out, out, in).
|
|
@end example
|
|
|
|
Note that functions may have more than one mode, just like predicates;
|
|
functions can be reversible.
|
|
|
|
Alternately, the mode declarations for @samp{length} could use
|
|
the standard library modes @samp{in/1} and @samp{out/1}:
|
|
|
|
@example
|
|
:- func length(list(T)) = int.
|
|
:- mode length(in(listskel)) = out.
|
|
:- mode length(out(listskel)) = in.
|
|
@end example
|
|
|
|
If a predicate or function has only one mode, the @samp{pred} and @samp{mode}
|
|
declaration can be combined:
|
|
|
|
@example
|
|
:- func length(list(T)::in) = (int::out).
|
|
:- pred append(list(T)::in, list(T)::in, list(T)::out).
|
|
@end example
|
|
|
|
If there is no mode declaration for a function, the compiler assumes
|
|
a default mode for the function in which all the arguments have mode @samp{in}
|
|
and the result of the function has mode @samp{out}. (However, there
|
|
is no requirement that a function have such a mode; if there is any
|
|
explicit mode declaration, it overrides the default.)
|
|
|
|
A function or predicate mode declaration is an assertion by the programmer
|
|
that for all possible argument terms and (if applicable) result term
|
|
for the function or predicate
|
|
that are approximated (in our technical sense)
|
|
by the initial instantiatedness trees of the mode declaration
|
|
and all of whose free variables are distinct,
|
|
if the function or predicate succeeds then
|
|
the resulting binding of those argument terms and (if applicable)
|
|
result term will in turn be approximated
|
|
by the final instantiatedness trees of the mode declaration,
|
|
with all free variables again being distinct.
|
|
We refer to such assertions as @dfn{mode declaration constraints}.
|
|
These assertions are checked by the compiler,
|
|
which rejects programs if it cannot prove
|
|
that their mode declaration constraints are satisfied.
|
|
|
|
Note that with the usual definition of append, the mode
|
|
|
|
@example
|
|
:- mode append(in_listskel, in_listskel, out_listskel).
|
|
@end example
|
|
|
|
would not be allowed, since it would create aliasing between the
|
|
different arguments --- on success of the predicate, the list elements
|
|
would be free variables but they would not be distinct.
|
|
|
|
In Mercury it is always possible to call a procedure with an
|
|
argument that is is more bound than the initial inst specified for that
|
|
argument in the procedure's mode declaration. In such cases, the
|
|
compiler will insert additional unifications to ensure that the
|
|
argument actually passed to the procedure will have the inst specified.
|
|
For example, if the predicate @code{p/1} has mode @samp{p(out)}, you
|
|
can still call @samp{p(X)} if @code{X} is ground. The compiler will
|
|
transform this code to @samp{p(Y), X = Y} where @code{Y} is a fresh
|
|
variable. It is almost as if the predicate @code{p/1} has another mode
|
|
@samp{p(in)}; we call such modes ``implied modes''.
|
|
|
|
To make this concept precise, we introduce the following definition.
|
|
A term @dfn{satisfies} an instantiatedness tree
|
|
if for every node in the instantiatedness tree,
|
|
|
|
@itemize @bullet
|
|
@item
|
|
if the node is ``free'',
|
|
then the corresponding node in the term (if any)
|
|
is either a distinct free variable,
|
|
or a function symbol.
|
|
|
|
@item
|
|
if the node is ``bound'',
|
|
then the corresponding node in the term (if any)
|
|
is a function symbol.
|
|
|
|
@end itemize
|
|
|
|
The @dfn{mode set} for a predicate or function
|
|
is the set of mode declarations for the predicate or function.
|
|
A mode set is an assertion by the programmer
|
|
that the predicate should only be called with argument terms
|
|
that satisfy the initial instantiatedness trees
|
|
of one of the mode declarations in the set
|
|
(i.e. the specified modes and the modes they imply
|
|
are the only allowed modes for this predicate or function).
|
|
We refer to the assertion associated with a mode set
|
|
as the @dfn{mode set constraint};
|
|
these are also checked by the compiler.
|
|
|
|
A predicate or function @var{p} is @dfn{well-moded
|
|
with respect to a given mode declaration}
|
|
if given that the predicates and functions called by @var{p}
|
|
all satisfy their mode declaration constraints,
|
|
there exists an ordering of the literals in the definition of @var{p}
|
|
such that
|
|
|
|
@itemize @bullet
|
|
@item
|
|
@var{p} satisfies its mode declaration constraint, and
|
|
@item
|
|
@var{p} satisfies the mode set constraint of all of the predicates and
|
|
functions it calls
|
|
@end itemize
|
|
|
|
We say that a predicate or function is well-moded
|
|
if it is well-moded with respect to
|
|
all the mode declarations in its mode set,
|
|
and we say that a program is well-moded
|
|
if all its predicates and functions are well-moded.
|
|
|
|
The mode analysis algorithm checks one procedure at a time.
|
|
It abstractly interprets the definition of the predicate or function,
|
|
keeping track of the instantiatedness of each variable,
|
|
and selecting a mode for each call and unification in the definition.
|
|
To ensure that
|
|
the mode set constraints of called predicates and functions are satisfied,
|
|
the compiler may reorder the elements of conjunctions;
|
|
it reports an error if no satisfactory order exists.
|
|
Finally it checks that
|
|
the resulting instantiatedness of the procedure's arguments
|
|
is the same as the one given by the procedure's declaration.
|
|
|
|
The mode analysis algorithm annotates each call with the mode used.
|
|
|
|
@node Unique modes
|
|
@chapter Unique modes
|
|
|
|
Mode declarations can also specify so-called ``unique modes''.
|
|
Mercury's unique modes are similar to ``linear types'' in some
|
|
functional programming languages such as Clean. They allow you to
|
|
specify when there is only one reference to a particular value, and
|
|
when there will be no more references to that value. If the compiler
|
|
knows there will be no more references to a value, it can perform
|
|
``compile-time garbage collection'' by automatically inserting code
|
|
to deallocate the storage associated with that value. Even more
|
|
importantly, the compiler can also simply reuse the storage immediately,
|
|
for example by destructively updating one element of an array rather
|
|
than making a new copy of the entire array in order to change one element.
|
|
Unique modes are also the mechanism Mercury uses to provide declarative I/O.
|
|
|
|
We have not yet implemented unique modes fully, and the details are
|
|
still in a state of flux. So the following should be considered
|
|
tentative.
|
|
|
|
@menu
|
|
* Destructive update::
|
|
* Backtrackable destructive update::
|
|
* Limitations of the current implementation::
|
|
@end menu
|
|
|
|
@node Destructive update
|
|
@section Destructive update
|
|
|
|
In addition to the insts mentioned above (@samp{free}, @samp{ground},
|
|
and @samp{bound(@dots{})}), Mercury also provides ``unique'' insts
|
|
@samp{unique} and @samp{unique(@dots{})} which are like @samp{ground}
|
|
and @samp{bound(@dots{})} respectively, except that they carry the
|
|
additional constraint that there can only be one reference to the
|
|
corresponding value. There is also an inst @samp{dead} which means
|
|
that there are no references to the corresponding value, so the compiler
|
|
is free to generate code that reuses that value.
|
|
There are three standard modes for manipulation unique values:
|
|
|
|
@example
|
|
% unique output
|
|
:- mode uo :: free -> unique.
|
|
|
|
% unique input
|
|
:- mode ui :: unique -> unique.
|
|
|
|
% destructive input
|
|
:- mode di :: unique -> dead.
|
|
@end example
|
|
|
|
Mode @samp{uo} is used to create a unique value.
|
|
Mode @samp{ui} is used to inspect a unique value without
|
|
losing its uniqueness.
|
|
Mode @samp{di} is used to deallocate or reuse the memory
|
|
occupied by a value that will not be used.
|
|
|
|
Note that a value is not considered @samp{unique} if it might be
|
|
needed on backtracking. This means that unique modes are generally
|
|
only useful for code whose determinism is @samp{det} or @samp{cc_multi}
|
|
(@pxref{Determinism}).
|
|
|
|
@node Backtrackable destructive update
|
|
@section Backtrackable destructive update
|
|
|
|
@quotation
|
|
``Well it just so happens that your friend here is only @emph{mostly} dead.
|
|
@*There's a big difference between mostly dead and all dead@dots{}
|
|
@*Now, mostly dead is slightly alive.
|
|
@*Now, all dead --- well, with all dead, there's usually only
|
|
one thing that you can do.''
|
|
|
|
``What's that?''
|
|
|
|
``Go through his clothes and look for loose change!''
|
|
|
|
--- from the movie ``The Princess Bride''.
|
|
@end quotation
|
|
|
|
To allow for backtrackable destructive updates --- that is, updates
|
|
whose effect is undone on backtracking, perhaps by recording the
|
|
overwritten values on a ``trail'' so that they can be restored
|
|
after backtracking --- Mercury also provides ``mostly unique''
|
|
modes. The insts @samp{mostly_unique} and @samp{mostly_dead}
|
|
are equivalent to @samp{unique} and @samp{dead},
|
|
except that only references which will be encountered during
|
|
forward execution are counted - it is OK for @samp{mostly_unique} or
|
|
@samp{mostly_dead} values to be needed again on backtracking.
|
|
|
|
Mercury defines some standard modes for manipulating ``mostly unique''
|
|
values, just as it does for unique values:
|
|
|
|
@example
|
|
% mostly unique output
|
|
:- mode muo :: free -> mostly_unique.
|
|
|
|
% mostly unique input
|
|
:- mode mui :: mostly_unique -> mostly_unique.
|
|
|
|
% mostly destructive input
|
|
:- mode mdi :: mostly_unique -> mostly_dead.
|
|
@end example
|
|
|
|
@node Limitations of the current implementation
|
|
@section Limitations of the current implementation
|
|
|
|
The implementation of the mode analysis algorithm is not quite complete;
|
|
as a result, it is not possible to use nested unique modes, i.e.
|
|
modes in which anything but the top level of a variable is unique.
|
|
If you do, you will get unique mode errors when you try
|
|
to get a unique field of a unique data structure.
|
|
It is also not possible to use unique-input modes;
|
|
only destructive-input and unique-output modes work.
|
|
|
|
The Mercury compiler does not (yet) reuse @samp{dead}
|
|
values. The only destructive update in the current implementation occurs
|
|
in library modules, e.g. for I/O and arrays. We do however plan to
|
|
implement structure reuse and compile-time garbage collection
|
|
in the very near future.
|
|
|
|
@node Determinism
|
|
@chapter Determinism
|
|
|
|
@menu
|
|
* Determinism categories::
|
|
* Determinism checking and inference::
|
|
* Replacing compile-time checking with run-time checking::
|
|
* Interfacing nondeterministic code with the real world::
|
|
* Committed choice nondeterminism::
|
|
@end menu
|
|
|
|
@node Determinism categories
|
|
@section Determinism categories
|
|
|
|
For each mode of a predicate or function,
|
|
we categorise that mode according to how many times it can succeed,
|
|
and whether or not it can fail before producing its first solution.
|
|
|
|
@itemize @bullet
|
|
@item
|
|
If all possible calls to a particular mode of a predicate or function
|
|
have exactly one solution,
|
|
then that mode is @dfn{deterministic} (@code{det}).
|
|
|
|
@item
|
|
If all possible calls to a particular mode of a predicate or function
|
|
either have no solutions or have one solution,
|
|
then that mode is @dfn{semideterministic} (@code{semidet}).
|
|
|
|
@item
|
|
If all possible calls to a particular mode of a predicate or function
|
|
have at least one solution but may have more,
|
|
then that mode is @dfn{multisolution} (@code{multi}).
|
|
|
|
@item
|
|
If some possible calls to a particular mode of a predicate or function
|
|
have no solution but other calls may have more than one solution,
|
|
then that mode is @dfn{nondeterministic} (@code{nondet}).
|
|
|
|
@item
|
|
If all possible calls to a particular mode of a predicate or function
|
|
fail without producing a solution,
|
|
then that mode has a determinism of @code{failure}.
|
|
|
|
@item
|
|
If all possible calls to a particular mode of a predicate or function
|
|
lead to a runtime error, i.e. neither succeed nor fail,
|
|
then that mode has a determinism of @code{erroneous}.
|
|
@end itemize
|
|
|
|
The determinism annotation @code{erroneous} is used on the library
|
|
predicate @samp{error/1}, but apart from that those last two determinism
|
|
annotations are generally not needed.
|
|
|
|
To summarize:
|
|
|
|
@example
|
|
Maximum number of solutions
|
|
Can fail? 0 1 > 1
|
|
no erroneous det multi
|
|
yes failure semidet nondet
|
|
@end example
|
|
|
|
(Note: the "Can fail?" column here indicates only whether the procedure
|
|
can fail before producing at least one solution; attempts to find a
|
|
@emph{second} solution to a particular call, e.g. for a procedure
|
|
with determinism @samp{multi}, are always allowed to fail.)
|
|
|
|
The determinism of each mode of a predicate or function
|
|
is indicated by an annotation on the mode declaration.
|
|
For example:
|
|
|
|
@example
|
|
:- pred append(list(T), list(T), list(T)).
|
|
:- mode append(in, in, out) is det.
|
|
:- mode append(out, out, in) is multi.
|
|
:- mode append(in, in, in) is semidet.
|
|
|
|
:- func length(list(T)) = int.
|
|
:- mode length(in) = out is det.
|
|
:- mode length(in(list_skel)) = out is det.
|
|
:- mode length(in) = in is semidet.
|
|
@end example
|
|
|
|
An annotation of @samp{det} or @samp{multi} is an assertion that
|
|
for every value each of the inputs, there exists at least one value
|
|
of the outputs for which the predicate is true, or (in the case
|
|
of functions) for which the function term is equal to the result term.
|
|
Conversely, an annotation of @samp{det} or @samp{semidet} is an assertion
|
|
that for every value each of the inputs, there exists at most one value
|
|
of the outputs for which the predicate is true, or (in the case
|
|
of functions) for which the function term is equal to the result term.
|
|
These assertions are called the @dfn{mode-determinism assertions};
|
|
they can play a role in the semantics, because in certain
|
|
circumstances they may allow an implementation to perform optimizations
|
|
that would not otherwise be allowed, such as optimizing away a goal
|
|
with no outputs even though it might infinitely loop.
|
|
|
|
If the mode of the predicate is given in the @code{:- pred} declaration
|
|
rather than in a separate @code{:- mode} declaration,
|
|
then the determinism annotation goes on the @code{:- pred} declaration
|
|
(and similarly for functions).
|
|
In particular, this is necessary
|
|
if a predicate does not have any argument variables.
|
|
If the determinism declaration is given on a @code{:- func} declaration
|
|
without the mode, the function is assumed to have the default mode
|
|
(see @ref{Modes} for more information on default modes of functions).
|
|
|
|
For example:
|
|
|
|
@example
|
|
:- pred loop(int::in) is erroneous.
|
|
loop(X) :- loop(X).
|
|
|
|
:- pred p is det.
|
|
p.
|
|
|
|
:- pred q is failure.
|
|
q :- fail.
|
|
@end example
|
|
|
|
If there is no mode declaration for a function, then the default
|
|
mode for that function is considered to have been declared as @samp{det}.
|
|
If you want to write a partial function, i.e. one whose determinism
|
|
is @samp{semidet}, then you must explicitly declare the mode and determinism.
|
|
|
|
In Mercury, a function is supposed to be a true mathematical function
|
|
of its arguments; that is, the value of the function's result should
|
|
be determined only by the values of its arguments. Hence, for
|
|
any mode of a function that specifies that all the arguments are fully
|
|
input (i.e. for which the initial inst of all the arguments is a ground inst),
|
|
the determinism of that mode can only be
|
|
@samp{det}, @samp{semidet}, @samp{erroneous}, or @samp{failure}.
|
|
|
|
The determinism categories form this lattice:
|
|
|
|
@example
|
|
erroneous
|
|
/ \
|
|
failure det
|
|
\ / \
|
|
semidet multi
|
|
\ /
|
|
nondet
|
|
@end example
|
|
|
|
The higher up this lattice a determinism category is,
|
|
the more the compiler knows about the number of solutions
|
|
of procedures of that determinism.
|
|
|
|
@node Determinism checking and inference
|
|
@section Determinism checking and inference
|
|
|
|
The determinism of goals
|
|
is inferred from the determinism of their component parts,
|
|
according to the rules below.
|
|
The inferred determinism of a procedure is just the inferred
|
|
determinism of the procedure's body.
|
|
|
|
For procedures that are local to a module,
|
|
the determinism annotations may be omitted;
|
|
in that case, their determinism will be inferred.
|
|
(To be precise, the determinism of procedures without a determinism annotation
|
|
is defined as the least fixpoint of the transformation which,
|
|
given an initial assignment
|
|
of the determinism @code{det} to all such procedures,
|
|
applies those rules to infer
|
|
a new determinism assignment for those procedures.)
|
|
|
|
It is an error to omit the determinism annotation
|
|
for procedures that are exported from their containing module.
|
|
|
|
If a determinism annotation is supplied for a procedure,
|
|
the declared determinism is compared against the inferred determinism.
|
|
If the declared determinism is greater than or not comparable to the
|
|
inferred determinism (in the partial ordering above), it is an error.
|
|
If the declared determinism is less than the inferred determinism,
|
|
it is not an error, but the implementation may issue a warning.
|
|
|
|
The determinism category of each goal
|
|
is inferred according to the following rules.
|
|
These rules work with the two components of determinism category:
|
|
whether the goal can fail without producing a solution,
|
|
and the maximum number of solutions of the goal (0, 1, or more).
|
|
If the inference process below reports that a goal can succeed more than once,
|
|
but the goal generates no outputs that are visible from outside the goal,
|
|
and the goal is not impure (@pxref{Impurity}),
|
|
then the final determinism of the goal
|
|
will be based on the goal succeeding at most once,
|
|
since the compiler will implicitly prune away any duplicate solutions.
|
|
|
|
@table @asis
|
|
@item Calls
|
|
The determinism category of a call is the determinism
|
|
declared or inferred for the called mode of the called procedure.
|
|
|
|
@item Unifications
|
|
The determinism of a unification
|
|
is either @code{det}, @code{semidet}, or @code{failure},
|
|
depending on its mode.
|
|
|
|
A unification that assigns the value of one variable to another
|
|
is deterministic.
|
|
A unification that constructs a structure and assigns it to a variable
|
|
is also deterministic.
|
|
A unification that tests whether a variable has a given top function symbol
|
|
is semideterministic,
|
|
unless the compiler knows the top function symbol of that variable,
|
|
in which case its determinism is either det or failure
|
|
depending on whether the two function symbols are the same or not.
|
|
A unification that tests two variables for equality
|
|
is semideterministic,
|
|
unless the compiler knows that the two variables are aliases for one another,
|
|
in which case the unification is deterministic,
|
|
or unless the compiler knows that the two variables
|
|
have different function symbols in the same position,
|
|
in which case the unification has a determinism of failure.
|
|
|
|
The compiler knows the top function symbol of a variable
|
|
if the previous part of the procedure definition
|
|
contains a unification of the variable with a function symbol,
|
|
or if the variable's type has only one function symbol.
|
|
|
|
@item Conjunctions
|
|
The determinism of the empty conjunction (the goal @samp{true})
|
|
is @code{det}.
|
|
The conjunction @samp{(@var{A}, @var{B})} can fail
|
|
if either @var{A} can fail, or if @var{A} can succeed at least once,
|
|
and @var{B} can fail.
|
|
The conjunction can succeed at most zero times
|
|
if either @var{A} or @var{B} can succeed at most zero times.
|
|
The conjunction can succeed more than once
|
|
if either @var{A} or @var{B} can succeed more than once
|
|
and both @var{A} and @var{B} can succeed at least once.
|
|
(If e.g. @var{A} can succeed at most zero times,
|
|
then even if @var{B} can succeed many times
|
|
the maximum number of solutions of the conjunction is still zero.)
|
|
Otherwise, i.e. if both @var{A} and @var{B} succeed at most once,
|
|
the conjunction can succeed at most once.
|
|
|
|
@item Switches
|
|
A disjunction is a @emph{switch}
|
|
if each disjunct has near its start a unification that
|
|
tests the same bound variable against a different function symbol.
|
|
For example, consider the common pattern
|
|
|
|
@example
|
|
(
|
|
L = [], empty(Out)
|
|
;
|
|
L = [H|T], nonempty(H, T, Out)
|
|
)
|
|
@end example
|
|
|
|
If L is input to the disjunction, then the disjunction is a switch on L.
|
|
|
|
A switch can fail
|
|
if the various arms of the switch do not cover
|
|
all the function symbols in the type of the switched-on variable,
|
|
or if the code in some arms of the switch can fail,
|
|
bearing in mind that in each arm of the switch,
|
|
the unification that tests the switched-on variable
|
|
against the function symbol of that arm is considered to be deterministic.
|
|
A switch can succeed several times
|
|
if some arms of the switch can succeed several times,
|
|
possibly because there are multiple disjuncts
|
|
that test the switched-on variable against the same function symbol.
|
|
A switch can succeed at most zero times
|
|
only if all arms of the switch can succeed at most zero times.
|
|
|
|
Only unifications may occur before the test of the switched-on variable
|
|
in each disjunct. Tests of the switched-on variable may occur within
|
|
existential quantification goals.
|
|
|
|
The following example is a switch.
|
|
|
|
@example
|
|
(
|
|
Out = 1, L = []
|
|
;
|
|
some [H, T] (
|
|
L = [H|T],
|
|
nonempty(H, T, Out)
|
|
)
|
|
)
|
|
@end example
|
|
|
|
The following example is not a switch because the call in the first
|
|
disjunct occurs before the test of the switched-on variable.
|
|
|
|
@example
|
|
(
|
|
empty(Out), L = []
|
|
;
|
|
L = [H|T], nonempty(H, T, Out)
|
|
)
|
|
@end example
|
|
|
|
@item Disjunctions
|
|
The determinism of the empty disjunction (the goal @samp{fail})
|
|
is @code{failure}.
|
|
A disjunction @samp{(@var{A} ; @var{B})} that is not a switch
|
|
can fail if both @var{A} and @var{B} can fail.
|
|
It can succeed at most zero times
|
|
if both @var{A} and @var{B} can succeed at most zero times.
|
|
It can succeed at most once
|
|
if one of @var{A} and @var{B} can succeed at most once
|
|
and the other can succeed at most zero times.
|
|
Otherwise, i.e. if either @var{A} or @var{B} can succeed more than once,
|
|
or if both @var{A} and @var{B} can succeed at least once,
|
|
it can succeed more than once.
|
|
|
|
@c The local determinism of a disjunction is @code{nondet} unless the
|
|
@c compiler can detect that the disjunction is actually a switch and
|
|
@c hence @dfn{index} the disjunction.
|
|
@c Precisely describing the rules for detecting switches is somewhat tricky,
|
|
@c and I won't attempt to do so, but they are
|
|
@c reasonable easy to understand in practice.
|
|
@c The compiler can index on any input variable to a disjunction
|
|
@c (not just the first head variable). It can also index on more than
|
|
@c one variable, since after indexing on the first one, switch detection is
|
|
@c applied to all sub-disjunctions. It can index on any functor, not
|
|
@c just the top-most one.
|
|
|
|
@item If-then-else
|
|
|
|
If the condition of an if-then-else cannot fail, the if-then-else
|
|
is equivalent to the conjunction of the condition and the ``then'' part,
|
|
and its determinism is computed accordingly.
|
|
Otherwise,
|
|
an if-then-else can fail if either the ``then'' part or the ``else'' part
|
|
can fail.
|
|
It can succeed at most zero times
|
|
if the ``else'' part can succeed at most zero times
|
|
and if at least one of the condition and the ``then'' part
|
|
can succeed at most zero times.
|
|
It can succeed more than once
|
|
if any one of the condition, the ``then'' part and the ``else'' part
|
|
can succeed more than once.
|
|
|
|
@item Negations
|
|
|
|
If the determinism of the negated goal is @code{erroneous},
|
|
then the determinism of the negation is @code{erroneous}.
|
|
If the determinism of the negated goal is @code{failure},
|
|
the determinism of the negation is @code{det}.
|
|
If the determinism of the negated goal is @code{det} or @code{multi},
|
|
the determinism of the negation is @code{failure}.
|
|
Otherwise, the determinism of the negation is @code{semidet}.
|
|
|
|
@end table
|
|
|
|
@node Replacing compile-time checking with run-time checking
|
|
@section Replacing compile-time checking with run-time checking
|
|
|
|
Note that ``perfect'' determinism inference is an undecidable problem,
|
|
because it requires solving the halting problem.
|
|
(For instance, in the following example
|
|
|
|
@example
|
|
:- pred p(T, T).
|
|
:- mode p(in, out) is det.
|
|
|
|
p(A, B) :-
|
|
(
|
|
something_complicated(A, B)
|
|
;
|
|
B = A
|
|
).
|
|
@end example
|
|
|
|
@noindent
|
|
@samp{p/2} can have more than one solution
|
|
only if @samp{something_complicated} can succeed.)
|
|
Sometimes, the rules specified by the Mercury language
|
|
for determinism inference will infer a determinism
|
|
that is not as precise as you would like.
|
|
However, it is generally easy to overcome such problems.
|
|
The way to do this is to replace the compiler's static checking
|
|
with some manual run-time checking.
|
|
For example, if you know that a particular goal should never fail,
|
|
but the compiler infers that goal to be @code{semidet},
|
|
you can check at runtime that the goal does succeed,
|
|
and if it fails, call the library predicate @samp{error/1}.
|
|
|
|
@example
|
|
:- pred q(T, T).
|
|
:- mode q(in, out) is det.
|
|
|
|
q(A, B) :-
|
|
( goal_that_should_never_fail(A, B0) ->
|
|
B = B0
|
|
;
|
|
error("goal_that_should_never_fail failed!")
|
|
).
|
|
@end example
|
|
|
|
@noindent
|
|
The predicate @code{error/1} has determinism @code{erroneous},
|
|
which means the compiler knows that it will never succeed or fail,
|
|
so the inferred determinism for the body of @code{q/2} is @code{det}.
|
|
(Checking assumptions like this is good coding style anyway.
|
|
The small amount of up-front work that Mercury requires
|
|
is paid back in reduced debugging time.)
|
|
Mercury's mode analysis knows that
|
|
computations with determinism erroneous can never succeed,
|
|
which is why it does not require the ``else'' part to generate
|
|
a value for @samp{B}.
|
|
The introduction of the new variable @samp{B0} is necessary
|
|
because the condition of an if-then-else is a negated context,
|
|
and can export the values it generates
|
|
only to the ``then'' part of the if-then-else,
|
|
not directly to the surrounding computation.
|
|
(If the surrounding computations had direct access
|
|
to values generated in conditions,
|
|
they might access them even if the condition failed.)
|
|
|
|
@node Interfacing nondeterministic code with the real world
|
|
@section Interfacing nondeterministic code with the real world
|
|
|
|
Normally, attempting to call
|
|
a @code{nondet} or @code{multi} mode of a predicate
|
|
from a predicate declared as @code{semidet} or @code{det}
|
|
will cause a determinism error.
|
|
So how can we call nondeterministic code from deterministic code?
|
|
There are several alternative possibilities.
|
|
|
|
If you just want to see if a nondeterministic goal is satisfiable or not,
|
|
without needing to know what variable bindings it produces,
|
|
then there is no problem -
|
|
determinism analysis considers @code{nondet} and @code{multi} goals
|
|
with no non-local output variables to be
|
|
@code{semidet} and @code{det} respectively.
|
|
|
|
If you want to use the values of output variables,
|
|
then you need to ask yourself
|
|
which one of possibly many solutions to a goal do you want?
|
|
If you want all of them, you need to use the predicate
|
|
@samp{solutions/2} in the standard library module @samp{std_util},
|
|
which collects all of the solutions to a goal into a list --
|
|
@pxref{Higher-order}.
|
|
|
|
If you just want one solution and don't care which,
|
|
the calling predicate should be declared @code{nondet} or @code{multi}.
|
|
The nondeterminism should then be propagated up the call tree
|
|
to the point at which it can be pruned.
|
|
In Mercury, pruning can be achieved in several ways.
|
|
|
|
The first way is the one mentioned above:
|
|
if a goal has no non-local output variables
|
|
then the implementation will only attempt to satisfy the goal once.
|
|
Any potential duplicate solutions will be implicitly pruned away.
|
|
|
|
The second way is to rely on the fact that
|
|
the implementation will only seek a single solution to @samp{main/2},
|
|
so alternative solutions to @samp{main/2}
|
|
(and hence also to @code{nondet} or @code{multi} predicates
|
|
called directly or indirectly from @samp{main/2})
|
|
are implicitly pruned away.
|
|
This is one way to achieve ``don't care'' style nondeterminism in Mercury.
|
|
|
|
The other situation in which you may want pruning
|
|
and committed choice style nondeterminism
|
|
is when you know that all the solutions returned will be equivalent.
|
|
For example, you might want to find the maximum element in a set
|
|
by iterating over the elements in the set.
|
|
Iterating over the elements in a set in an unspecified order is a
|
|
nondeterministic operation,
|
|
but no matter which order you remove them,
|
|
the maximum value in the set should be the same.
|
|
|
|
If you know that there will only ever be at most one distinct
|
|
solution, then you can use the function
|
|
@samp{promise_only_solution/1}, which is defined
|
|
as a builtin function in the Mercury standard library.
|
|
|
|
@example
|
|
:- func promise_only_solution(pred(T)) = T.
|
|
:- mode promise_only_solution(pred(out) is cc_multi) = out is det.
|
|
:- mode promise_only_solution(pred(out) is cc_nondet) = out is semidet.
|
|
@end example
|
|
|
|
@noindent
|
|
A call to that function, e.g. @samp{promise_only_solution(Pred)}, constitutes a
|
|
promise on the part of the caller that the argument @samp{Pred} has at most
|
|
one solution, i.e. that
|
|
|
|
@example
|
|
not some [X1, X2] (Pred(X1), Pred(X2), X1 \= X2)
|
|
@end example
|
|
|
|
@noindent
|
|
holds. @samp{promise_only_solution(Pred)} presumes that this
|
|
assumption is satisfied, and returns the value of @samp{X} for which
|
|
@samp{Pred(X)} is true, if any. If the assumption is not
|
|
satisfied, then the behaviour is undefined.
|
|
|
|
Note that specifying a user-defined equivalence relation
|
|
as the equality predicate for user-defined types (@pxref{Equality preds})
|
|
means that the @samp{promise_only_solution/1} function
|
|
can be used to express more general forms of equivalence.
|
|
For example, if you define a set type which represents sets as unsorted lists,
|
|
you would want to define a user-defined equivalence relation for that type,
|
|
which could sort the lists before comparing them.
|
|
The @samp{promise_only_solution/1} function could then be used for sets
|
|
even though the lists used to represent the sets
|
|
might not be in the same order in every solution.
|
|
|
|
@node Committed choice nondeterminism
|
|
@section Committed choice nondeterminism
|
|
|
|
In addition to the determinism annotations described earlier, there are
|
|
``committed choice'' versions of @code{multi}
|
|
and @code{nondet}, called @code{cc_multi} and @code{cc_nondet}.
|
|
These can be used instead of @code{multi} or @code{nondet} if all calls
|
|
to that mode of the predicate (or function) occur in a context in
|
|
which only one solution is needed.
|
|
|
|
Such single-solution contexts are determined as follows.
|
|
|
|
@itemize @bullet
|
|
@item
|
|
The body of any procedure declared @code{cc_multi} or
|
|
@code{cc_nondet} is in a single-solution context.
|
|
For example, the program entry point @samp{main/2} may
|
|
be declared @code{cc_multi}, and in that case the clauses
|
|
for @code{main} are in a single-solution context.
|
|
|
|
@item
|
|
Any goal with no output variables is in a single-solution context.
|
|
|
|
@item
|
|
If a conjunction is in a single-solution context, then
|
|
the right-most conjunct is in a single-solution context,
|
|
and if the right-most conjunct cannot fail,
|
|
then rest of the conjunction is also in a single-solution
|
|
context.
|
|
("Right-most" here refers to the order @emph{after} mode reordering.)
|
|
|
|
@item
|
|
If an if-then-else is in a single-solution context, then the
|
|
``then'' part and the ``else'' part are in single-solution contexts,
|
|
and if the ``then'' part cannot fail, then the condition of the
|
|
if-then-else is also in a single-solution context.
|
|
|
|
@item
|
|
For other compound goals, i.e. disjunctions, negations, and
|
|
(explicitly) existentially quantified goals, if the compound goal
|
|
is in a single-solution context, then the immediate sub-goals of that
|
|
compound goal are also in single-solution contexts.
|
|
|
|
@end itemize
|
|
|
|
The compiler will check that all calls to a committed-choice
|
|
mode of a predicate (or function) do indeed occur in a single-solution context.
|
|
|
|
You can declare two different modes of a predicate (or function) which differ
|
|
only in ``cc-ness'' (i.e. one being @samp{multi} and the other
|
|
@samp{cc_multi}, or one being @samp{nondet} and the other @samp{cc_nondet}).
|
|
In that case, the compiler will select the appropriate one for each
|
|
call depending on whether the call comes from a single-solution context
|
|
or not. Calls from single-solution contexts will call the committed
|
|
choice version, while calls which are not from single-solution contexts
|
|
will call the backtracking version.
|
|
|
|
There are several reasons to use committed choice determinism annotations.
|
|
One reason is for efficiency: committed choice annotations allow
|
|
the compiler to generate much more efficient code.
|
|
Another reason is for doing I/O, which is allowed only in @samp{det}
|
|
or @samp{cc_multi} predicates, not in @samp{multi} predicates.
|
|
Another is for dealing with types that use non-canonical representations
|
|
(@pxref{Equality preds}).
|
|
And there are a variety of other applications.
|
|
|
|
@c XXX fix semantics for I/O + committed choice + mode inference
|
|
|
|
@c @node Assertions
|
|
@c @chapter Assertions
|
|
@c
|
|
@c Mercury supports the declaration of laws that hold for predicates and
|
|
@c functions.
|
|
@c These laws are only checked for type-correctness,
|
|
@c it is the responsibility of the programmer to ensure overall correctness.
|
|
@c The behaviour of programs with incorrect laws is undefined.
|
|
@c
|
|
@c A new law is introduced with the @samp{:- assertion} declaration.
|
|
@c
|
|
@c Here are some examples of @samp{:- assertion} declarations.
|
|
@c The following example declares the function @samp{+} to be commutative.
|
|
@c
|
|
@c @example
|
|
@c :- assertion
|
|
@c all [A,B,R] (
|
|
@c R = A + B
|
|
@c <=>
|
|
@c R = B + A
|
|
@c ).
|
|
@c @end example
|
|
@c
|
|
@c Note that each variable in the declaration was explicitly quantified.
|
|
@c The current Mercury compiler requires that each assertion begins with
|
|
@c an @samp{all} quantification, and that every variable is explicitly
|
|
@c quantified.
|
|
@c
|
|
@c Here is a more complicated declaration. It declares that @samp{append} is
|
|
@c associative.
|
|
@c
|
|
@c @example
|
|
@c :- assertion
|
|
@c all [A,B,C,ABC] (
|
|
@c (some [AB] (append(A, B, AB), append(AB, C, ABC)))
|
|
@c <=>
|
|
@c (some [BC] (append(B, C, BC), append(A, BC, ABC)))
|
|
@c ).
|
|
@c @end example
|
|
|
|
@node Equality preds
|
|
@chapter User-defined equality predicates
|
|
|
|
When defining abstract data types,
|
|
often it is convenient to use a non-canonical representation ---
|
|
that is, one for which a single abstract value may have more than
|
|
one different possible concrete representations.
|
|
For example, you may wish to implement an abstract type @samp{set}
|
|
by representing a set as an (unsorted) list.
|
|
|
|
@example
|
|
:- module set_as_unsorted_list.
|
|
:- interface.
|
|
:- type set(T).
|
|
|
|
:- implementation.
|
|
:- import_module list.
|
|
:- type set(T) ---> set(list(T)).
|
|
@end example
|
|
|
|
@noindent
|
|
In this example, the concrete representations @samp{set([1,2])} and
|
|
@samp{set([2,1])} would both represent the same abstract value, namely
|
|
the set containing the elements 1 and 2.
|
|
|
|
For types such as this, which do not have a canonical representation,
|
|
the standard definition of equality is not the desired one; we want equality on
|
|
sets to mean equality of the abstract values, not equality of their
|
|
representations. To support such types, Mercury allows programmers to
|
|
specify a user-defined equality predicate for user-defined types:
|
|
|
|
@example
|
|
:- type set(T) ---> set(list(T))
|
|
where equality is set_equals.
|
|
@end example
|
|
|
|
@noindent
|
|
Here @samp{set_equals} is the name of a user-defined predicate that
|
|
is used for equality on the type @samp{set(T)}. It could for example
|
|
be defined in terms of a @samp{subset} predicate.
|
|
|
|
@example
|
|
:- pred set_equals(set(T)::in, set(T)::in) is semidet.
|
|
set_equals(S1, S2) :-
|
|
subset(S1, S2),
|
|
subset(S2, S1).
|
|
@end example
|
|
|
|
A type declaration for a type @samp{foo(T1, @dots{}, TN)} may contain a
|
|
@samp{where equality is @var{equalitypred}} specification only
|
|
if the following conditions are satisfied:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
The type @samp{foo(T1, @dots{}, TN)} must be a discriminated union type;
|
|
it may not be an equivalence type
|
|
|
|
@item
|
|
@var{equalitypred} must be the name of a predicate which can
|
|
be called with two ground arguments of type @samp{pred(foo(T1, @dots{}, TN))},
|
|
and whose determinism in that mode is @samp{semidet}.
|
|
Typically the equality predicate would have type
|
|
@samp{pred(foo(T1, @dots{}, TN), foo(T1, @dots{}, TN)}
|
|
and mode @samp{(in, in) is semidet}, but it is also legal
|
|
for the type, mode and determinism to be more permissive:
|
|
the type or the mode's initial insts may be more general
|
|
(e.g. the type could be just the polymorphic type @samp{pred(T, T)})
|
|
and the mode's final insts or the determinism may be more
|
|
specific (e.g. the determinism could be any of @samp{det},
|
|
@samp{failure} or @samp{erroneous}).
|
|
The equality predicate must also be ``pure'' (@pxref{Impurity}).
|
|
|
|
@end itemize
|
|
|
|
Types with user-defined equality can only be used in limited ways.
|
|
Because there multiple representations for the same abstract
|
|
value, any attempt to examine the representation of such a value
|
|
is a conceptually non-deterministic operation.
|
|
In Mercury this is modelled using committed choice nondeterminism.
|
|
|
|
The semantics of a specifying @samp{where equality is @var{equalitypred}}
|
|
on the type declaration for a type @var{T} are as follows:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
If the program contains any deconstruction unification or switch
|
|
on a variable of type @var{T} that could fail, other than unifications
|
|
with mode @samp{(in, in)}, then it is a compile-time error.
|
|
|
|
@item
|
|
If the program contains any deconstruction unification or switch
|
|
on a variable of type @var{T} that cannot fail, then that operation
|
|
has determinism @samp{cc_multi}.
|
|
|
|
@item
|
|
Any attempts to examine the representation of a variable of type @var{T}
|
|
using facilities of the standard library (e.g. @samp{argument}/3
|
|
and @samp{functor/3} in @samp{std_util}) that do not have determinism
|
|
@samp{cc_multi} or @samp{cc_nondet} will result in a run-time error.
|
|
|
|
@item
|
|
In addition to the usual equality axioms,
|
|
the declarative semantics of the program will contain the axiom
|
|
@samp{@var{X} = @var{Y} <=> @var{equalitypred}(X, Y)} for all
|
|
@var{X} and @var{Y} of type @samp{T}.
|
|
|
|
@item
|
|
Any @samp{(in, in)} unifications for type @var{T} are computed using the
|
|
specified predicate @var{equalitypred}.
|
|
|
|
@item
|
|
@var{equalitypred} should be an equivalence relation; that is, it must be
|
|
symmetric, reflexive, and transitive. However, the compiler is not required
|
|
to check this@footnote{If @var{equalitypred} is not an equivalence relation,
|
|
then the program is inconsistent: its declarative semantics
|
|
contains a contradiction, because the additional axioms for the user-defined
|
|
equality contradict the standard equality axioms. That implies that the
|
|
implementation may compute any answer at all (@pxref{Semantics}),
|
|
i.e. the behaviour of the program is undefined.}.
|
|
|
|
@end itemize
|
|
|
|
@node Higher-order
|
|
@chapter Higher-order programming
|
|
|
|
Mercury supports higher-order functions and predicates with currying,
|
|
closures, and lambda expressions.
|
|
(To be pedantic, it would be more accurate to
|
|
say that Mercury supports higher-order procedures: in Mercury, when you
|
|
construct a higher-order term, you only get one mode of
|
|
a predicate or function; if you want multiple modes, you must pass multiple
|
|
higher-order procedures.)
|
|
|
|
@menu
|
|
* Creating higher-order terms::
|
|
* Calling higher-order terms::
|
|
* Higher-order modes::
|
|
@end menu
|
|
|
|
@node Creating higher-order terms
|
|
@section Creating higher-order terms
|
|
@c NB. This section is pointed to by an error message in compiler/typecheck.m,
|
|
@c so if you change the section name, you need to update that error message.
|
|
|
|
To create a higher-order predicate or function term, you can use
|
|
a lambda expression, or, if the predicate or function has only one
|
|
mode and it is not a zero-arity function, you can just use its name.
|
|
For example, if you have declared a predicate
|
|
|
|
@example
|
|
:- pred sum(list(int), int).
|
|
:- mode sum(in, out) is det.
|
|
@end example
|
|
|
|
@noindent
|
|
the following three unifications have the same effect:
|
|
|
|
@example
|
|
X = lambda([List::in, Length::out] is det, sum(List, Length))
|
|
Y = (pred(List::in, Length::out) is det :- sum(List, Length))
|
|
Z = sum
|
|
@end example
|
|
|
|
In the above example, the type of @samp{X}, @samp{Y}, and @samp{Z} is
|
|
@samp{pred(list(int), int)}, which means a predicate of two
|
|
arguments of types @samp{list(int)} and @samp{int} respectively.
|
|
|
|
The syntax using @samp{lambda} is deprecated;
|
|
please use the syntax using @samp{pred} instead.
|
|
[The syntax using @samp{lambda} was supported to enable programs to work
|
|
in both Mercury and Prolog, because the syntax using @samp{pred}
|
|
can't be easily emulated in Prolog. Now that we have implemented
|
|
better debugging environments for Mercury, there is no need for this.]
|
|
|
|
Similarly, given
|
|
|
|
@example
|
|
:- func scalar_product(int, list(int)) = list(int).
|
|
:- mode scalar_product(in, in) = out is det.
|
|
@end example
|
|
|
|
@noindent
|
|
the following three unifications have the same effect:
|
|
|
|
@example
|
|
X = (func(Num, List) = NewList :- NewList = scalar_product(Num, List))
|
|
Y = (func(Num::in, List::in) = (NewList::out) is det
|
|
:- NewList = scalar_product(Num, List))
|
|
Z = scalar_product
|
|
@end example
|
|
|
|
In the above example, the type of @samp{X}, @samp{Y}, and @samp{Z} is
|
|
@samp{func(int, list(int)) = list(int)}, which means a function of two
|
|
arguments, whose types are @samp{int} and @samp{list(int)},
|
|
with a return type of @samp{int}.
|
|
As with @samp{:- func} declarations, if the modes and determinism
|
|
of the function are omitted in a higher-order function term, then
|
|
the modes default to @samp{in} for the arguments, @samp{out} for the
|
|
function result, and the determinism defaults to @samp{det}.
|
|
|
|
If the predicate or function has more than one mode, you must use an explicit
|
|
lambda expression to specify which mode you want.
|
|
|
|
You can also create higher-order function terms of non-zero arity
|
|
and higher-order predicate terms by ``currying'',
|
|
i.e. specifying the first few arguments to a predicate or function, but
|
|
leaving the remaining arguments unspecified. For example, the
|
|
unification
|
|
|
|
@example
|
|
Sum123 = sum([1,2,3])
|
|
@end example
|
|
|
|
@noindent
|
|
binds @samp{Sum123} to a higher-order predicate term of type @samp{pred(int)}.
|
|
Similarly, the unification
|
|
|
|
@example
|
|
Double = scalar_product(2)
|
|
@end example
|
|
|
|
@noindent
|
|
binds @samp{Double} to a higher-order function term of type
|
|
@samp{func(list(int)) = list(int)}.
|
|
|
|
For higher-order predicate expressions that thread an accumulator
|
|
pair, we have syntax that allows you to use DCG notation in the
|
|
goal of the expression. For example,
|
|
|
|
@example
|
|
Pred = (pred(Strings::in, Num::out, di, uo) is det -->
|
|
io__write_string("The strings are: "),
|
|
@{ list__length(Strings, Num) @},
|
|
io__write_strings(Strings),
|
|
io__nl
|
|
)
|
|
@end example
|
|
|
|
@noindent
|
|
is equivalent to
|
|
|
|
@example
|
|
Pred = (pred(Strings::in, Num::out, IO0::di, IO::uo) is det :-
|
|
io__write_string("The strings are: ", IO0, IO1),
|
|
list__length(Strings, Num),
|
|
io__write_strings(Strings, IO1, IO2),
|
|
io__nl(IO2, IO)
|
|
)
|
|
@end example
|
|
|
|
Higher-order function terms of zero arity can only be created using
|
|
an explicit lambda expression; you have to use e.g. @samp{(func) = foo}
|
|
rather than plain @samp{foo}, because the latter denotes the result
|
|
of evaluating the function, rather than the function itself.
|
|
|
|
Note that when constructing a higher-order term, you cannot just use
|
|
the name of a builtin language construct such as @samp{=}, @samp{\=},
|
|
@samp{call}, or @samp{apply}, and nor can such constructs be curried.
|
|
Instead, you must either use an explicit lambda expression,
|
|
or you must write a forwarding predicate or function.
|
|
For example, instead of
|
|
|
|
@example
|
|
list__filter([1,2,3], \=(2), List)
|
|
@end example
|
|
|
|
@noindent
|
|
you must write either
|
|
|
|
@example
|
|
list__filter([1,2,3], (pred(X::in) is semidet :- X \= 2), List)
|
|
@end example
|
|
|
|
@noindent
|
|
or
|
|
|
|
@example
|
|
list__filter([1,2,3], not_equal(2), List)
|
|
@end example
|
|
|
|
@noindent
|
|
where you have defined @samp{not_equal} using
|
|
|
|
@example
|
|
:- pred not_equal(T::in, T::in) is semidet.
|
|
not_equal(X, Y) :- X \= Y.
|
|
@end example
|
|
|
|
Another case when this arises is when want to curry a higher-order
|
|
term. Suppose, for example, that you have a higher-order predicate
|
|
term @samp{OldPred} of type @samp{pred(int, char, float)}, and you want
|
|
to construct a new higher-order predicate term @samp{NewPred} of type
|
|
@samp{pred(char, float)} from @samp{OldPred} by supplying a value for
|
|
for just the first argument. The solution is the same: use
|
|
an explicit lambda expression or a forwarding predicate.
|
|
In either case, the body of the lambda expression or the forwarding
|
|
predicate must contain a higher-order call with all the arguments
|
|
supplied.
|
|
|
|
@node Calling higher-order terms
|
|
@section Calling higher-order terms
|
|
|
|
Once you have created a higher-order predicate term (sometimes known
|
|
as a closure), the next thing you want to do is to call it.
|
|
For predicates, you use the builtin goal call/N:
|
|
|
|
@table @asis
|
|
@item @code{call(Closure)}
|
|
@itemx @code{call(Closure1, Arg1)}
|
|
@itemx @code{call(Closure2, Arg1, Arg2)}
|
|
@itemx @dots{}
|
|
A higher-order predicate call. @samp{call(Closure)} just calls the
|
|
specified higher-order predicate term. The other forms append the
|
|
specified arguments onto the argument list of the closure before
|
|
calling it.
|
|
@end table
|
|
|
|
For example, the goal
|
|
|
|
@example
|
|
call(Sum123, Result)
|
|
@end example
|
|
|
|
@noindent
|
|
would bind @samp{Result} to the sum of @samp{[1, 2, 3]}, i.e. to 6.
|
|
|
|
For functions, you use the builtin expression apply/N:
|
|
|
|
@table @asis
|
|
@item @code{apply(Closure)}
|
|
@itemx @code{apply(Closure1, Arg1)}
|
|
@itemx @code{apply(Closure2, Arg1, Arg2)}
|
|
@itemx @dots{}
|
|
A higher-order function application. Such a term denotes the
|
|
result of invoking the specified higher-order function term with
|
|
the specified arguments.
|
|
@end table
|
|
|
|
For example, given the definition of @samp{Double} above, the goal
|
|
|
|
@example
|
|
List = apply(Double, [1, 2, 3])
|
|
@end example
|
|
|
|
@noindent
|
|
would be equivalent to
|
|
|
|
@example
|
|
List = scalar_product(2, [1, 2, 3])
|
|
@end example
|
|
|
|
@noindent
|
|
and so for a suitable implementation of the function
|
|
@samp{scalar_product/2} this would bind @samp{List} to
|
|
@samp{[2, 4, 6]}.
|
|
|
|
One extremely useful higher-order predicate in the Mercury standard
|
|
library is @code{solutions/2}, which has the following declaration:
|
|
|
|
@example
|
|
:- pred solutions(pred(T), list(T)).
|
|
:- mode solutions(pred(out) is nondet, out) is det.
|
|
@end example
|
|
|
|
The term which you pass to @samp{solutions/2} is a higher-order
|
|
predicate term. You can pass the name of a one-argument predicate,
|
|
or you can pass a several-argument predicate with all but one
|
|
of the arguments supplied (a closure). The declarative semantics of
|
|
@samp{solutions/2} can be defined as follows:
|
|
|
|
@example
|
|
solutions(Pred, List) is true iff
|
|
all [X] (call(Pred, X) <=> list__member(X, List))
|
|
and List is sorted.
|
|
@end example
|
|
|
|
@noindent
|
|
where @samp{call(Pred, X)} invokes the higher-order predicate term
|
|
@samp{Pred} with argument @samp{X},
|
|
and where @samp{list__member/2} is the standard
|
|
library predicate for list membership. In other words,
|
|
@samp{solutions(Pred, List)} finds all the values of @samp{X}
|
|
for which @samp{call(Pred, X)} is true, collects these solutions
|
|
in a list, sorts the list, and returns that list as its result.
|
|
Here's an example: the standard library defines a predicate
|
|
@samp{list__perm(List0, List)}
|
|
|
|
@example
|
|
:- pred list__perm(list(T), list(T)).
|
|
:- mode list__perm(in, out) is nondet.
|
|
@end example
|
|
|
|
@noindent
|
|
which succeeds iff List is a permutation of List0.
|
|
Hence the following call to solutions
|
|
|
|
@example
|
|
solutions(list__perm([3,1,2]), L)
|
|
@end example
|
|
|
|
@noindent
|
|
should return all the possible permutations of the list @samp{[3,1,2]}
|
|
in sorted order:
|
|
|
|
@example
|
|
L = [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]].
|
|
@end example
|
|
|
|
See also @samp{unsorted_solutions/2} and @samp{solutions_set/2}, which
|
|
are defined in the standard library module @samp{std_util} and documented
|
|
in the Mercury Library Reference Manual.
|
|
|
|
@node Higher-order modes
|
|
@section Higher-order modes
|
|
|
|
In Mercury, the mode and determinism of a higher-order predicate or function
|
|
term are part of that term's @emph{inst}, not its @emph{type}.
|
|
This allows a single higher-order predicate to work on argument
|
|
predicates of different modes and determinism, which is particularly
|
|
useful for library predicates such as @samp{list__map} and @samp{list__foldl}.
|
|
|
|
The language contains builtin @samp{inst} values
|
|
|
|
@example
|
|
pred is @var{Determinism}
|
|
pred(@var{Mode}) is @var{Determinism}
|
|
pred(@var{Mode1}, @var{Mode2}) is @var{Determinism}
|
|
@dots{}
|
|
(func) = @var{Mode} is @var{Determinism}
|
|
func(@var{Mode1}) = @var{Mode} is @var{Determinism}
|
|
func(@var{Mode1}, @var{Mode2}) = @var{Mode} is @var{Determinism}
|
|
@dots{}
|
|
@end example
|
|
|
|
These insts represent the instantiation state of variables bound
|
|
to higher-order predicate and function terms with the appropriate mode
|
|
and determinism.
|
|
For example, @samp{pred(out) is det} represents the instantiation state
|
|
of being bound to a higher-order predicate term which is @samp{det}
|
|
and accepts one output argument; the term @samp{sum([1,2,3])} from the
|
|
example above is one such higher-order predicate term which matches
|
|
this instantiation state.
|
|
|
|
As a convenience, the language also contains builtin @samp{mode} values
|
|
of the same name (and they are what we have been using in the examples
|
|
up to now). These modes map from the corresponding @samp{inst} to
|
|
itself. It is as if they were defined by
|
|
|
|
@example
|
|
:- mode (pred is @var{Determinism}) :: in(pred is @var{Determinism}).
|
|
:- mode (pred(@var{Inst}) is @var{Determinism}) ::
|
|
in(pred(@var{Inst}) is @var{Determinism}).
|
|
@dots{}
|
|
@end example
|
|
|
|
@noindent
|
|
using the parametric inst @samp{in/1} mentioned in @ref{Modes}
|
|
which maps an inst to itself.
|
|
|
|
If you want to define a predicate which returns a higher-order predicate
|
|
term, you would use a mode such as @samp{free -> pred(@dots{}) is @dots{}},
|
|
or @samp{out(pred(@dots{}) is @dots{})}. For example:
|
|
|
|
@example
|
|
:- pred foo(pred(int)).
|
|
:- mode foo(free -> pred(out) is det) is det.
|
|
|
|
foo(sum([1,2,3])).
|
|
@end example
|
|
|
|
Note that in Mercury it is an error to attempt to unify two
|
|
higher-order terms. This is because equivalence of
|
|
higher-order terms is undecidable in the general case.
|
|
|
|
For example, given the definition of @samp{foo} above, the goal
|
|
|
|
@example
|
|
foo((pred(X::out) is det :- X = 6))
|
|
@end example
|
|
|
|
@noindent
|
|
is illegal. If you really want to compare higher-order predicates
|
|
for equivalence, you must program it yourself; for example,
|
|
the above goal could legally be written as
|
|
|
|
@example
|
|
P = (pred(X::out) is det :- X = 6),
|
|
foo(Q),
|
|
all [X] (call(P, X) <=> call(Q, X)).
|
|
@end example
|
|
|
|
Note that the compiler will only catch direct attempts at higher-order
|
|
unifications; indirect attempts (via polymorphic predicates, for
|
|
example @samp{(list__append([], [P], [Q])} may result in an error at
|
|
run-time rather than at compile-time.
|
|
|
|
@node Modules
|
|
@chapter Modules
|
|
|
|
@menu
|
|
* The module system::
|
|
* An example module::
|
|
* Sub-modules::
|
|
@end menu
|
|
|
|
@node The module system
|
|
@section The module system
|
|
|
|
The Mercury module system is relatively simple and straightforward.
|
|
|
|
Each module must start with a @samp{:- module @var{ModuleName}}
|
|
declaration, specifying the name of the module.
|
|
|
|
An @samp{:- interface.} declaration indicates
|
|
the start of the module's interface section:
|
|
this section specifies the entities that are exported by this module.
|
|
Mercury provides support for abstract data types, by allowing the
|
|
definition of a type to be kept hidden, with the interface
|
|
only exporting the type name.
|
|
The interface section may contain definitions of types,
|
|
type classes, data constructors, instantiation states, and
|
|
modes, and declarations for abstract data types, abstract type class
|
|
instances, functions, predicates, and (sub-)modules.
|
|
The interface section may not contain definitions for functions or
|
|
predicates (i.e. clauses), or definitions of (sub-)modules.
|
|
|
|
An @samp{:- implementation.} declaration indicates
|
|
the start of the module's implementation section.
|
|
Any entities declared in this section are local to the module
|
|
(and its sub-modules) and cannot be used by other modules.
|
|
The implementation section must contain definitions
|
|
for all abstract data types, abstract instance declarations,
|
|
functions, predicates, and sub-modules exported by the module,
|
|
as well as for all local types, type class instances, functions,
|
|
predicates, and sub-modules.
|
|
The implementation section can be omitted if it is empty.
|
|
|
|
The module may optionally end with a @samp{:- end_module @var{ModuleName}}
|
|
declaration; the name specified in the @samp{end_module} must be the
|
|
same as that in the corresponding @samp{module} declaration.
|
|
|
|
@c should we mention multipart interfaces and implementations?
|
|
@c ===> no
|
|
|
|
If a module wishes to make use of entities exported by other modules,
|
|
then it must explicitly import those modules using one or more
|
|
@samp{:- import_module @var{Modules}} or @samp{:- use_module @var{Modules}}
|
|
declarations, in order to make those declarations visible.
|
|
In both cases, @var{Modules} is a comma-separated list of
|
|
fully-qualified module names.
|
|
These declarations may occur either in the interface or the implementation
|
|
section. If the imported entities are used in the interface section,
|
|
then the corresponding @code{import_module} or @code{use_module}
|
|
declaration must also be in the interface section. If the imported
|
|
entities are only used in the implementation section, the
|
|
@code{import_module} or @code{use_module} declaration should be in
|
|
the implementation section.
|
|
|
|
The names of predicates, functions, constructors, constructor fields,
|
|
types, modes, insts, type classes,
|
|
and (sub-)modules can be explicitly module qualified using the @samp{:}
|
|
operator, e.g. @samp{module:name} or @samp{module:submodule:name}.
|
|
This is useful both for readability and for resolving name conflicts.
|
|
Uses of entities imported using @code{use_module} declarations
|
|
@emph{must} be explicitly module qualified.
|
|
|
|
Currently we also support @samp{__} as an alternative module qualifier,
|
|
so you can write @code{module__name} instead of @code{module:name}.
|
|
We are considering changing the module qualifier from @samp{:}
|
|
to @samp{.} in a future version, so that we can use @samp{:} as
|
|
a type qualifier instead. Hence for the time being we recommend
|
|
that you use @samp{__} rather than @samp{:} as module qualifier.
|
|
|
|
Certain optimizations require information or source code for predicates
|
|
defined in other modules to be as effective as possible. At the moment,
|
|
inlining and higher-order specialization are the only optimizations that
|
|
the Mercury compiler can perform across module boundaries.
|
|
|
|
One module must export a predicate @samp{main/2}, which
|
|
must be declared as either
|
|
|
|
@example
|
|
:- pred main(io__state::di, io__state::uo) is det.
|
|
@end example
|
|
|
|
@noindent
|
|
or
|
|
|
|
@example
|
|
:- pred main(io__state::di, io__state::uo) is cc_multi.
|
|
@end example
|
|
|
|
@noindent
|
|
(or any declaration equivalent to one of the two above).
|
|
|
|
Mercury has a standard library which includes modules for
|
|
lists, stacks, queues, priority queues, sets, bags (multi-sets),
|
|
maps (dictionaries), random number generation, input/output
|
|
and filename and directory handling.
|
|
See the Mercury Library Reference Manual for details.
|
|
|
|
@node An example module
|
|
@section An example module.
|
|
|
|
For illustrative purposes, here is the definition of a
|
|
simple module for managing queues:
|
|
|
|
@example
|
|
:- module queue.
|
|
:- interface.
|
|
|
|
% Declare an abstract data type.
|
|
|
|
:- type queue(T).
|
|
|
|
% Declare some predicates which operate on the abstract data type.
|
|
|
|
:- pred empty_queue(queue(T)).
|
|
:- mode empty_queue(out) is det.
|
|
:- mode empty_queue(in) is semidet.
|
|
|
|
:- pred put(queue(T), T, queue(T)).
|
|
:- mode put(in, in, out) is det.
|
|
|
|
:- pred get(queue(T), T, queue(T)).
|
|
:- mode get(in, out, out) is semidet.
|
|
|
|
:- implementation.
|
|
|
|
% Queues are implemented as lists. We need the `list' module
|
|
% for the declaration of the type list(T), with its constructors
|
|
% '[]'/0 % and '.'/2, and for the declaration of the predicate
|
|
% list__append/3.
|
|
|
|
:- import_module list.
|
|
|
|
% Define the queue ADT.
|
|
|
|
:- type queue(T) == list(T).
|
|
|
|
% Declare the exported predicates.
|
|
|
|
empty_queue([]).
|
|
|
|
put(Queue0, Elem, Queue) :-
|
|
list__append(Queue0, [Elem], Queue).
|
|
|
|
get([Elem | Queue], Elem, Queue).
|
|
|
|
:- end_module queue.
|
|
|
|
@end example
|
|
|
|
@node Sub-modules
|
|
@section Sub-modules
|
|
|
|
As mentioned above, modules may contain sub-modules.
|
|
There are two kinds of sub-modules, called nested sub-modules
|
|
and separate sub-modules; the difference is that nested sub-modules
|
|
are defined in the same source file as the containing module,
|
|
whereas separate sub-modules are defined in separate source files.
|
|
Implementations should support separate compilation of separate sub-modules.
|
|
|
|
A module may not contain more than one sub-module with the same name.
|
|
|
|
@menu
|
|
* Nested sub-modules::
|
|
* Separate sub-modules::
|
|
* Visibility rules::
|
|
* Implementation bugs and limitations::
|
|
@end menu
|
|
|
|
@node Nested sub-modules
|
|
@subsection Nested sub-modules
|
|
|
|
Nested sub-modules within a module are delimited by
|
|
matching @samp{:- module} and @samp{:- end_module} declarations.
|
|
(Note that @samp{:- end_module} for nested sub-modules
|
|
are mandatory, not optional, even if the nested sub-module
|
|
is the last thing in the source file.
|
|
Also note that the module name in a @samp{:- module} or @samp{:- end_module}
|
|
declaration need not be fully-qualified.)
|
|
The sequence of items thus delimited is known as a sub-module item sequence.
|
|
|
|
The interface and implementation parts of a nested sub-module
|
|
may be specified in two different sub-module declarations.
|
|
If a sub-module item sequence includes an interface section,
|
|
then it is a declaration of that sub-module;
|
|
if it includes an implementation section,
|
|
then it is a definition of that sub-module;
|
|
and if includes both, then it is both declaration and definition.
|
|
|
|
It is an error to declare a sub-module twice, or to define it twice.
|
|
It is an error to define a sub-module without declaring it.
|
|
If a sub-module is declared but not explicitly defined,
|
|
then there is an implicit definition with an empty implementation section
|
|
for that sub-module (this will result in an error, if the interface
|
|
section includes declarations but not definitions for any types,
|
|
predicates, modes, or (doubly) nested sub-modules).
|
|
|
|
@node Separate sub-modules
|
|
@subsection Separate sub-modules
|
|
|
|
Separate sub-modules are declared using
|
|
@samp{:- include_module @var{Modules}} declarations.
|
|
Each @samp{:- include_module} declaration specifies a comma-separated list
|
|
of sub-modules.
|
|
|
|
@example
|
|
:- include_module @var{Module1}, @var{Module2}, @dots{}, @var{ModuleN}.
|
|
@end example
|
|
|
|
Each of the named sub-modules in an @samp{:- include_module} declaration
|
|
must be defined in a separate source file.
|
|
The mapping between module names and source file names is
|
|
implementation-defined. (For a module named @samp{foo:bar:baz},
|
|
The University of Melbourne Mercury implementation requires the source
|
|
to be located in a file named @file{foo.bar.baz.m}, @file{bar.baz.m},
|
|
or @file{baz.m}.)
|
|
The separate source file must contain the declaration (interface)
|
|
and definition (implementation) of the sub-module.
|
|
It must start with a @samp{:- module} declaration
|
|
which matches that in the @samp{:- include_module} declaration
|
|
in the parent, followed by the interface and (if necessary)
|
|
implementation sections, and it may optionally end with a @samp{:- end_module}
|
|
declaration. (Note: the module names in the @samp{:- module},
|
|
@samp{:- end_module}, and @samp{:- include_module} declarations
|
|
need not be fully-qualified. However,
|
|
if the file name used for a particular module does
|
|
not include all the module qualifiers, then the University of Melbourne
|
|
Mercury implementation requires the module name in the @samp{:- module}
|
|
declaration for that module to be fully qualified.)
|
|
|
|
If an @samp{:- include_module} declaration occurs in the interface
|
|
section of a module, then only the declarations (interfaces) of the sub-modules
|
|
are included in the parent module's interface; the definitions
|
|
(implementations) of the sub-modules are considered to be implicitly
|
|
part of the parent module's implementation.
|
|
|
|
Apart from that, the semantics of separate sub-modules are
|
|
identical to those of nested sub-modules.
|
|
|
|
@node Visibility rules
|
|
@subsection Visibility rules
|
|
|
|
Any declarations in the parent module, including those in the
|
|
parent module's implementation section, are visible in the parent's
|
|
sub-modules, including indirect sub-modules (i.e. sub-sub-modules, etc.).
|
|
Similarly, declarations in the interfaces of any modules imported using an
|
|
@samp{:- import_module} or a @samp{:- use_module} in the parent module
|
|
are visible in the parent's sub-modules, including indirect sub-modules.
|
|
However, declarations in a child module are not visible in the parent
|
|
module or in "sibling" modules (other children of the same parent)
|
|
unless the child is explicitly imported using an @samp{:- import_module}
|
|
or @samp{:- use_module} declaration.
|
|
|
|
Note that as mentioned previously, all @samp{:- import_module} and
|
|
@samp{:- use_module} declarations must use fully-qualified module
|
|
names.
|
|
|
|
@node Implementation bugs and limitations
|
|
@subsection Implementation bugs and limitations
|
|
|
|
The current implementation of sub-modules has a couple of minor
|
|
limitations.
|
|
|
|
@itemize @bullet
|
|
@item
|
|
The compiler sometimes reports spurious errors if you
|
|
define an equivalence type in a sub-module and export it
|
|
as abstract type.
|
|
@item
|
|
When using nested modules,
|
|
the Mercury build tool Mmake sometimes tries to build things in the
|
|
wrong order and hence reports spurious errors about @samp{.int*} files
|
|
not being found. In these cases, simply typing @samp{mmake} again will
|
|
usually solve the problem. (If it doesn't, the work-around is
|
|
to use separate sub-modules rather than nested sub-modules, i.e. put
|
|
the sub-modules in a separate source file.)
|
|
@item
|
|
Using @samp{mmake} to do parallel makes (e.g. @samp{mmake --jobs 2})
|
|
doesn't always work correctly if you're using nested sub-modules.
|
|
(The work-around is to use separate sub-modules instead of nested
|
|
sub-modules, i.e. to put the sub-modules in separate source files.)
|
|
@end itemize
|
|
|
|
@node Type classes
|
|
@chapter Type classes
|
|
|
|
Mercury supports constrained polymorphism in the form of type classes.
|
|
Type classes allow the programmer to write predicates and functions which
|
|
operate on variables of any type (or sequence of types) for which a certain
|
|
set of operations is defined.
|
|
|
|
@menu
|
|
* Typeclass declarations::
|
|
* Instance declarations::
|
|
* Abstract instance declarations::
|
|
* Type class constraints on predicates and functions::
|
|
* Type class constraints on type class declarations::
|
|
* Type class constraints on instance declarations::
|
|
@end menu
|
|
|
|
@node Typeclass declarations
|
|
@section Typeclass declarations
|
|
|
|
A @dfn{type class} is a name for a set of types (or a set of sequences of
|
|
types) for which certain predicates and/or functions, called the @dfn{methods}
|
|
of that type class, are defined.
|
|
A @samp{typeclass} declaration defines a new type class, and
|
|
specifies the set of predicates and/or functions
|
|
that must be defined on a type (or sequence of types) for it (them) to be
|
|
considered to be an instance of that type class.
|
|
|
|
The @code{typeclass} declaration gives the name of the type class that
|
|
it is defining, the
|
|
names of the type variables which are parameters to the type class, and the
|
|
operations (i.e. methods) which form the interface of the type class.
|
|
|
|
For example,
|
|
|
|
@example
|
|
:- typeclass point(T) where [
|
|
% coords(Point, X, Y):
|
|
% X and Y are the cartesian coordinates of Point
|
|
pred coords(T, float, float),
|
|
mode coords(in, out, out) is det,
|
|
|
|
% translate(Point, X_Offset, Y_Offset) = NewPoint:
|
|
% NewPoint is Point translated X_Offset units in the X direction
|
|
% and Y_Offset units in the Y direction
|
|
func translate(T, float, float) = T
|
|
].
|
|
@end example
|
|
|
|
@noindent
|
|
declares the type class @code{point}, which
|
|
represents points in two dimensional space.
|
|
|
|
@code{pred}, @code{func} and @code{mode} declarations are the only legal
|
|
declarations inside a @code{typeclass} declaration. The number of parameters
|
|
to the type class (e.g. @code{T}) is not limited. For example, the following
|
|
is allowed:
|
|
|
|
@example
|
|
:- typeclass a(T1, T2) where [@dots{}].
|
|
@end example
|
|
|
|
The parameters must be distinct variables.
|
|
Each @code{typeclass} declaration must have at least one parameter.
|
|
|
|
It is OK for a @code{typeclass} declaration to declare no methods,
|
|
e.g.
|
|
|
|
@example
|
|
:- typeclass foo(T) where [].
|
|
@end example
|
|
|
|
There must not be more than one type class declaration with the
|
|
same name and arity in the same module.
|
|
|
|
@node Instance declarations
|
|
@section Instance declarations
|
|
|
|
Once the interface of the type class has been defined in the @code{typeclass}
|
|
declaration, we can use an @code{instance} declaration to define how a
|
|
particular type (or sequence of types) satisfies the interface declared
|
|
in the @code{typeclass} declaration.
|
|
|
|
An instance declaration has the form
|
|
|
|
@example
|
|
:- instance @var{classname}(@var{typename}(@var{typevar}, @dots{}), @dots{})
|
|
where [pred(@var{methodname}/@var{arity}) is @var{predname},
|
|
func(@var{methodname}/@var{arity}) is @var{funcname},
|
|
@dots{}].
|
|
@end example
|
|
|
|
An @samp{instance} declaration gives a type for each parameter of the
|
|
type class. Each of these types must be either a type with no arguments, or
|
|
a polymorphic type whose arguments are all distinct type variables.
|
|
For example @code{int}, @code{list(T)} and @code{bintree(K,V)} are allowed,
|
|
but @code{T}, @code{list(int)} and @code{bintree(T,T)} are not.
|
|
The types in an instance declaration must not be abstract types which
|
|
are elsewhere defined as equivalence types.
|
|
A program may not contain more than one @code{instance} declaration for a
|
|
particular type (or sequence of types, in the case of a multi-parameter
|
|
type class). These restrictions ensure that there are no overlapping instance
|
|
declarations, ie. there is at most one instance declaration that may be
|
|
applied to any type (or sequence of types).
|
|
|
|
Each entry in the @samp{where [@dots{}]} part of an @code{instance}
|
|
declaration defines the implementation of one of the class methods
|
|
for this instance.
|
|
The @var{predname} or @var{funcname} must name a function or
|
|
predicate of the specified arity whose type, modes, determinism, and
|
|
purity are at least as permissive as the declared type, modes,
|
|
determinism, and purity of the class method with the specified
|
|
@var{methodname} and @var{arity}, after the types of the arguments
|
|
in the instance declaration have been substituted in place of the
|
|
parameters in the type class declaration.
|
|
Each @samp{instance} declaration must define an implementation for
|
|
every method declared in the corresponding @samp{typeclass} declaration.
|
|
It is an error to define more than one implementation for the same
|
|
method within a single @samp{instance} declaration.
|
|
|
|
Any call to a method must have argument types (and in the case of functions,
|
|
return type) which are constrained to be a member of that method's
|
|
type class, or which match one of the instance declarations visible at
|
|
the point of the call. A method call will invoke the
|
|
predicate or function specified for that method in the
|
|
instance declaration that matches the types of the arguments
|
|
to the call.
|
|
|
|
Note that even if a type class has no methods, an explicit instance
|
|
declaration is required for a type to be considered an instance
|
|
of that type class.
|
|
|
|
Here's an example of some code using an instance declaration:
|
|
|
|
@example
|
|
:- type coordinate
|
|
---> coordinate(
|
|
float, % X coordinate
|
|
float % Y coordinate
|
|
).
|
|
|
|
:- instance point(coordinate) where [
|
|
pred(coords/3) is coordinate_coords,
|
|
func(translate/3) is coordinate_translate
|
|
].
|
|
|
|
|
|
:- pred coordinate_coords(coordinate, float, float).
|
|
:- mode coordinate_coords(in, out, out) is det.
|
|
|
|
coordinate_coords(coordinate(X, Y), X, Y).
|
|
|
|
:- func coordinate_translate(coordinate, float, float) = coordinate.
|
|
|
|
coordinate_translate(coordinate(X, Y), Dx, Dy) = coordinate(X + Dx, Y + Dy).
|
|
@end example
|
|
|
|
We have now made the @code{coordinate} type an instance of the @code{point}
|
|
type class. If we introduce a new type, @code{coloured_coordinate} which
|
|
represents a point in two dimensional space with a colour associated with it,
|
|
it can also become an instance of the type class:
|
|
|
|
@example
|
|
:- type rgb
|
|
---> rgb(
|
|
int,
|
|
int,
|
|
int
|
|
).
|
|
|
|
:- type coloured_coordinate
|
|
---> coloured_coordinate(
|
|
float,
|
|
float,
|
|
rgb
|
|
).
|
|
|
|
:- instance point(coloured_coordinate) where [
|
|
pred(coords/3) is coloured_coordinate_coords,
|
|
func(translate/3) is coloured_coordinate_translate
|
|
].
|
|
|
|
|
|
:- pred coloured_coordinate_coords(coloured_coordinate, float, float).
|
|
:- mode coloured_coordinate_coords(in, out, out) is det.
|
|
|
|
coloured_coordinate_coords(coloured_coordinate(X, Y, _), X, Y).
|
|
|
|
:- func coloured_coordinate_translate(coloured_coordinate, float, float)
|
|
= coloured_coordinate.
|
|
|
|
coloured_coordinate_translate(coloured_coordinate(X, Y, Colour), Dx, Dy)
|
|
= coloured_coordinate(X + Dx, Y + Dy, Colour).
|
|
@end example
|
|
|
|
If we call @samp{translate/3} with the first argument having type
|
|
@samp{coloured_coordinate}, this will invoke
|
|
@samp{coloured_coordinate_translate}.
|
|
Likewise, if we call @samp{translate/3} with the first argument having type
|
|
@samp{coordinate}, this will invoke @samp{coordinate_translate}.
|
|
|
|
Further instances of the type class could be made, e.g. a type which represents
|
|
the point using polar coordinates.
|
|
|
|
@node Abstract instance declarations
|
|
@section Abstract instance declarations
|
|
|
|
Abstract instance declarations are instance declarations whose
|
|
implementations are hidden. An abstract instance declaration has the
|
|
same form as an instance declaration, but without the @samp{where
|
|
[@dots{}]} part. An abstract instance declaration declares that
|
|
a sequence of types is an instance of a particular type class without
|
|
defining how the type class methods are implemented for those types.
|
|
Like abstract type declarations,
|
|
abstract instance declarations are only useful in the interface
|
|
section of a module. Each abstract instance declaration must
|
|
be accompanied by a corresponding non-abstract instance declaration
|
|
that defines how the type class methods are implemented.
|
|
|
|
Here's an example:
|
|
|
|
@example
|
|
:- module hashable.
|
|
:- interface.
|
|
:- import_module int, string.
|
|
|
|
:- typeclass hashable(T) where [func hash(T) = int].
|
|
:- instance hashable(int).
|
|
:- instance hashable(string).
|
|
|
|
:- implementation.
|
|
|
|
:- instance hashable(int) where [func(hash/1) is hash_int].
|
|
:- instance hashable(string) where [func(hash/1) is hash_string].
|
|
|
|
:- func hash_int(int) = int.
|
|
hash_int(X) = X.
|
|
|
|
:- func hash_string(string) = int.
|
|
hash_string(S) = H :-
|
|
% use the standard library predicate string__hash/2
|
|
string__hash(S, H).
|
|
|
|
:- end_module hashable.
|
|
@end example
|
|
|
|
@node Type class constraints on predicates and functions
|
|
@section Type class constraints on predicates and functions
|
|
|
|
Mercury allows a type class constraint to appear as part of a predicate or
|
|
function's type signature. This constrains the values that can be taken
|
|
by type variables in the signature to belong to particular type classes.
|
|
|
|
A type class constraint is of the form:
|
|
|
|
@example
|
|
<= @var{Typeclass}(@var{TypeVariable}, @dots{}), @dots{}
|
|
@end example
|
|
|
|
where @var{Typeclass} is the name of a type class and @var{TypeVariable} is
|
|
a type variable that appears in the predicate's or function's type signature.
|
|
|
|
For example
|
|
|
|
@example
|
|
:- pred distance(P1, P2, float) <= (point(P1), point(P2)).
|
|
:- mode distance(in, in, out) is det.
|
|
|
|
distance(A, B, Distance) :-
|
|
coords(A, Xa, Ya),
|
|
coords(B, Xb, Yb),
|
|
XDist = Xa - Xb,
|
|
YDist = Ya - Yb,
|
|
Distance = sqrt(XDist*XDist + YDist*YDist).
|
|
@end example
|
|
|
|
In the above example, the @code{distance} predicate is able to calculate the
|
|
distance between any two points, regardless of their representation, as long
|
|
as the @code{coords} operation has been defined. These
|
|
constraints are checked at compile time.
|
|
|
|
@node Type class constraints on type class declarations
|
|
@section Type class constraints on type class declarations
|
|
|
|
Type class constraints may also appear in @code{typeclass} declarations,
|
|
meaning that one type class is a ``superclass'' of another.
|
|
|
|
The variables that appear as arguments to the type classes in the constraints
|
|
must also be arguments to the type class in question.
|
|
|
|
For example, the following declares the @samp{ring} type class, which describes
|
|
types with a particular set of numerical operations defined:
|
|
|
|
@example
|
|
:- typeclass ring(T) where [
|
|
func zero = (T::out) is det, % '+' identity
|
|
func one = (T::out) is det, % '*' identity
|
|
func plus(T::in, T::in) = (T::out) is det, % '+'/2 (forward mode)
|
|
func mult(T::in, T::in) = (T::out) is det, % '*'/2 (forward mode)
|
|
func negative(T::in) = (T::out) is det % '-'/1 (forward mode)
|
|
].
|
|
@end example
|
|
|
|
We can now add the following declaration:
|
|
|
|
@example
|
|
:- typeclass euclidean(T) <= ring(T) where [
|
|
func div(T::in, T::in) = (T::out) is det,
|
|
func mod(T::in, T::in) = (T::out) is det
|
|
].
|
|
@end example
|
|
|
|
This introduces a new type class, @code{euclidean}, of which @code{ring} is a
|
|
superclass. The operations defined by the @code{euclidean} type class are
|
|
@code{div}, @code{mod}, as well as all those defined by the @code{ring}
|
|
type class. Any type declared to be an instance of @code{euclidean} must also
|
|
be declared to be an instance of @code{ring}.
|
|
|
|
Typeclass constraints on type class declarations gives rise to a superclass
|
|
relation. This relation must be acyclic. That is, it is an error if a type
|
|
class is its own (direct or indirect) superclass.
|
|
|
|
@node Type class constraints on instance declarations
|
|
@section Type class constraints on instance declarations
|
|
|
|
Typeclass constraints may also be placed upon instance declarations. The
|
|
variables that appear as arguments to the type classes in the constraints must
|
|
all be type variables that appear in the types in the instance declarations.
|
|
|
|
For example, consider the following declaration of a type class of types that
|
|
may be printed:
|
|
|
|
@example
|
|
:- typeclass portrayable(T) where [
|
|
pred portray(T::in, io__state::di, io__state::uo) is det
|
|
].
|
|
@end example
|
|
|
|
The programmer could declare instances such as
|
|
|
|
@example
|
|
:- instance portrayable(int) where [
|
|
pred(portray/3) is io__write_int
|
|
].
|
|
|
|
:- instance portrayable(char) where [
|
|
pred(portray/3) is io__write_char
|
|
].
|
|
@end example
|
|
|
|
However, when it comes to writing the instance declaration for a type such as
|
|
@code{list(T)}, we want to be able print out the list elements using the
|
|
@code{portray/3} for the particular type of the list elements. This can be
|
|
achieved by placing a type class constraint on the @code{instance} declaration,
|
|
as in the following example:
|
|
|
|
@example
|
|
:- instance portrayable(list(T)) <= portrayable(T) where [
|
|
pred(portray/3) is portray_list
|
|
].
|
|
|
|
:- pred portray_list(list(T), io__state, io__state) <= portrayable(T).
|
|
:- mode portray_list(in, di, uo) is det.
|
|
|
|
portray_list([]) -->
|
|
[].
|
|
portray_list([X|Xs]) -->
|
|
portray(X),
|
|
io__write_char(' '),
|
|
portray_list(Xs).
|
|
@end example
|
|
|
|
For abstract instance declarations, the type class constraints on an
|
|
abstract instance declaration must exactly match the type class
|
|
constraints on the corresponding non-abstract instance declaration that
|
|
defines that instance.
|
|
@c XXX The current implementation does not enforce that rule.
|
|
|
|
@node Existential types
|
|
@chapter Existential types
|
|
|
|
Existentially quantified type variables (or simply "existential types"
|
|
for short) are useful tools for data abstraction. In combination with
|
|
type classes, they allow you to write code in an "object oriented"
|
|
style that is similar to the use of interfaces in Java or abstract
|
|
base classes in C++.
|
|
|
|
Mercury supports existential type quantifiers on predicate and function
|
|
declarations, and in data type definitions. You can put type class
|
|
constraints on existentially quantified type variables.
|
|
|
|
@menu
|
|
* Existentially typed predicates and functions::
|
|
* Existential class constraints::
|
|
* Existentially typed data types::
|
|
* Some idioms using existentially quantified types::
|
|
* Known bugs in the current implementation::
|
|
@end menu
|
|
|
|
@node Existentially typed predicates and functions
|
|
@section Existentially typed predicates and functions
|
|
|
|
@menu
|
|
* Syntax for explicit type qualifiers::
|
|
* Semantics of type qualifiers::
|
|
* Examples of correct code using type quantifiers::
|
|
* Examples of incorrect code using type quantifiers::
|
|
@end menu
|
|
|
|
@node Syntax for explicit type qualifiers
|
|
@subsection Syntax for explicit type qualifiers
|
|
|
|
Type variables in type declarations for polymorphic predicates or functions
|
|
are normally universally quantified.
|
|
However, it is also possible to existentially quantify such
|
|
type variables, by using an explicit existential quantifier of
|
|
the form @samp{some @var{Vars}} before the @samp{pred} or @samp{func}
|
|
declaration, where @var{Vars} is a list of variables.
|
|
|
|
For example:
|
|
|
|
@example
|
|
% Here the type variables `T' is existentially quantified
|
|
:- some [T] pred foo(T).
|
|
|
|
% Here the type variables `T1' and `T2' are existentially quantified.
|
|
:- some [T1, T2] func bar(int, list(T1), set(T2)) = pair(T1, T2).
|
|
|
|
% Here the type variable `T2' is existentially quantified,
|
|
% but the type variables `T1' and `T3' are universally quantified.
|
|
:- some [T2] pred foo(T1, T2, T3).
|
|
@end example
|
|
|
|
Explicit universal quantifiers, of the form @samp{all @var{Vars}},
|
|
are also permitted on @samp{pred} and @samp{func} declarations,
|
|
although they are not necessary, since universal quantification is
|
|
the default. (If both universal and existential quantifiers
|
|
are present, the universal quantifiers must precede the existential
|
|
quantifiers.) For example:
|
|
|
|
@example
|
|
% Here the type variable `T2' is existentially quantified,
|
|
% but the type variables `T1' and `T3' are universally quantified.
|
|
:- all [T3] some [T2] pred foo(T1, T2, T3).
|
|
@end example
|
|
|
|
@node Semantics of type qualifiers
|
|
@subsection Semantics of type qualifiers
|
|
|
|
If a type variable in the type declaration for a polymorphic predicate
|
|
or function is universally quantified, this means the caller will
|
|
determine the value of the type variable, and the callee must be defined
|
|
so that it will work for @emph{all} types which are an instance of its
|
|
declared type.
|
|
|
|
For an existentially quantified type variable, the situation is the
|
|
converse: the @emph{callee} must determine the value of the type variable,
|
|
and all @emph{callers} must be defined so as to work for all types
|
|
which are an instance of the called procedure's declared type.
|
|
|
|
When type checking a predicate or function, if a variable has a type
|
|
that occurs as a universally quantified type variable in the predicate
|
|
or function declaration, or a type that occurs as an existentially
|
|
quantified type variable in the declaration of one of the predicates
|
|
or functions that it calls, then its type is treated as an opaque type.
|
|
This means that there are very few things which it is legal to do with
|
|
such a variable -- basically you can only pass it to another procedure
|
|
expecting the same type, unify it with another value of the same
|
|
type, put it in a polymorphic data structure, or pass it to a
|
|
polymorphic procedure whose argument type is universally quantified.
|
|
(Note, however, that the standard library includes some quite powerful
|
|
procedures such as `io__write' which can be useful in this context.)
|
|
|
|
A non-variable type is considered @emph{more general} than an
|
|
existentially quantified type variable. Type inference will therefore
|
|
never infer an existentially quantified type for a predicate or
|
|
function unless that predicate or function calls (directly or indirectly)
|
|
a predicate or function which was explicitly declared to have an
|
|
existentially quantified type.
|
|
|
|
For procedures involving calls to existentially-typed predicates or functions,
|
|
the compiler's mode analysis must take account of the modes for type
|
|
variables in all polymorphic calls.
|
|
Universally quantified type variables have mode @samp{in},
|
|
whereas existentially quantified type variables have mode @samp{out}.
|
|
As usual, the compiler's mode analysis will attempt to reorder the
|
|
elements of conjunctions in order to satisfy the modes.
|
|
|
|
@node Examples of correct code using type quantifiers
|
|
@subsection Examples of correct code using type quantifiers
|
|
|
|
Here are some examples of type-correct code using universal and
|
|
existential types.
|
|
|
|
@example
|
|
/* simple examples */
|
|
|
|
:- pred foo(T).
|
|
foo(_).
|
|
% ok
|
|
|
|
:- pred call_foo.
|
|
call_foo :- foo(42).
|
|
% ok (T = int)
|
|
|
|
:- some [T] pred e_foo(T).
|
|
e_foo(X) :- X = 42.
|
|
% ok (T = int)
|
|
|
|
:- pred call_e_foo.
|
|
call_e_foo :- e_foo(_).
|
|
% ok
|
|
|
|
/* examples using higher-order functions */
|
|
|
|
:- func bar(T, T, func(T) = int) = int.
|
|
bar(X, Y, F) = F(X) + F(Y).
|
|
% ok
|
|
|
|
:- func call_bar = int.
|
|
call_bar = bar(2, 3, (func(X) = X*X)).
|
|
% ok (T = int)
|
|
% returns 13 (= 2*2 + 3*3)
|
|
|
|
:- some [T] pred e_bar(T, T, func(T) = int).
|
|
:- mode e_bar(out, out, out(func(in) = out is det)).
|
|
e_bar(2, 3, (func(X) = X * X)).
|
|
% ok (T = int)
|
|
|
|
:- func call_e_bar = int.
|
|
call_e_bar = F(X) + F(Y) :- e_bar(X, Y, F).
|
|
% ok
|
|
% returns 13 (= 2*2 + 3*3)
|
|
|
|
@end example
|
|
|
|
@node Examples of incorrect code using type quantifiers
|
|
@subsection Examples of incorrect code using type quantifiers
|
|
|
|
Here are some examples of code using universal and
|
|
existential types that contains type errors.
|
|
|
|
@example
|
|
/* simple examples */
|
|
|
|
:- pred bad_foo(T).
|
|
bad_foo(42).
|
|
% type error
|
|
|
|
:- some [T] pred e_foo(T).
|
|
e_foo(42).
|
|
% ok
|
|
|
|
:- pred bad_call_e_foo.
|
|
bad_call_e_foo :- e_foo(42).
|
|
% type error
|
|
|
|
:- some [T] pred e_bar1(T).
|
|
e_bar1(42).
|
|
e_bar1(42).
|
|
e_bar1(43).
|
|
% ok (T = int)
|
|
|
|
:- some [T] pred bad_e_bar2(T).
|
|
bad_e_bar2(42).
|
|
bad_e_bar2("blah").
|
|
% type error (cannot unify types `int' and `string')
|
|
|
|
:- some [T] pred bad_e_bar3(T).
|
|
bad_e_bar3(X) :- e_foo(X).
|
|
bad_e_bar3(X) :- e_foo(X).
|
|
% type error (attempt to bind type variable `T' twice)
|
|
|
|
@end example
|
|
|
|
@node Existential class constraints
|
|
@section Existential class constraints
|
|
|
|
Existentially quantified type variables are especially useful in
|
|
combination with type class constraints.
|
|
|
|
Type class constraints can be either universal or existential.
|
|
Universal type class constraints are written using "<=",
|
|
as described in @ref{Type class constraints on predicates and functions};
|
|
they signify a constraint that the @emph{caller} must satisfy.
|
|
Existential type class constraints are written in the same syntax
|
|
as universal constraints, but using "=>" instead of "<=";
|
|
they signify a constraint that the @emph{callee} must satisfy.
|
|
(If a declaration has both universal and existential constraints,
|
|
then the existential constraints must precede the universal constraints.)
|
|
|
|
For example:
|
|
|
|
@example
|
|
% Here `c1(T2)' and `c2(T1, T2)' are existential constraints,
|
|
% and `c3(T1)' is a universal constraint,
|
|
:- all [T1] some [T2] ((pred p(T1, T2) => (c1(T2), c2(T1, T2))) <= c3(T1)).
|
|
@end example
|
|
|
|
In general, constraints that constrain any existentially quantified
|
|
type variables should be existential constraints, and constraints that
|
|
constrain only universally quantified type variables should be
|
|
universal constraints. (The only time exceptions to this rule would
|
|
make any sense at all would be if there were instance declarations that
|
|
were visible in the definition of the caller but which due to module
|
|
visibility issues were not in the definition of the callee, or vice
|
|
versa. But even then, any exception to this rule would have to involve
|
|
a rather obscure coding style, which we do not recommend.)
|
|
|
|
@node Existentially typed data types
|
|
@section Existentially typed data types
|
|
|
|
Type variables occurring in the body of a discriminated union type
|
|
definition may be existentially quantified. Constructor definitions
|
|
within discriminated union type definitions may be preceded by
|
|
an existential type quantifier and followed by one or more existential
|
|
type class constraints.
|
|
|
|
For example:
|
|
|
|
@example
|
|
% A simple heterogeneous list type
|
|
:- type list_of_any
|
|
---> nil_any
|
|
; some [T] cons_any(T, list_of_any).
|
|
|
|
% A heterogeneous list type with a type class constraint
|
|
:- typeclass showable(T) where [ func show(T) = string ].
|
|
:- type showable_list
|
|
---> nil
|
|
; some [T] (cons(T, list_of_any) => showable(T)).
|
|
|
|
% A different way of doing the same kind of thing, this
|
|
% time using the standard type list(T).
|
|
:- type showable ---> some [T] (s(T) => showable(T)).
|
|
:- type list_of_showable == list(showable).
|
|
|
|
% Here's an arbitrary example involving multiple
|
|
% type variables and multiple constraints
|
|
:- typeclass foo(T1, T2) where [ /* ... */ ].
|
|
:- type bar(T)
|
|
---> f1
|
|
; f2(T)
|
|
; some [T]
|
|
f4(T)
|
|
; some [T1, T2]
|
|
(f4(T1, T2, T) => showable(T1), showable(T2))
|
|
; some [T1, T2]
|
|
(f5(list(T1), T2) => fooable(T1, list(T2)))
|
|
.
|
|
@end example
|
|
|
|
Construction and deconstruction of existentially quantified data types
|
|
are inverses: when constructing a value of an existentially quantified
|
|
data type, the ``existentially quantified'' functor acts for purposes
|
|
of type checking like a universally quantified function: the caller
|
|
will determine the values of the type variables.
|
|
Conversely, for deconstruction the functor acts like an
|
|
existentially quantified function: the caller must be defined so
|
|
as to work for all possible values of the existentially quantified
|
|
type variables which satisfy the declared type class constraints.
|
|
|
|
In order to make this distinction clear to the compiler,
|
|
whenever you want to construct a value using an existentially
|
|
quantified functor, you must prepend @samp{new } onto the functor name.
|
|
This tells the compiler to treat it as though it were universally
|
|
quantified: the caller can bind that functor's existentially quantified
|
|
type variables to any type which satisfies the declared type class
|
|
constraints. Conversely, any occurrence without the @samp{new } prefix
|
|
must be a deconstruction, and is therefore existentially quantified:
|
|
the caller must not bind the existentially quantified type variables,
|
|
but the caller is allowed to depend on those type variables satisfying
|
|
the declared type class constraints, if any.
|
|
|
|
For example, the function @samp{make_list} constructs a value of type
|
|
@samp{list_of_showable} containing a sequence of values of different types,
|
|
all of which are instances of the @samp{showable} class
|
|
|
|
@example
|
|
:- instance showable(int).
|
|
:- instance showable(float).
|
|
:- instance showable(string).
|
|
|
|
:- func make_list = showable_list.
|
|
make_list = List :-
|
|
Int = 42,
|
|
Float = 1.0,
|
|
String = "blah",
|
|
List = 'new cons'(Int,
|
|
'new cons'(Float,
|
|
'new cons'(String, nil))).
|
|
@end example
|
|
|
|
while the function @samp{process_list} below applies the @samp{show}
|
|
method of the @samp{showable} class to the values in such a list.
|
|
|
|
@example
|
|
:- func process_list(list_of_showable) = list(string).
|
|
process_list(nil) = "".
|
|
process_list(cons(Head, Tail)) = [show(Head) | process_list(Tail)].
|
|
@end example
|
|
|
|
@node Some idioms using existentially quantified types
|
|
@section Some idioms using existentially quantified types
|
|
|
|
The standard library module @samp{std_util} provides an abstract
|
|
type named @samp{univ} which can hold values of any type.
|
|
You can form heterogeneous containers (containers that can hold values of
|
|
different types at the same time) by using data structures
|
|
that contain @code{univ}s, e.g. @samp{list(univ)}.
|
|
|
|
The interface to @samp{std_util} includes the following:
|
|
|
|
@example
|
|
% `univ' is a type which can hold any value.
|
|
:- type univ.
|
|
|
|
% The function univ/1 takes a value of any type and constructs
|
|
% a `univ' containing that value (the type will be stored along
|
|
% with the value)
|
|
:- func univ(T) = univ.
|
|
|
|
% The function univ_value/1 takes a `univ' argument and extracts
|
|
% the value contained in the `univ' (together with its type).
|
|
% This is the inverse of the function univ/1.
|
|
:- some [T] func univ_value(univ) = T.
|
|
@end example
|
|
|
|
The @samp{univ} type in the standard library is in fact a simple
|
|
example of an existentially typed data type. It could be implemented
|
|
as follows:
|
|
|
|
@example
|
|
:- implementation.
|
|
:- type univ ---> some [T] mkuniv(T).
|
|
univ(X) = 'new mkuniv'(X).
|
|
univ_value(mkuniv(X)) = X.
|
|
@end example
|
|
|
|
An existentially typed procedure is not allowed to have different
|
|
types for its existentially typed arguments in different clauses or
|
|
or in different subgoals of a single clause. For instance, both
|
|
of the following examples are illegal:
|
|
|
|
@example
|
|
:- some [T] pred bad_example(string, T).
|
|
bad_example("foo", 42).
|
|
bad_example("bar", "blah").
|
|
% type error (cannot unify `int' and `string')
|
|
|
|
:- some [T] pred bad_example2(string, T).
|
|
bad_example2(Name, Value) :-
|
|
( Name = "foo", Value = 42
|
|
; Name = "bar", Value = "blah"
|
|
).
|
|
% type error (cannot unify `int' and `string')
|
|
@end example
|
|
|
|
However, using @samp{univ},
|
|
it is possible for an existentially typed function to return
|
|
values of different types at each invocation.
|
|
|
|
@example
|
|
:- some [T] pred good_example(string, T).
|
|
good_example(Name, univ_value(Univ)) :-
|
|
( Name = "foo", Univ = univ(42)
|
|
; Name = "bar", Univ = univ("blah")
|
|
).
|
|
@end example
|
|
|
|
Using @samp{univ} doesn't work if you also want to use type class constraints.
|
|
If you want to use type class constraints, then you must define your own
|
|
existentially typed data type, analogous to @samp{univ}, and use that:
|
|
|
|
@example
|
|
:- type univ_showable ---> some [T] (mkshowable(T) => showable(T)).
|
|
|
|
:- some [T] pred harder_example(string, T) => showable(T).
|
|
harder_example(Name, Showable) :-
|
|
( Name = "bar", Univ = 'new mkshowable'(42)
|
|
; Name = "bar", Univ = 'new mkshowable'("blah")
|
|
),
|
|
Univ = mkshowable(Showable).
|
|
@end example
|
|
|
|
@node Known bugs in the current implementation
|
|
@section Known bugs in the current implementation
|
|
|
|
The current implementation does not properly deal with most cases
|
|
that involve both existentially quantified constraints and
|
|
mode reordering due to the modes of type variables.
|
|
Note that this can easily arise if you're using nested function calls.
|
|
The symptom in such cases is usually spurious mode errors,
|
|
or sometimes internal compiler errors of the form
|
|
|
|
@example
|
|
Software error: map__lookup: key not found
|
|
Key Type: prog_data:class_constraint
|
|
Key Functor: constraint/2
|
|
Value Type: hlds_data:constraint_proof
|
|
@end example
|
|
|
|
@noindent
|
|
The work-around is to write such code in the correct order manually
|
|
rather than relying on the compiler's mode reordering.
|
|
For nested function calls, you may need to split them up using
|
|
temporary variables, e.g. instead of @samp{X = f(g(Y))},
|
|
write @samp{G = g(Y), X = f(G)}.
|
|
|
|
@node Semantics
|
|
@chapter Semantics
|
|
|
|
A legal Mercury program is one that complies with the syntax,
|
|
type, mode, determinism, and module system rules specified in earlier chapters.
|
|
If a program does not comply with those rules,
|
|
the compiler must report an error.
|
|
|
|
For each legal Mercury program,
|
|
there is an associated predicate calculus theory
|
|
whose language is specified by the type declarations in the program
|
|
and whose axioms are the completion of the clauses for all predicates
|
|
in the program,
|
|
plus the usual equality axioms extended with the completion of the
|
|
equations for all functions in the program,
|
|
plus axioms corresponding to the mode-determinism assertions
|
|
(@pxref{Determinism}),
|
|
plus axioms specifying the semantics of library predicates and functions.
|
|
The declarative semantics of a legal Mercury program
|
|
is specified by this theory.
|
|
|
|
Mercury implementations must be sound:
|
|
the answers they compute must be true in every model of the theory.
|
|
Mercury implementations are not required to be complete:
|
|
they may fail to compute an answer in finite time,
|
|
or they may exhaust the resource limitations of the execution
|
|
environment, even though an answer is provable in the theory.
|
|
However, there are certain minimum requirements that they
|
|
must satisfy with respect to completeness.
|
|
|
|
There is an operational semantics of Mercury programs called the
|
|
@dfn{strict sequential} operational semantics. In this semantics,
|
|
the program is executed top-down, starting from @samp{main/2},
|
|
and function calls within a goal, conjunctions and disjunctions are all
|
|
executed in depth-first left-to-right order.
|
|
Conjunctions and function calls are ``minimally'' reordered as required
|
|
by the modes:
|
|
the order is determined by selecting the first mode-correct sub-goal
|
|
(conjunct or function call),
|
|
executing that, then selecting the first of the remaining sub-goals
|
|
which is now mode-correct, executing that, and so on.
|
|
(There is no interleaving of different individual conjuncts or function calls,
|
|
however; the sub-goals are reordered, not split and interleaved.)
|
|
Function application is strict, not lazy.
|
|
@c XXX should document the operational semantics of switches and if-then-elses
|
|
|
|
Mercury implementations are required to provide a method of processing
|
|
Mercury programs which is equivalent to the strict sequential
|
|
operational semantics.
|
|
|
|
There is another operational semantics of Mercury programs called
|
|
the @dfn{strict commutative} operational semantics. This semantics
|
|
is equivalent to the strict sequential operational semantics except
|
|
that there is no requirement that function calls, conjunctions and disjunctions
|
|
be executed left-to-right; they may be executed in any order, and may
|
|
even be interleaved. Furthermore, the order may even be different each
|
|
time a particular goal is entered.
|
|
|
|
As well as providing the strict sequential operational semantics,
|
|
Mercury implementations may optionally provide additional
|
|
implementation-defined operational semantics, provided that
|
|
any such implementation-defined operational semantics are
|
|
at least as complete as the strict commutative operational
|
|
semantics. An implementation-defined semantics
|
|
is ``at least as complete'' as the strict commutative
|
|
semantics if and only if the implementation-defined
|
|
semantics guarantees to compute an answer in finite time for
|
|
any program for which an answer would be computed in finite time for all
|
|
possible executions under the strict commutative semantics
|
|
(i.e. for all possible orderings of conjunctions and disjunctions).
|
|
|
|
Thus, to summarize, there are in fact a variety of different operational
|
|
semantics for Mercury. In one of them, the strict sequential semantics, there
|
|
is no nondeterminism --- the behaviour is always specified exactly.
|
|
Programs are executed top-down using SLDNF (or something equivalent),
|
|
mode analysis does ``minimal'' reordering (in a precisely defined sense),
|
|
function calls, conjunctions and disjunctions are executed depth-first
|
|
left-to-right, and function evaluation is strict. All implementations
|
|
are required to support the strict sequential semantics, so that a
|
|
program which works on one implementation using this semantics will be
|
|
guaranteed to work on any other implementation. However,
|
|
implementations are also allowed to support other operational
|
|
semantics, which may have non-determinism, so long as they are sound
|
|
with respect to the declarative semantics, and so long as they meet a
|
|
minimum level of completeness (they must be at least as complete as the
|
|
strict commutative semantics, in the sense that every program which
|
|
terminates for all possible orderings must must also terminate in any
|
|
implementation-defined operational semantics).
|
|
|
|
This compromise allows Mercury to be used in several different ways.
|
|
Programmers who care more about ease of programming and portability
|
|
than about efficiency can use the strict sequential semantics, and
|
|
can then be guaranteed that if their program works on one correct
|
|
implementation, it will work on all correct implementations. Compiler
|
|
implementors who want to write optimizing implementations that do lots
|
|
of clever code reorderings and other high-level transformations or that
|
|
want to offer parallelizing implementations which take maximum
|
|
advantage of parallelism can define different semantic models.
|
|
Programmers who care about efficiency more than portability can write
|
|
code for these implementation-defined semantic models. Programmers who
|
|
care about efficiency @emph{and} portability can achieve this by writing
|
|
code for the commutative semantics.
|
|
Of course, this is not
|
|
quite as easy as using the strict sequential semantics, since it is
|
|
in general not sufficient to test your programs on just one
|
|
implementation if you are to be sure that it will be able to use the
|
|
maximally efficient operational semantics on any implementation.
|
|
However, if you do write code which works for all possible executions
|
|
under commutative semantics (i.e. for all possible orderings of
|
|
conjunctions and disjunctions), then you can be guaranteed that it
|
|
will work correctly on every implementation, under every possible
|
|
implementation-defined semantics.
|
|
|
|
The University of Melbourne Mercury implementation offers eight
|
|
different semantics, which can be selected with different
|
|
combinations of the @samp{--no-reorder-conj}, @samp{--no-reorder-disj},
|
|
and @samp{--fully-strict} options. (The @samp{--fully-strict} option
|
|
prevents the compiler from improving completeness by optimizing away infinite
|
|
loops or calls to @code{error/1}.) The default semantics are the
|
|
commutative semantics. Enabling all of these options gives you the
|
|
the strict sequential semantics. Enabling just some of them gives
|
|
you a semantics somewhere in between.
|
|
|
|
Future implementations of Mercury may wish to offer other operational semantics.
|
|
For example, they may wish to provide semantics in which function
|
|
evaluation is lazy, rather than strict; semantics with a guaranteed
|
|
fair search rule; and so forth.
|
|
|
|
@node C interface
|
|
@chapter C interface
|
|
|
|
@menu
|
|
* Calling C code from Mercury:: How to implement a Mercury predicate
|
|
or function as a call to C code.
|
|
* Including C headers:: Using functions with prototypes from a
|
|
non-standard header file.
|
|
* Including C code:: Including definitions of C
|
|
functions in your Mercury code.
|
|
* Linking with C object files:: Linking with C object files and
|
|
libraries.
|
|
* Calling Mercury code from C:: How to export a Mercury function or
|
|
predicate for use by C code.
|
|
* Passing data to and from C:: Exchanging simple data types between
|
|
Mercury and C.
|
|
* Using C pointers:: Maintaining a reference to C data
|
|
structures in Mercury code.
|
|
* Memory management:: Caveats about passing dynamically
|
|
allocated memory to or from C.
|
|
* Trailing:: Undoing side-effects on backtracking.
|
|
@end menu
|
|
|
|
The Mercury distribution includes a number of examples of the
|
|
use of the C interface that show how to interface C++ with Mercury
|
|
and how to set up @samp{Mmake} files to automate the build process.
|
|
See the @samp{samples/c_interface} directory in the Mercury distribution.
|
|
|
|
@node Calling C code from Mercury
|
|
@section Calling C code from Mercury
|
|
|
|
There are two slightly different mechanisms for calling C code from Mercury:
|
|
@samp{pragma import} and @samp{pragma c_code}. @samp{pragma import}
|
|
allows you to call C functions from Mercury. @samp{pragma c_code}
|
|
allows you to implement Mercury procedures using arbitrary fragments
|
|
of C code. @samp{pragma import} is usually simpler, but
|
|
@samp{pragma c_code} is a bit more flexible.
|
|
|
|
@c
|
|
@c We can't use "@samp" or even "`...'" in node names -- if we use
|
|
@c either, then texi2dvi barfs. So the node names are
|
|
@c e.g. "pragma import" rather than "@samp{pragma import}".
|
|
@c
|
|
@menu
|
|
* pragma import:: Importing C functions.
|
|
* pragma c_code:: Defining Mercury procedures using C code.
|
|
* Nondet pragma c_code:: Using @samp{pragma c_code} for Mercury procedures
|
|
that can have more than one solution.
|
|
* C code attributes:: Describing properties of C functions or C code.
|
|
* Purity and side effects:: Explains when side effects are allowed.
|
|
@end menu
|
|
|
|
@node pragma import
|
|
@subsection pragma import
|
|
|
|
A declaration of the form
|
|
|
|
@example
|
|
:- pragma import(@var{Pred}(@var{Mode1}, @var{Mode2}, @dots{}),
|
|
@var{Attributes}, "@var{C_Name}").
|
|
@end example
|
|
|
|
@noindent
|
|
or
|
|
|
|
@example
|
|
:- pragma import(@var{Func}(@var{Mode1}, @var{Mode2}, @dots{}) = @var{Mode},
|
|
@var{Attributes}, "@var{C_Name}").
|
|
@end example
|
|
|
|
@noindent
|
|
imports a C function for use by Mercury.
|
|
@var{Pred} or @var{Func} must specify the name of a previously declared
|
|
Mercury predicate or function, and @var{Mode1}, @var{Mode2}, @dots{},
|
|
and (for functions) @var{Mode} must specify one of the
|
|
modes of that predicate or function. There must be no clauses
|
|
for the specified Mercury procedure; instead, any calls to that
|
|
procedure will be executed by calling the C function named
|
|
@var{C_Name}. The @var{Attributes} argument is optional; if present,
|
|
it specifies properties of the given C function (@pxref{C code attributes}).
|
|
|
|
For example, the following code imports the C function @samp{cos()}
|
|
as the Mercury function @samp{cos/1}:
|
|
|
|
@example
|
|
:- func cos(float) = float.
|
|
:- pragma import(cos(in) = out, [will_not_call_mercury], "cos").
|
|
@end example
|
|
|
|
The interface to the C function for a given Mercury procedure is
|
|
determined as follows. Mercury types are converted to C types
|
|
according to the rules in @ref{Passing data to and from C}.
|
|
Mercury arguments declared with input modes are passed by value to the
|
|
C function. For output arguments, the Mercury implementation will pass
|
|
to the C function an address in which to store the result.
|
|
If the Mercury procedure can fail, then its C function should return a
|
|
truth value of type @samp{Integer} indicating success or failure:
|
|
non-zero indicates success, and zero indicates failure.
|
|
If the Mercury procedure is a Mercury function that cannot fail, and
|
|
the function result has an output mode, then the C function should
|
|
return the Mercury function result value.
|
|
Otherwise the function result is appended as an extra argument.
|
|
Arguments of type @samp{io__state} or @samp{store__store(_)} are not
|
|
passed at all; that's because these types represent mutable state, and
|
|
in C modifications to mutable state are done via side effects, rather
|
|
than argument passing.
|
|
|
|
If you use @samp{pragma import} for a polymorphically typed Mercury procedure,
|
|
the compiler will prepend one @samp{type_info} argument to the parameters
|
|
passed to the C function for each polymorphic type variable in the
|
|
Mercury procedure's type signature. The values passed in these arguments
|
|
will be the same as the values that would be obtained using the Mercury
|
|
@samp{type_of} function in the Mercury standard library module @samp{std_util}.
|
|
These values may be useful in case the C function wishes to in turn call
|
|
another polymorphic Mercury procedure (@pxref{Calling Mercury code from C}).
|
|
|
|
You may not give a @samp{pragma import} declaration for a procedure
|
|
with determinism @samp{nondet} or @samp{multi}.
|
|
(It is however possible to define a @samp{nondet} or @samp{multi} procedure
|
|
using @samp{pragma c_code} -- @pxref{Nondet pragma c_code}).
|
|
|
|
@node pragma c_code
|
|
@subsection pragma c_code
|
|
|
|
A declaration of the form
|
|
|
|
@example
|
|
:- pragma c_code(@var{Pred}(@var{Var1}::@var{Mode1}, @var{Var2}::@var{Mode2}, @dots{}),
|
|
@var{Attributes}, @var{C_Code}).
|
|
@end example
|
|
|
|
@noindent
|
|
or
|
|
|
|
@example
|
|
:- pragma c_code(@var{Func}(@var{Var1}::@var{Mode1}, @var{Var2}::@var{Mode2}, @dots{}) = (@var{Var}::@var{Mode}),
|
|
@var{Attributes}, @var{C_Code}).
|
|
@end example
|
|
|
|
@noindent
|
|
means that any calls to the specified mode of @var{Pred} or @var{Func}
|
|
will result in execution of the C code given in @var{C_Code}.
|
|
The C code fragment may refer to the specified variables
|
|
(@var{Var1}, @var{Var2}, @dots{}, and @var{Var})
|
|
directly by name. These variables will have C types corresponding
|
|
to their Mercury types, as determined by the rules specified in
|
|
@ref{Passing data to and from C}. It is an error for a variable
|
|
to occur more than once in the argument list.
|
|
|
|
The C code fragment may declare local variables, but it should not
|
|
declare any labels or static variables unless there is also a Mercury
|
|
@samp{pragma no_inline} declaration (@pxref{Inlining}) for the procedure.
|
|
The reason for this is that otherwise the Mercury implementation may
|
|
inline the procedure by duplicating the C code fragment for each call.
|
|
If the C code fragment declared a static variable, inlining it in this
|
|
way could result in the program having multiple instances of the static
|
|
variable, rather than a single shared instance. If the C code fragment
|
|
declared a label, inlining it in this way could result in an error due
|
|
to the same label being defined twice inside a single C function.
|
|
|
|
If there is a @code{pragma import} or @code{pragma c_code} declaration for a
|
|
mode of a predicate or function, then there must not be any clauses for that
|
|
predicate or function, and there must be a @code{pragma c_code}
|
|
or @code{pragma import} declaration for every mode of the predicate or function.
|
|
|
|
For example, the following piece of code defines a Mercury function
|
|
@samp{sin/1} which calls the C function @samp{sin()} of the same name.
|
|
|
|
@example
|
|
:- func sin(float) = float.
|
|
:- pragma c_code(sin(X::in) = (Sin::out),
|
|
[may_call_mercury],
|
|
"Sin = sin(X);").
|
|
@end example
|
|
|
|
If the C code does not recursively invoke Mercury code,
|
|
as in the above example, then you can use @samp{will_not_call_mercury}
|
|
in place of @samp{may_call_mercury} in the declarations above.
|
|
This allows the compiler to use a slightly more efficient calling convention.
|
|
(If you use this form, and the C code @emph{does} invoke Mercury code,
|
|
then the behaviour is undefined --- your program may misbehave or crash.)
|
|
|
|
The C code in a @code{pragma c_code} declaration
|
|
for any procedure whose determinism indicates that it could fail
|
|
must assign a truth value to the macro @samp{SUCCESS_INDICATOR}.
|
|
For example:
|
|
|
|
@example
|
|
:- pred string__contains_char(string, character).
|
|
:- mode string__contains_char(in, in) is semidet.
|
|
|
|
:- pragma c_code(string__contains_char(Str::in, Ch::in),
|
|
[will_not_call_mercury],
|
|
"SUCCESS_INDICATOR = (strchr(Str, Ch) != NULL);").
|
|
@end example
|
|
|
|
@code{SUCCESS_INDICATOR} should not be used other than as the target of
|
|
an assignment.
|
|
(For example, it may be @code{#define}d to a register, so you should not
|
|
try to take its address.)
|
|
Procedures whose determinism indicates that that they cannot fail
|
|
should not access @code{SUCCESS_INDICATOR}.
|
|
|
|
Arguments whose mode is input will have their values set by the
|
|
Mercury implementation on entry to the C code. If the procedure
|
|
succeeds, the C code must set the values of all output arguments
|
|
before returning. If the procedure fails, the C code need only
|
|
set @code{SUCCESS_INDICATOR} to false (zero).
|
|
|
|
@node Nondet pragma c_code
|
|
@subsection Nondet pragma c_code
|
|
|
|
For procedures that can return more than one result on backtracking,
|
|
i.e. those with determinism @samp{nondet} or @samp{multi},
|
|
the form of @samp{pragma c_code} declaration described previously
|
|
does not suffice. Instead, you should use a declaration of the form
|
|
shown below:
|
|
|
|
@example
|
|
:- pragma c_code(@var{Pred}(@var{Var1}::@var{Mode1}, @var{Var2}::@var{Mode2}, @dots{}),
|
|
@var{Attributes}, local_vars(@var{LocalVars}), first_code(@var{FirstCode}),
|
|
retry_code(@var{RetryCode}), common_code(@var{CommonCode})).
|
|
@end example
|
|
|
|
@noindent
|
|
or
|
|
|
|
@example
|
|
:- pragma c_code(@var{Func}(@var{Var1}::@var{Mode1}, @var{Var2}::@var{Mode2}, @dots{}) = (@var{Var}::@var{Mode}),
|
|
@var{Attributes}, local_vars(@var{LocalVars}), first_code(@var{FirstCode}),
|
|
retry_code(@var{RetryCode}), common_code(@var{CommonCode})).
|
|
@end example
|
|
|
|
@noindent
|
|
Here @var{FirstCode}, @var{RetryCode}, and @var{CommonCode} are all
|
|
Mercury strings containing C code.
|
|
@var{FirstCode} will be executed whenever the Mercury procedure is called.
|
|
@var{RetryCode} will be executed whenever a given call to the procedure
|
|
is re-entered on backtracking to find subsequent solutions.
|
|
The @samp{common_code(@var{CommonCode})} argument is optional; if present,
|
|
@var{CommonCode} will be executed after each execution of
|
|
@var{FirstCode} or @var{RetryCode}.
|
|
|
|
The code that is executed on each call or retry should finish by
|
|
executing one of the three macros @samp{FAIL}, @samp{SUCCEED}, or
|
|
@samp{SUCCEED_LAST}. The @samp{FAIL} macro indicates that the call has
|
|
failed; the call will not be retried. The @samp{SUCCEED} macro
|
|
indicates that the call has succeeded, and that there may be more
|
|
solutions; the call may be retried on backtracking. The
|
|
@samp{SUCCEED_LAST} macro indicates that the call has succeeded, but
|
|
that there are no more solutions after this one; the call will not be
|
|
retried.
|
|
|
|
@var{LocalVars} is a sequence of struct member declarations which are
|
|
used to hold any state which needs to be preserved in case of backtracking
|
|
or passed between the different C code fragments.
|
|
The code fragments @var{FirstCode}, @var{RetryCode}, and @var{CommonCode}
|
|
may use the macro @samp{LOCALS}, which is defined to be a pointer to a struct
|
|
containing the fields specified by @var{LocalVars}, to access this saved state.
|
|
|
|
Note @var{RetryCode} and @var{CommonCode} may not access the input
|
|
variables -- only @var{FirstCode} should access the input variables.
|
|
If @var{RetryCode} or @var{CommonCode} need to access any of the input
|
|
variables, then @var{FirstCode} should copy the values needed to the
|
|
@var{LocalVars}.
|
|
|
|
The following example shows how you can use a state variable to
|
|
keep track of the next alternative to return.
|
|
|
|
@example
|
|
%
|
|
% This example implements the equivalent of
|
|
% foo(X) :- X = 20 ; X = 10 ; X = 42 ; X = 99 ; fail.
|
|
%
|
|
:- pred foo(int).
|
|
:- mode foo(out) is multi.
|
|
:- pragma c_code(foo(X::out), [will_not_call_mercury, thread_safe],
|
|
local_vars("
|
|
int state;
|
|
"),
|
|
first_code("
|
|
LOCALS->state = 1;
|
|
"),
|
|
retry_code("
|
|
LOCALS->state++;
|
|
"),
|
|
common_code("
|
|
switch (LOCALS->state) @{
|
|
case 1: X = 20; SUCCEED; break;
|
|
case 2: X = 10; SUCCEED; break;
|
|
case 3: X = 42; SUCCEED; break;
|
|
case 4: X = 99; SUCCEED; break;
|
|
case 5: FAIL; break;
|
|
@}
|
|
")
|
|
).
|
|
@end example
|
|
|
|
@noindent
|
|
The next example is a more realistic example;
|
|
it shows how you could implement the reverse
|
|
mode of @samp{string__append}, which returns
|
|
all possible ways of splitting a string into
|
|
two pieces, using @samp{pragma c_code}.
|
|
|
|
@example
|
|
:- pred string__append(string, string, string).
|
|
:- mode string__append(out, out, in) is multi.
|
|
:- pragma c_code(string__append(S1::out, S2::out, S3::in),
|
|
[will_not_call_mercury, thread_safe],
|
|
local_vars("
|
|
String s;
|
|
size_t len;
|
|
size_t count;
|
|
"),
|
|
first_code("
|
|
LOCALS->s = S3;
|
|
LOCALS->len = strlen(S3);
|
|
LOCALS->count = 0;
|
|
"),
|
|
retry_code("
|
|
LOCALS->count++;
|
|
"),
|
|
common_code("
|
|
S1 = copy_substring(LOCALS->s, 0, LOCALS->count);
|
|
S2 = copy_substring(LOCALS->s, LOCALS->count,
|
|
LOCALS->len);
|
|
if (LOCALS->count < LOCALS->len) @{
|
|
SUCCEED;
|
|
@} else @{
|
|
SUCCEED_LAST;
|
|
@}
|
|
")
|
|
).
|
|
@end example
|
|
|
|
@node C code attributes
|
|
@subsection C code attributes
|
|
|
|
As described above, @samp{pragma import} and @samp{pragma c_code}
|
|
declarations may include a list of attributes describing properties
|
|
of the given C function or C code.
|
|
All Mercury implementations must support the attributes listed below.
|
|
They may also support additional attributes.
|
|
|
|
The attributes which must be supported by all implementations
|
|
are as follows:
|
|
|
|
@table @asis
|
|
|
|
@item @samp{may_call_mercury}/@samp{will_not_call_mercury}
|
|
This attribute declares whether or not execution inside this C code may
|
|
call back into Mercury or not. The default, in case neither is specified,
|
|
is @samp{may_call_mercury}. Specifying @samp{will_not_call_mercury}
|
|
may allow the compiler to generate more efficient code.
|
|
If you specify @samp{will_not_call_mercury},
|
|
but the C code @emph{does} invoke Mercury code, then the behaviour is
|
|
undefined.
|
|
|
|
@item @samp{thread_safe}/@samp{not_thread_safe}
|
|
This attribute declares whether or not it is safe for multiple threads
|
|
to execute this C code concurrently.
|
|
The default, in case neither is specified, is @samp{not_thread_safe}.
|
|
If the C code is declared @samp{thread_safe}, then the Mercury implementation
|
|
is permitted to execute the code concurrently from multiple threads without
|
|
taking any special precautions. If the C code is declared
|
|
@samp{not_thread_safe},
|
|
then the Mercury implementation must not invoke the code concurrently from
|
|
multiple threads. If the Mercury implementation does use multithreading,
|
|
then it must take appropriate steps to prevent this.
|
|
(The experimental multithreaded version of the current
|
|
University of Melbourne Mercury implementation protects
|
|
@samp{not_thread_safe} code using a mutex:
|
|
C code that is not thread-safe has code inserted around it to obtain
|
|
and release a mutex. All non-thread-safe C code shares a single mutex.)
|
|
@c XXX this can cause deadlocks if not_thread_safe C code calls
|
|
@c Mercury which calls C
|
|
|
|
@end table
|
|
|
|
@node Purity and side effects
|
|
@subsection Purity and side effects
|
|
|
|
Note that procedures implemented in C using either
|
|
@samp{pragma import} or @samp{pragma c_code} must still be ``pure'',
|
|
unless declared otherwise (@pxref{Impurity}), and they must
|
|
be type-correct and mode-correct. (Determinism-correctness
|
|
is also required, but it follows from the rules already stated
|
|
above.) They may perform destructive update on their
|
|
arguments only if those arguments have an appropriate
|
|
unique mode declaration.
|
|
They may perform I/O only if their arguments
|
|
include an @samp{io__state} pair (see the @samp{io} chapter
|
|
of the Mercury Library Reference Manual).
|
|
The Mercury implementation is allowed to assume that
|
|
these rules are followed, and to optimize accordingly.
|
|
If the C code is not type-correct, mode-correct,
|
|
determinism-correct, and purity-correct with respect
|
|
to its Mercury declaration, then the behaviour is
|
|
undefined.
|
|
|
|
For example, the following code defines a predicate
|
|
@samp{c_write_string/3}, which has a similar effect to
|
|
the Mercury library predicate @samp{io__write_string/3}:
|
|
|
|
@example
|
|
:- pred c_write_string(string, io__state, io__state).
|
|
:- mode c_write_string(in, di, uo) is det.
|
|
|
|
:- pragma c_code(c_write_string(S::in, IO0::di, IO::uo),
|
|
[may_call_mercury],
|
|
"puts(S); IO = IO0;").
|
|
@end example
|
|
|
|
@noindent
|
|
In this example, the I/O is done via side effects inside the C code,
|
|
but the Mercury interface includes @samp{io__state} arguments
|
|
to ensure that the predicate has a proper declarative
|
|
semantics. If the @samp{io__state} arguments were
|
|
left off, then the Mercury implementation might apply
|
|
undesirable optimizations (e.g. reordering, duplicate
|
|
call elimination, tabling, lazy evaluation, @dots{})
|
|
to this procedure, which could effect the behaviour
|
|
of the program in unpredictable ways.
|
|
|
|
@node Including C headers
|
|
@section Including C headers
|
|
|
|
Any macros, function prototypes, or other C declarations
|
|
that are used in @samp{c_code} pragmas must be included using a
|
|
@samp{c_header_code} declaration of the form
|
|
|
|
@example
|
|
:- pragma c_header_code(@var{HeaderCode}).
|
|
@end example
|
|
|
|
@noindent
|
|
@var{HeaderCode} can be a C @samp{#include} line, for example
|
|
|
|
@example
|
|
:- pragma c_header_code("#include <math.h>")
|
|
@end example
|
|
|
|
@noindent
|
|
or
|
|
|
|
@example
|
|
:- pragma c_header_code("#include ""tcl.h""").
|
|
@end example
|
|
|
|
@noindent
|
|
or it may contain any C declarations, for example
|
|
|
|
@example
|
|
:- pragma c_header_code("
|
|
extern int errno;
|
|
#define SIZE 200
|
|
struct Employee @{
|
|
char name[SIZE];
|
|
@}
|
|
extern int bar;
|
|
extern void foo(void);
|
|
").
|
|
@end example
|
|
|
|
Mercury automatically includes certain headers such as @code{<stdlib.h>},
|
|
but you should not rely on this, as the set of headers which Mercury
|
|
automatically includes is subject to change.
|
|
|
|
@node Including C code
|
|
@section Including C code
|
|
|
|
Definitions of C functions or global variables may be
|
|
included using a declaration of the form
|
|
|
|
@example
|
|
:- pragma c_code(@var{Code}).
|
|
@end example
|
|
|
|
For example,
|
|
|
|
@example
|
|
:- pragma c_code("
|
|
int bar = 42;
|
|
void foo(void) @{@}
|
|
").
|
|
@end example
|
|
|
|
Such code is copied verbatim into the generated C file.
|
|
|
|
@node Calling Mercury code from C
|
|
@section Calling Mercury code from C
|
|
|
|
It is also possible to export Mercury procedures to C,
|
|
so that you can call Mercury code from C (or from
|
|
other languages that can interface to C, e.g. C++).
|
|
|
|
A declaration of the form
|
|
|
|
@example
|
|
:- pragma export(@var{Pred}(@var{Mode1}, @var{Mode2}, @dots{}), "@var{C_Name_1}").
|
|
@end example
|
|
|
|
@noindent
|
|
or
|
|
|
|
@example
|
|
:- pragma export(@var{Func}(@var{Mode1}, @var{Mode2}, @dots{}) = @var{Mode}, "@var{C_Name_2}").
|
|
@end example
|
|
|
|
@noindent
|
|
exports a procedure for use by C.
|
|
|
|
For each Mercury module containing @samp{pragma export} declarations,
|
|
the Mercury implementation will automatically create a header file
|
|
for that module which declares a C function @var{C_Name()}
|
|
for each of the @samp{pragma export} declarations.
|
|
Each such C function is the C interface to the specified mode of
|
|
the specified Mercury predicate or function.
|
|
|
|
The interface to a Mercury procedure is determined as follows.
|
|
(The rules here are just the converse of the rules for @samp{pragma import}).
|
|
Mercury types are converted to C types according to the rules in
|
|
@ref{Passing data to and from C}.
|
|
Input arguments are passed by value. For output arguments, the
|
|
caller must pass the address in which to store the result.
|
|
If the Mercury procedure can fail, then its C interface function
|
|
returns a truth value indicating success or failure.
|
|
If the Mercury procedure is a Mercury function that cannot fail, and
|
|
the function result has an output mode, then the C interface
|
|
function will return the Mercury function result value.
|
|
Otherwise the function result is appended as an extra argument.
|
|
Arguments of type @samp{io__state} or @samp{store__store(_)}
|
|
are not passed at all; that's because these types represent mutable state,
|
|
and in C modifications to mutable state are done via side effects,
|
|
rather than argument passing.
|
|
|
|
Calling polymorphically typed Mercury procedures from C is a little bit
|
|
more difficult than calling ordinary (monomorphically typed) Mercury procedures.
|
|
The simplest method is to just create monomorphic forwarding
|
|
procedures that call the polymorphic procedures, and export them,
|
|
rather than exporting the polymorphic procedures.
|
|
|
|
If you do export a polymorphically typed Mercury procedure, the compiler
|
|
will prepend one @samp{type_info} argument to the parameter list of
|
|
the C interface function for each polymorphic type variable in the
|
|
Mercury procedure's type signature. The caller must arrange to pass
|
|
in appropriate @samp{type_info} values corresponding to the types
|
|
of the other arguments passed. These @samp{type_info} arguments can
|
|
be obtained using the Mercury @samp{type_of} function in the Mercury
|
|
standard library module @samp{std_util}.
|
|
|
|
@node Linking with C object files
|
|
@section Linking with C object files
|
|
|
|
A Mercury implementation should allow you to link with
|
|
object files or libraries that were produced by compiling C code.
|
|
The exact mechanism for linking with C object files is
|
|
implementation-dependent. The following text describes how
|
|
it is done for the University of Melbourne Mercury implementation.
|
|
|
|
To link an existing object file into your Mercury code,
|
|
set the @samp{Mmake} variable @samp{MLOBJS} in the
|
|
@samp{Mmake} file in the directory in which you are working.
|
|
To link an existing library into your Mercury code,
|
|
set the @samp{Mmake} variable @samp{MLLIBS}.
|
|
For example, the following will link in the object file
|
|
@samp{my_functions.o} from the current directory and
|
|
the library file @samp{libfancy_library.a}, or perhaps its
|
|
shared version @samp{fancy_library.so}, from the directory
|
|
@samp{/usr/local/contrib/lib}.
|
|
|
|
@example
|
|
MLOBJS = my_functions.o
|
|
MLFLAGS = -R/usr/local/contrib/lib -L/usr/local/contrib/lib
|
|
MLLIBS = -lfancy_library
|
|
@end example
|
|
|
|
As illustrated by the example, the values for @samp{MLFLAGS} and
|
|
@samp{MLLIBS} variables are similar to those taken by the Unix linker.
|
|
|
|
For more information, see the ``Libraries'' chapter of the
|
|
Mercury User's Guide, and the @samp{man} pages for @samp{mmc} and @samp{ml}.
|
|
|
|
@node Passing data to and from C
|
|
@section Passing data to and from C
|
|
|
|
For each of the Mercury types @code{int}, @code{float}, @code{char},
|
|
and @code{string}, there is a C typedef for the corresponding type in C:
|
|
@code{Integer}, @code{Float}, @code{Char}, and @code{String} respectively.
|
|
|
|
In the current implementation, @samp{Integer} is a typedef for an
|
|
integral type whose size is the same size as a pointer; @samp{Float} is
|
|
a typedef for @samp{double} (unless the program and the Mercury library
|
|
was compiled with @samp{-DUSE_SINGLE_PREC_FLOAT}, in which case it is
|
|
a typedef for @samp{float}); @samp{Char} is a typedef for @samp{char};
|
|
and @samp{String} is a typedef for @samp{Char *}.
|
|
|
|
Mercury variables of type @code{int}, @code{float}, @code{char}, or
|
|
@code{string} are passed to and from C as C variables whose type is
|
|
given by the corresponding typedef. Mercury variables of any other
|
|
type are passed as a @samp{Word}, which in the current implementation
|
|
is a typedef for an unsigned type whose size is the same size as a pointer.
|
|
(Note: it would in fact be better for each Mercury type to map to a distinct
|
|
abstract type in C, since that would be more type-safe, and thus we may
|
|
change this in a future release. We advise programmers who are manipulating
|
|
Mercury types in C code to use typedefs for each user-defined Mercury type,
|
|
and to treat each such type as an abstract data type. This is good style
|
|
and it will also minimize any compatibility problems if and when we do change
|
|
this.)
|
|
|
|
Mercury lists can be manipulated by C code using the following macros,
|
|
which are defined by the Mercury implementation.
|
|
|
|
@example
|
|
MR_list_is_empty(list) /* test if a list is empty */
|
|
MR_list_head(list) /* get the head of a list */
|
|
MR_list_tail(list) /* get the tail of a list */
|
|
MR_list_empty() /* create an empty list */
|
|
MR_list_cons(head,tail) /* construct a list with the given head and tail */
|
|
@end example
|
|
|
|
Note that the use of these macros is subject to some caveats
|
|
(@pxref{Memory management}).
|
|
|
|
@node Using C pointers
|
|
@section Using C pointers
|
|
|
|
The inbuilt Mercury type @code{c_pointer} can be used to pass C pointers
|
|
between C functions which are called from Mercury. For example:
|
|
|
|
@example
|
|
:- module pointer_example.
|
|
|
|
:- interface.
|
|
|
|
:- type complicated_c_structure.
|
|
|
|
% Initialise the abstract C structure that we pass around in Mercury.
|
|
:- pred initialise_complicated_structure(complicated_c_structure::uo) is det.
|
|
|
|
% Perform a calculation on the C structure.
|
|
:- pred do_calculation(int::in, complicated_structure::di,
|
|
complicated_structure::uo) is det.
|
|
|
|
:- implementation.
|
|
|
|
% Our C structure is implemented as a c_pointer.
|
|
:- type complicated_c_structure --->
|
|
complicated_c_structure(c_pointer).
|
|
|
|
:- pragma c_header_code("
|
|
extern struct foo *init_struct(void);
|
|
extern struct foo *perform_calculation(int, struct foo *);
|
|
");
|
|
|
|
:- pragma c_code(initialise_complicated_structure(Structure::uo),
|
|
[may_call_mercury],
|
|
"Structure = init_struct();").
|
|
|
|
:- pragma c_code(do_calculation(Value::in, Structure0::di, Structure::uo,
|
|
[may_call_mercury],
|
|
"Structure = perform_calculation(Value, Structure0);").
|
|
@end example
|
|
|
|
@node Memory management
|
|
@section Memory management
|
|
|
|
Passing pointers to dynamically-allocated memory from Mercury to code
|
|
written in other languages, or vice versa, is in general
|
|
implementation-dependent.
|
|
|
|
The current Mercury implementation supports two different methods of memory
|
|
management: conservative garbage collection, or no garbage collection.
|
|
(With the latter method, heap storage is reclaimed only on backtracking.)
|
|
|
|
Conservative garbage collection makes inter-language calls simplest.
|
|
When using conservative garbage collection, heap storage is reclaimed
|
|
automatically. Pointers to dynamically-allocated memory can be passed
|
|
to and from C without taking any special precautions.
|
|
|
|
When using no garbage collection, you must be careful not to retain
|
|
pointers to memory on the Mercury heap after Mercury has backtracked
|
|
to before the point where that memory was allocated.
|
|
You must also avoid the use of the macros
|
|
@code{list_empty()} and @code{list_cons()}.
|
|
(The reason for this is that they may access Mercury's @samp{hp} register,
|
|
which might not be valid in C code. Using them in the bodies of
|
|
procedures defined using @samp{pragma c_code} with
|
|
@samp{will_not_call_mercury} would probably work, but we don't advise it.)
|
|
Instead, you can write Mercury functions to perform these actions
|
|
and use @samp{pragma export} to access them from C.
|
|
This alternative method also works with conservative garbage collection.
|
|
|
|
Future Mercury implementations may use non-conservative methods
|
|
of garbage collection. For such implementations, it will be necessary
|
|
to explicitly register pointers passed to C with the garbage collector.
|
|
The mechanism for doing this has not yet been decided on.
|
|
It would be desirable to provide a single memory management interface
|
|
for use when interfacing with other languages that can work for all
|
|
methods of memory management, but more implementation experience is
|
|
needed before we can formulate such an interface.
|
|
|
|
@node Trailing
|
|
@section Trailing
|
|
|
|
In certain compilation grades (see the ``Compilation model options''
|
|
section of the Mercury User's Guide), the University of Melbourne
|
|
Mercury implementation supports trailing. Trailing is a means
|
|
of having side-effects, such as destructive updates to data structures,
|
|
undone on backtracking. The basic idea is that during forward
|
|
execution, whenever you perform a destructive modification to
|
|
a data structure that may still be live on backtracking,
|
|
you should record whatever information is necessary to restore it
|
|
on a stack-like data structure called the ``trail''. Then, if
|
|
a computation fails, and execution backtracks to before those
|
|
those updates were performed, the Mercury runtime engine will
|
|
traverse the trail back to the most recent choice point,
|
|
undoing all those updates.
|
|
|
|
The interface used is a set of C functions (which are actually
|
|
implemented as macros) and types. Typically these will be
|
|
called from C code within @samp{pragma c_code} declarations
|
|
in Mercury code.
|
|
|
|
For examples of the use of this interface, see the modules
|
|
@file{extras/trailed_update/tr_array.m} and
|
|
@file{extras/clpr/cfloat.m} in the Mercury distribution.
|
|
|
|
@menu
|
|
* Choice points::
|
|
* Value trailing::
|
|
* Function trailing::
|
|
* Delayed goals and floundering::
|
|
* Avoiding redundant trailing::
|
|
@end menu
|
|
|
|
@node Choice points
|
|
@subsection Choice points
|
|
|
|
A ``choice point'' is a point in the computation to
|
|
which execution might backtrack when a goal fails or
|
|
throws an exception. The ``current''
|
|
choice point is the one that was most recently
|
|
encountered; that is also the one to which execution
|
|
will branch if the current computation fails.
|
|
|
|
When you trail an update, the Mercury engine will ensure that if
|
|
execution ever backtracks to the choice point that was current
|
|
at the time of trailing, then the update will be undone.
|
|
|
|
If the Mercury compiler determines that it will never
|
|
need to backtrack to a particular choice point, then it will
|
|
``prune'' away that choice point. If a choice point is pruned,
|
|
the trail entries for those updates will not necessarily be discarded,
|
|
because in general they may still be necessary in case we backtrack
|
|
to a prior choice point.
|
|
|
|
@node Value trailing
|
|
@subsection Value trailing
|
|
|
|
The simplest form of trailing is value trailing.
|
|
This allows you to trail updates to memory and have
|
|
the Mercury runtime engine automatically undo them
|
|
on backtracking.
|
|
|
|
@table @b
|
|
@item @bullet{} @code{MR_trail_value()}
|
|
Prototype:
|
|
@example
|
|
void MR_trail_value(Word *@var{address}, Word @var{value});
|
|
@end example
|
|
|
|
Ensures that if future execution backtracks to the
|
|
current choice point, then @var{value} will be placed in @var{address}.
|
|
@sp 1
|
|
@item @bullet{} @code{MR_trail_current_value()}
|
|
Prototype:
|
|
@example
|
|
void MR_trail_current_value(Word *@var{address});
|
|
@end example
|
|
|
|
Ensures that if future execution backtracks to the
|
|
current choice point, the value currently in @var{address}
|
|
will be restored.
|
|
|
|
@samp{MR_trail_current_value(@var{address})} is equivalent to
|
|
@samp{MR_trail_value(@var{address}, *@var{address})}.
|
|
|
|
@end table
|
|
|
|
@node Function trailing
|
|
@subsection Function trailing
|
|
|
|
For more complicated uses of trailing, you can store the address
|
|
of a C function on the trail and have the Mercury runtime call your
|
|
function back whenever future execution backtracks to the current choice point
|
|
or earlier, or whenever that choice point is pruned, because execution
|
|
commits to never backtracking over that point,
|
|
or whenever that choice point is garbage collected.
|
|
|
|
Note the garbage collector in the current Mercury implementation
|
|
does not garbage-collect the trail; this case is mentioned
|
|
only so that we can cater for possible future extensions.
|
|
|
|
@table @b
|
|
@item @bullet{} @code{MR_trail_function()}
|
|
Prototype:
|
|
@example
|
|
typedef enum @{
|
|
MR_undo,
|
|
MR_exception,
|
|
MR_retry,
|
|
MR_commit,
|
|
MR_solve,
|
|
MR_gc
|
|
@} MR_untrail_reason;
|
|
|
|
void MR_trail_function(
|
|
void (*@var{untrail_func})(Word, MR_untrail_reason),
|
|
void *@var{value}
|
|
);
|
|
@end example
|
|
@noindent
|
|
A call to @samp{MR_trail_function(@var{untrail_func}, @var{value})}
|
|
adds an entry to the function trail.
|
|
The Mercury implementation ensures that
|
|
if future execution ever backtracks to current choicepoint,
|
|
or backtracks past the current choicepoint to some earlier choicepoint,
|
|
then @code{(*@var{untrail_func})(@var{value}, @var{reason})} will be called,
|
|
where @var{reason} will be @samp{MR_undo} if the backtracking was due to
|
|
a goal failing, @samp{MR_exception} if the backtracking was due to
|
|
a goal throwing an exception, or @samp{MR_retry} if the backtracking
|
|
was due to the use of the "retry" command in mdb, the Mercury debugger,
|
|
or any similar user request in a debugger.
|
|
The Mercury implementation also ensures that if the current choice point is
|
|
pruned because execution commits to never backtracking to it,
|
|
then @code{(*@var{untrail_func})(@var{value}, MR_commit)} will be called.
|
|
It also ensures that if execution requires that the current goal be
|
|
solvable, then @code{(*@var{untrail_func})(@var{value}, MR_solve)}
|
|
will be called. This happens in calls to @code{solutions/2}, for example.
|
|
(@code{MR_commit} is used for ``hard'' commits, i.e. when we commit
|
|
to a solution and prune away the alternative solutions; @code{MR_solve}
|
|
is used for ``soft'' commits, i.e. when we must commit to a solution
|
|
but do not prune away all the alternatives.)
|
|
|
|
MR_gc is currently not used ---
|
|
it is reserved for future use.
|
|
|
|
@end table
|
|
|
|
Typically if the @var{untrail_func} is called with @var{reason} being
|
|
@samp{MR_undo}, @samp{MR_exception}, or @samp{MR_retry}, then it should undo
|
|
the effects of the update(s) specified by @var{value}, and the free any
|
|
resources associated with that trail entry. If it is called with @var{reason}
|
|
being @samp{MR_commit} or @samp{MR_solve}, then it not undo the update(s);
|
|
instead, it may check for floundering (see the next section).
|
|
In the @samp{MR_commit} case it may, in some cases, be possible to
|
|
also free resources associated with the trail entry.
|
|
If it is called with anything else (such as @samp{MR_gc}),
|
|
then it should probably abort execution with an error message.
|
|
|
|
@node Delayed goals and floundering
|
|
@subsection Delayed goals and floundering
|
|
|
|
Another use for the function trail is check for floundering
|
|
in the presence of delayed goals.
|
|
|
|
Often, when implementing certain kinds of constraint solvers, it may
|
|
not be possible to actually solve all of the constraints at the time
|
|
they are added. Instead, it may be necessary to simply delay their
|
|
execution until a later time, in the hope the constraints may become
|
|
solvable when more information is available. If you do implement a
|
|
constraint solver with these properties, then at certain points in
|
|
the computation --- for example, after executing a negated goal --- it
|
|
is important for the system to check that their are no outstanding
|
|
delayed goals which might cause failure, before execution commits
|
|
to this execution path. If there are any such delayed goals, the
|
|
computation is said to ``flounder''. If the check for floundering was
|
|
omitted, then it could lead to unsound behaviour, such as a negation
|
|
failing even though logically speaking it ought to have succeeded.
|
|
|
|
The check for floundering can be implemented using the function trail,
|
|
by simply calling @samp{MR_trail_function()} to add a function trail
|
|
entry whenever you create a delayed goal, and putting the appropriate
|
|
check for floundering in the @samp{MR_commit} and @samp{MR_solve} cases
|
|
of your function.
|
|
The Mercury distribution includes some examples of this:
|
|
see the @samp{ML_cfloat_untrail_func()}
|
|
function in the file @samp{extras/clpr/cfloat.m} and the
|
|
@samp{ML_var_untrail_func()} function in the file
|
|
@samp{extras/trailed_update/var.m}.)
|
|
If your function does detect floundering, then it should print
|
|
an error message and then abort execution.
|
|
|
|
@node Avoiding redundant trailing
|
|
@subsection Avoiding redundant trailing
|
|
|
|
If a mutable data structure is updated multiple times, and each update
|
|
is recorded on the trail using the functions described above, then
|
|
some of this trailing may be redundant. It is generally not necessary
|
|
to record enough information to recover the original state of the
|
|
data structure for @emph{every} update on the trail; instead, it is
|
|
enough to record the original state of each updated data structure
|
|
just once for each choice point occurring after the data structure
|
|
is allocated, rather than once for each update.
|
|
|
|
The functions described below provide a means to avoid
|
|
redundant trailing.
|
|
|
|
@table @b
|
|
@item @bullet{} @code{MR_ChoicepointId}
|
|
Declaration:
|
|
@example
|
|
typedef @dots{} MR_ChoicepointId;
|
|
@end example
|
|
|
|
The type @code{MR_ChoicepointId} is an abstract type used
|
|
to hold the identity of a choice point. Values of this
|
|
type can be compared using C's @samp{==} operator
|
|
or using @samp{MR_choicepoint_newer()}.
|
|
@sp 1
|
|
@item @bullet{} @code{MR_current_choicepoint_id()}
|
|
Prototype:
|
|
@example
|
|
MR_ChoicepointId MR_current_choicepoint_id(void);
|
|
@end example
|
|
|
|
@code{MR_current_choicepoint_id()} returns a value indicating
|
|
the identity of the most recent choice point; that is, the
|
|
point to which execution would backtrack if the current computation
|
|
failed.
|
|
The value remains meaningful if the choicepoint is pruned
|
|
away by a commit, but is not meaningful after backtracking
|
|
past the point where the choicepoint was created (since
|
|
choicepoint ids may be reused after backtracking).
|
|
@sp 1
|
|
@item @bullet{} @code{MR_null_choicepoint_id()}
|
|
Prototype:
|
|
@example
|
|
MR_ChoicepointId MR_null_choicepoint_id(void);
|
|
@end example
|
|
|
|
@code{MR_null_choicepoint_id()} returns a ``null'' value that is
|
|
distinct from any value ever returned by @code{MR_current_choicepoint_id}.
|
|
(Note that @code{MR_null_choicepoint_id()}
|
|
is a macro that is guaranteed to be suitable for use as a
|
|
static initializer, so that it can for example be used to
|
|
provide the initial value of a C global variable.)
|
|
@sp 1
|
|
@item @bullet{} @code{MR_choicepoint_newer()}
|
|
Prototype:
|
|
@example
|
|
bool MR_choicepoint_newer(MR_ChoicepointId, MR_ChoicepointId);
|
|
@end example
|
|
|
|
@code{MR_choicepoint_newer(x, y)} true iff the choicepoint indicated by
|
|
@samp{x} is newer than (i.e. was created more recently than) the
|
|
choicepoint indicated by @samp{y}. The null ChoicepointId is considered
|
|
older than any non-null ChoicepointId. If either of the choice points
|
|
have been backtracked over, the behaviour is undefined.
|
|
|
|
@end table
|
|
|
|
The way these functions are generally used is as follows.
|
|
When you create a mutable data structure, you should call
|
|
@code{MR_current_choicepoint_id()} and save the value it returns
|
|
as a @samp{prev_choicepoint} field in your data structure.
|
|
(If your mutable data structure
|
|
is a C global variable, then you can use MR_null_choicepoint_id()
|
|
for the initial value of this @samp{prev_choicepoint} field.)
|
|
When you are about to modify your mutable data structure,
|
|
you can then call @code{MR_current_choicepoint_id()} again and
|
|
compare the result from that call with the value saved in
|
|
the @samp{prev_choicepoint} field in the data structure
|
|
using @code{MR_choicepoint_newer()}.
|
|
If the current choicepoint is newer, then you must trail the update,
|
|
and update the @samp{prev_choicepoint} field with the new value;
|
|
furthermore, you must also take care that on backtracking the
|
|
previous value of the @samp{prev_choicepoint} field in your data
|
|
structure is restored to its previous value, by trailing that update too.
|
|
But if @code{MR_current_choice_id()} is not newer than the
|
|
@code{prev_choicepoint} field, then you can safely perform
|
|
the update to your data structure without trailing it.
|
|
|
|
For an example, see the sample module below.
|
|
|
|
Note that there is a cost to this -- you have to include
|
|
an extra field in your data structure for each part of
|
|
the data structure which you might update, you
|
|
need to perform a test for each update to decide whether
|
|
or not to trail it, and if you do need to trail the update,
|
|
then you have an extra field that you need to trail.
|
|
Whether or not the benefits from avoiding redundant trailing
|
|
outweigh these costs will depend on your application.
|
|
|
|
@example
|
|
:- module trailing_example.
|
|
:- interface.
|
|
|
|
:- type int_ref.
|
|
|
|
% Create a new int_ref with the specified value.
|
|
:- pred new_int_ref(int_ref::uo, int::in) is det.
|
|
|
|
% update_int_ref(Ref0, Ref, OldVal, NewVal):
|
|
% Ref0 has value OldVal and Ref has value NewVal.
|
|
:- pred update_int_ref(int_ref::mdi, int_ref::muo,
|
|
int::out, int::in) is det.
|
|
|
|
:- implementation.
|
|
|
|
:- type int_ref ---> int_ref(c_pointer).
|
|
|
|
:- pragma import(new_int_ref(uo, in),
|
|
"new_int_ref").
|
|
:- pragma import(update_int_ref(mdi, muo, out, in),
|
|
"update_int_ref").
|
|
|
|
:- pragma c_header_code("
|
|
typedef Word Mercury_IntRef;
|
|
void new_int_ref(Mercury_IntRef *ref, Integer value);
|
|
void update_int_ref(Mercury_IntRef ref0, Mercury_IntRef *ref,
|
|
Integer *old_value, Integer new_value);
|
|
").
|
|
|
|
:- pragma c_code("
|
|
typedef struct @{
|
|
MR_ChoicepointId prev_choicepoint;
|
|
Integer data;
|
|
@} C_IntRef;
|
|
|
|
void
|
|
new_int_ref(Mercury_IntRef *ref, Integer value)
|
|
@{
|
|
C_IntRef *x = malloc(sizeof(C_IntRef));
|
|
x->prev_choicepoint = MR_current_choicepoint_id();
|
|
x->data = value;
|
|
*ref = (Mercury_IntRef) x;
|
|
@}
|
|
|
|
void
|
|
update_int_ref(Mercury_IntRef ref0, Mercury_IntRef *ref,
|
|
Integer *old_value, Integer new_value)
|
|
@{
|
|
C_IntRef *x = (C_IntRef *) ref0;
|
|
*old_value = x->data;
|
|
|
|
/* check whether we need to trail this update */
|
|
if (MR_choicepoint_newer(MR_current_choicepoint_id(),
|
|
x->prev_choicepoint))
|
|
@{
|
|
/* trail both x->data and x->prev_choicepoint,
|
|
since we're about to update them both*/
|
|
assert(sizeof(x->data) == sizeof(Word));
|
|
assert(sizeof(x->prev_choicepoint) == sizeof(Word));
|
|
MR_trail_current_value((Word *)&x->data);
|
|
MR_trail_current_value((Word *)&x->prev_choicepoint);
|
|
|
|
/* update x->prev_choicepoint to indicate that
|
|
x->data's previous value has been trailed
|
|
at this choice point */
|
|
x->prev_choicepoint = MR_current_choicepoint_id();
|
|
@}
|
|
x->data = new_value;
|
|
*ref = ref0;
|
|
@}
|
|
").
|
|
@end example
|
|
|
|
@c @item @code{void MR_untrail_to(MR_TrailEntry *@var{old_trail_ptr}, MR_untrail_reason @var{reason});}
|
|
@c
|
|
@c Apply all the trail entries between @samp{MR_trail_ptr} and
|
|
@c @var{old_trail_ptr}, using the specified @var{reason}.
|
|
@c
|
|
@c This function is called by the Mercury engine after backtracking,
|
|
@c after a commit, or after catching an exception.
|
|
@c There is probably little need for user code to call this function,
|
|
@c but it might be needed if you're doing certain low-level things
|
|
@c such as implementing your own exception handling.
|
|
|
|
@node Impurity
|
|
@chapter Impurity declarations
|
|
|
|
In order to efficiently implement certain predicates, it is occasionally
|
|
necessary to venture outside pure logic programming. Other predicates
|
|
cannot be implemented at all within the paradigm of logic programming,
|
|
for example, all solutions predicates. Such predicates are often
|
|
written using the C interface. Sometimes, however, it would be more
|
|
convenient, or more efficient, to write such predicates using the
|
|
facilities of Mercury. For example, it is much more convenient to
|
|
access arguments of compound Mercury terms in Mercury than in C, and the
|
|
ability of the Mercury compiler to specialize code can make higher-order
|
|
predicates written in Mercury significantly more efficient than similar
|
|
C code.
|
|
|
|
One important aim of Mercury's impurity system is to make the
|
|
distinction between the pure and impure code very clear. This is done
|
|
by requiring every impure predicate to be so declared, and by requiring
|
|
every call to an impure predicate to be flagged as such. Predicates
|
|
that are implemented in terms of impure predicates are assumed to be
|
|
impure themselves unless they are explicitly promised to be pure.
|
|
|
|
Please note that the facilities described here are needed only very
|
|
rarely. The main intent is for implementing language primitives such as
|
|
the all solutions predicates. Any use of @samp{impure} or @samp{semipure}
|
|
probably indicates either a weakness in the Mercury standard library, or
|
|
the programmer's lack of familiarity with the standard library.
|
|
Newcomers to Mercury are hence encouraged to @strong{skip this section}.
|
|
|
|
|
|
|
|
@menu
|
|
* Purity levels:: Choosing the right level of purity.
|
|
* Impurity semantics:: What impure code means.
|
|
* Declaring impurity:: Declaring predicates impure.
|
|
* Impure calls:: Marking a call as impure.
|
|
* Promising purity:: Promising that a predicate is pure.
|
|
* Impurity Example:: A simple example using impurity.
|
|
@end menu
|
|
|
|
|
|
@node Purity levels
|
|
@section Choosing the right level of purity
|
|
|
|
Mercury distinguishes three ``levels'' of purity:
|
|
|
|
@table @dfn
|
|
@item pure
|
|
Pure predicates and functions always return the same outputs given the
|
|
same inputs. They do not interact with the ``real'' world (i.e., do any
|
|
input/output) without taking an io__state (@pxref{Types}) as input and
|
|
returning one as output, and do not make any changes to any data
|
|
structure that will not be undone on backtracking (unless the data
|
|
structure would be unreachable on backtracking). The behaviour of other
|
|
predicates is never affected by the invocation of pure predicates, nor
|
|
is the behaviour of pure predicates ever affected by the invocation of
|
|
other predicates.
|
|
|
|
The vast majority of Mercury predicates are pure.
|
|
|
|
@item semipure
|
|
Semipure predicates are just like pure predicates, except that their
|
|
behaviour may be affected by the invocation of impure predicates. That
|
|
is, they are sensitive to the state of the computation other than as
|
|
reflected by their input arguments, though they do not affect the state
|
|
themselves.
|
|
|
|
@item impure
|
|
Impure predicates may do anything, including changing the state of the
|
|
computation.
|
|
|
|
@end table
|
|
|
|
|
|
@node Impurity semantics
|
|
@section Semantics
|
|
|
|
It is important to the proper operation of impure and semipure code, to
|
|
the flexibility of the compiler to optimize pure code, and to the
|
|
semantics of the Mercury language, that a clear distinction be drawn
|
|
between ordinary Mercury code and imperative code written with Mercury
|
|
syntax. How this distinction is drawn will be explained below; the
|
|
purpose of this section is to explain the semantics of programs with
|
|
impure predicates.
|
|
|
|
A @emph{declarative} semantics of impure Mercury code would be largely
|
|
useless, because the declarative semantics cannot capture the intent of
|
|
the programmer. Impure predicates are executed for their side-effects,
|
|
which by definition are not part of their declarative semantics. Thus
|
|
it is the @emph{operational} semantics of impure predicates that Mercury
|
|
must specify, and Mercury compilers must respect.
|
|
|
|
The operational semantics of a Mercury predicate which invokes impure
|
|
code is a modified form of the @emph{strict sequential} semantics
|
|
(@pxref{Semantics}). @emph{Impure} goals may not be reordered relative
|
|
to any other goals; not even ``minimal'' reordering as implied by the
|
|
modes is permitted. If any such reordering is needed, this is a mode
|
|
error. However, @emph{pure} and @emph{semipure} goals may be reordered
|
|
as long as they are not moved across an impure goal. Execution of
|
|
impure goals is strict: they must be executed if they are reached, even
|
|
if it can be determined that that computation cannot lead to successful
|
|
termination.
|
|
|
|
Semipure goals can be given a ``contextual'' declarative semantics.
|
|
They cannot have any side-effects, so it is expected that, given the
|
|
context in which they are called (relative to any impure goals in the
|
|
program), their declarative semantics fully captures the intent of the
|
|
programmer. Thus a semipure goal has a perfectly consistent declarative
|
|
semantics, until an impure goal is reached. After that, it has another
|
|
(possibly different) declarative semantics, until the next impure goal
|
|
is executed, and so on. Mercury compilers must respect this contextual
|
|
nature of the semantics of semipure goals; within a single context, a
|
|
compiler may treat a semipure goal as if it were pure.
|
|
|
|
|
|
@node Declaring impurity
|
|
@section Declaring predicate impurity
|
|
|
|
A predicate is declared to be impure or semipure by preceding the word
|
|
@code{pred} in its @code{pred} declaration with @code{impure}
|
|
or @code{semipure}, respectively. That is, a declaration of the form:
|
|
|
|
@example
|
|
:- impure pred @var{Pred}(@var{Arguments}@dots{}).
|
|
@end example
|
|
|
|
@noindent
|
|
or
|
|
|
|
@example
|
|
:- semipure pred @var{Pred}(@var{Arguments}@dots{}).
|
|
@end example
|
|
|
|
@noindent
|
|
declares the predicate @var{Pred} to be impure or semipure, respectively.
|
|
|
|
|
|
@node Impure calls
|
|
@section Marking a call as impure
|
|
|
|
If a predicate is impure or semipure, all calls to it must be preceded
|
|
with the word @code{impure} or @code{semipure}, respectively. Note
|
|
that only predicate calls need to (and are permitted to) be prefixed
|
|
with @code{impure} or @code{semipure}, compound goals never need this.
|
|
See @ref{Impurity Example} for an example of this.
|
|
|
|
The requirement that impure or semipure calls be marked with
|
|
@code{impure} or @code{semipure} allows someone
|
|
reading the code to tell which goals are not pure, making code which
|
|
relies on side effects somewhat less mysterious. Furthermore, it means
|
|
that if a call is @emph{not} preceded by @code{impure} or
|
|
@code{semipure}, then the reader can rely on the call having a proper
|
|
declarative semantics, without hidden side-effects.
|
|
|
|
|
|
@node Promising purity
|
|
@section Promising that a predicate is pure
|
|
|
|
Some predicates which call impure or semipure predicates are themselves
|
|
pure. In fact, the main purpose of the Mercury impurity system is to
|
|
allow programmers to write pure predicates using impure ones, while protecting
|
|
the procedural implementation from aggressive compiler optimizations.
|
|
Of course, the Mercury compiler cannot verify that a predicate is pure,
|
|
so it is the programmer's responsibility to ensure this. If a predicate
|
|
is promised pure and is not, the behaviour of the program is undefined.
|
|
|
|
The programmer may promise that a predicate is pure using the
|
|
@code{promise_pure} pragma:
|
|
|
|
@example
|
|
:- pragma promise_pure(@var{Name}/@var{Arity}).
|
|
@end example
|
|
|
|
|
|
@node Impurity Example
|
|
@section An example using impurity
|
|
|
|
The following example illustrates how a pure predicate may be
|
|
implemented using impure code. Note that this code is not reentrant,
|
|
and so is not useful as is. It is meant only as an example.
|
|
|
|
@example
|
|
:- pragma c_header_code("#include <limits.h>").
|
|
:- pragma c_header_code("Integer max;").
|
|
|
|
:- impure pred init_max is det.
|
|
:- pragma c_code(init_max,
|
|
[will_not_call_mercury],
|
|
"max = INT_MIN;").
|
|
|
|
:- impure pred set_max(int::in) is det.
|
|
:- pragma c_code(set_max(X::in),
|
|
[will_not_call_mercury],
|
|
"if (X > max) max = X;").
|
|
|
|
:- semipure pred get_max(int::out) is det.
|
|
:- pragma c_code(get_max(X::out),
|
|
[will_not_call_mercury],
|
|
"X = max;").
|
|
|
|
:- pragma promise_pure(max_solution/2).
|
|
:- pred max_solution(pred(int), int).
|
|
:- mode max_solution(pred(out) is multi, out) is det.
|
|
|
|
max_solution(Generator, Max) :-
|
|
impure init_max,
|
|
( Generator(X),
|
|
impure set_max(X),
|
|
fail
|
|
; semipure get_max(Max)
|
|
).
|
|
@end example
|
|
|
|
@node Pragmas
|
|
@chapter Pragmas
|
|
|
|
The pragma declarations described below are a standard part of the
|
|
Mercury language, as are the pragmas for controlling the C interface
|
|
(@pxref{C interface}) and impurity (@pxref{Impurity}).
|
|
As an extension, implementations may also choose to support additional
|
|
pragmas with implementation-dependent semantics
|
|
(@pxref{Implementation-dependent extensions}).
|
|
|
|
@menu
|
|
* Inlining:: Pragmas can be used to suggest or prevent
|
|
procedure inlining.
|
|
* Type specialization:: Pragmas can be used to produce specialized
|
|
versions of polymorphic procedures.
|
|
* Obsolescence:: Library developers can declare old versions
|
|
of predicates or functions to be obsolete.
|
|
* Source file name:: The @samp{source_file} pragma and
|
|
@samp{#@var{line}} directives provide support
|
|
for preprocessors and other tools that
|
|
generate Mercury code.
|
|
@end menu
|
|
|
|
@node Inlining
|
|
@section Inlining
|
|
|
|
A declaration of the form
|
|
|
|
@example
|
|
:- pragma inline(@var{Name}/@var{Arity}).
|
|
@end example
|
|
|
|
@noindent
|
|
is a hint to the compiler that all calls to the predicate(s) or function(s)
|
|
with name @var{Name} and arity @var{Arity} should be inlined.
|
|
|
|
The current Mercury implementation is smart enough to inline
|
|
simple predicates even without this hint.
|
|
|
|
A declaration of the form
|
|
|
|
@example
|
|
:- pragma no_inline(@var{Name}/@var{Arity}).
|
|
@end example
|
|
|
|
@noindent
|
|
ensures the compiler will not inline this predicate. This may be used
|
|
simply for performance concerns (inlining can cause unwanted code bloat
|
|
in some cases) or to prevent possibly dangerous inlining when using
|
|
low-level C code.
|
|
|
|
@node Type specialization
|
|
@section Type specialization
|
|
|
|
The overhead of polymorphism can in some cases be significant, especially
|
|
where polymorphic predicates make heavy use of class method calls or the
|
|
built-in unification and comparison routines. To avoid this, the programmer
|
|
can suggest to the compiler that a specialized version of a procedure should
|
|
be created for a specific set of argument types.
|
|
|
|
@menu
|
|
* Syntax and semantics of type specialization pragmas::
|
|
* When to use type specialization::
|
|
* Implementation specific details::
|
|
@end menu
|
|
|
|
@node Syntax and semantics of type specialization pragmas
|
|
@subsection Syntax and semantics of type specialization pragmas
|
|
|
|
A declaration of the form
|
|
|
|
@example
|
|
:- pragma type_spec(@var{Name}/@var{Arity}, @var{Subst}).
|
|
:- pragma type_spec(@var{Name}(@var{Modes}), @var{Subst}).
|
|
@end example
|
|
|
|
@noindent
|
|
suggests to the compiler that a specialized version of predicate(s)
|
|
or function(s) with name @var{Name} and arity @var{Arity} should be
|
|
created with the type substitution given by @var{Subst} applied to the
|
|
argument types. The second form of the declaration only suggests
|
|
specialization of the specified mode of the predicate or function.
|
|
|
|
The substitution is written as a conjunction of bindings of the form
|
|
@w{@samp{@var{TypeVar} = @var{Type}}}, for example @w{@samp{K = int}} or
|
|
@w{@samp{(K = int, V = list(int))}}.
|
|
|
|
The declarations
|
|
|
|
@example
|
|
:- pred map__lookup(map(K, V), K, V).
|
|
:- pragma type_spec(map__lookup/3, K = int).
|
|
@end example
|
|
|
|
@noindent
|
|
give a hint to the compiler that a version of @samp{map__lookup/3} should
|
|
be created for integer keys.
|
|
|
|
Implementations are free to ignore @samp{pragma type_spec} declarations.
|
|
Implementations are also free to perform type specialization
|
|
even in the absence of any @samp{pragma type_spec} declarations.
|
|
|
|
@node When to use type specialization
|
|
@subsection When to use type specialization
|
|
|
|
The set of types for which a predicate or function should be specialized is
|
|
best determined by profiling your application. Overuse of type specialization
|
|
will result in code bloat.
|
|
|
|
Type specialization of predicates or functions which
|
|
unify or compare polymorphic variables is most effective when
|
|
the specialized types are built-in types such as @samp{int}, @samp{float}
|
|
and @samp{string}, or enumeration types, since their unification and
|
|
comparison procedures are simple and can be inlined.
|
|
|
|
Predicates or functions which make use of type class method calls
|
|
may also be candidates for specialization. Again, this is most effective
|
|
when the called type class methods are simple enough to be inlined.
|
|
|
|
@node Implementation specific details
|
|
@subsection Implementation specific details
|
|
|
|
The University of Melbourne Mercury compiler performs user-requested type
|
|
specializations when invoked with @samp{--user-guided-type-specialization},
|
|
which is enabled at optimization level @samp{-O2} or higher.
|
|
|
|
@node Obsolescence
|
|
@section Obsolescence
|
|
|
|
A declaration of the form
|
|
|
|
@example
|
|
:- pragma obsolete(@var{Name}/@var{Arity}).
|
|
@end example
|
|
|
|
@noindent
|
|
declares that the predicate(s) or function(s)
|
|
with name @var{Name} and arity @var{Arity} are ``obsolete'':
|
|
it instructs the compiler to issue a warning whenever the named
|
|
predicate(s) or function(s) are used.
|
|
|
|
@samp{pragma obsolete} declarations are intended for use by library
|
|
developers, to allow gradual (rather than abrupt) evolution of library
|
|
interfaces. If a library developer changes the interface of a library
|
|
predicate, they should leave the old version of that predicate in the
|
|
library, but mark it as obsolete using a @samp{pragma obsolete}
|
|
declaration, and document how library users should modify their code to
|
|
suit the new interface. The users of the library will then get a
|
|
warning if they use obsolete features, and can consult the library
|
|
documentation to determine how to fix their code. Eventually, when the
|
|
library developer deems that users have had sufficient warning, they
|
|
can remove the old version entirely.
|
|
|
|
@node Source file name
|
|
@section Source file name
|
|
|
|
The @samp{source_file} pragma and @samp{#@var{line}} directives provide
|
|
support for preprocessors and other tools that generate Mercury code.
|
|
The tool can insert these directives into the generated Mercury code
|
|
to allow the Mercury compiler to report diagnostics (error and warning
|
|
messages) at the original source code location, rather than at the
|
|
location in the automatically generated Mercury code.
|
|
|
|
A @samp{source_file} pragma is a declaration of the form
|
|
|
|
@example
|
|
:- pragma source_file(@var{Name}).
|
|
@end example
|
|
|
|
@noindent
|
|
where @var{Name} is a string that specifies the name of the source file.
|
|
|
|
For example, if a preprocessor generated a file @file{foo.m} based on a
|
|
input file @file{foo.m.in}, and it copied lines 20, 30, and 31 from
|
|
@file{foo.m.in}, the following directives would ensure that any
|
|
error or warnings for those lines copied from @file{foo.m} were reported
|
|
at their original source locations in @file{foo.m.in}.
|
|
|
|
@example
|
|
:- module foo.
|
|
:- pragma source_file("foo.m.in").
|
|
#20
|
|
% this line comes from line 20 of foo.m
|
|
#30
|
|
% this line comes from line 30 of foo.m
|
|
% this line comes from line 31 of foo.m
|
|
:- pragma source_file("foo.m").
|
|
#10
|
|
% this automatically generated line is line 10 of foo.m
|
|
@end example
|
|
|
|
Note that if a generated file contains some text which is copied from a
|
|
source file, and some which is automatically generated, it is a good
|
|
idea to use @samp{pragma source_file} and @samp{#@var{line}} directives
|
|
to reset the source file name and line number to point back to the
|
|
generated file for the automatically generated text, as in the above
|
|
example.
|
|
|
|
@node Implementation-dependent extensions
|
|
@chapter Implementation-dependent extensions
|
|
|
|
The University of Melbourne Mercury implementation supports the following
|
|
extensions to the Mercury language:
|
|
|
|
@menu
|
|
* Fact tables:: Support for very large tables of facts.
|
|
* Tabled evaluation:: Support for automatically recording previously
|
|
calculated results and detecting or avoiding
|
|
certain kinds of infinite loops.
|
|
* Termination analysis:: Support for automatic proofs of termination.
|
|
@ifset aditi
|
|
* Aditi deductive database interface::
|
|
Support for bottom-up evaluation of Mercury
|
|
predicates.
|
|
@end ifset
|
|
@end menu
|
|
|
|
@node Fact tables
|
|
@section Fact tables
|
|
|
|
Large tables of facts can be compiled using a different algorithm that
|
|
is more efficient and produces more efficient code.
|
|
|
|
A declaration of the form
|
|
|
|
@example
|
|
:- pragma fact_table(@var{Name}/@var{Arity}, @var{FileName}).
|
|
@end example
|
|
|
|
@noindent
|
|
tells the compiler that the predicate or function with name @var{Name}
|
|
and arity @var{Arity} is defined by a set of facts in an external file
|
|
@var{FileName}. Defining large tables of facts in this way allows the
|
|
compiler to use a more efficient algorithm for compiling them.
|
|
This algorithm uses less memory than would normally be required
|
|
to compile the facts so much larger tables are possible.
|
|
|
|
Each mode is indexed on all its input arguments so the compiler can
|
|
produce very efficient code using this technique.
|
|
|
|
In the current implementation, the table of facts is compiled into a
|
|
separate C file named @samp{@var{FileName}.c}. The compiler will
|
|
automatically generate the correct dependencies for this file when the
|
|
command @samp{mmake @var{main_module}.depend} is invoked. This ensures
|
|
that the C file will be compiled to @samp{@var{FileName}.o} and then
|
|
linked with the other object files when @samp{mmake @var{main_module}}
|
|
is invoked.
|
|
|
|
The main limitation of the @samp{fact_table} pragma is that
|
|
predicates or functions defined as fact tables can only have
|
|
arguments of types @samp{string}, @samp{int} or @samp{float}.
|
|
|
|
@node Tabled evaluation
|
|
@section Tabled evaluation
|
|
|
|
(Note: ``Tabled evaluation'' has no relation to the ``fact tables''
|
|
described above.)
|
|
|
|
Ordinarily, the results of each procedure call are not recorded;
|
|
if the same procedure is called with the same arguments,
|
|
then the answer(s) must be recomputed again.
|
|
For some procedures, this recomputation can be very wasteful.
|
|
|
|
With tabled evaluation, the implementation keeps a table containing the
|
|
previously computed results of the specified procedure; at each
|
|
procedure call, the implementation will search the table to check
|
|
whether the answer(s) have already been computed and if so, the answers
|
|
will be returned directly from the tables rather than being recomputed.
|
|
This can result in much faster execution, at the cost of additional
|
|
space to record answers in the table.
|
|
|
|
The implementation can optionally also check at runtime for the situation
|
|
where a procedure calls itself recursively with the same arguments,
|
|
which would normally result in a infinite loop; if this situation is
|
|
encountered, it can (at the programmer's option) either throw an
|
|
exception, or avoid the infinite loop by computing solutions
|
|
using the ``minimal model'' semantics.
|
|
|
|
The current Mercury implementation thus supports three different
|
|
pragmas for tabling, to cover these three cases: @samp{pragma memo}
|
|
does no loop checking, @samp{pragma loop_check} checks for loops
|
|
and throws an exception if a loop is detected, while
|
|
@samp{pragma minimal_model} computes the ``minimal model'' semantics.
|
|
|
|
@c XXX we should fix this bug...
|
|
@cartouche
|
|
@strong{Warning:}
|
|
The current implementation of @samp{pragma minimal_model} is broken:
|
|
the generated code sometimes produces incorrect results. It should
|
|
not be used. Also the current implementation of all three pragmas
|
|
is broken for procedures with determinism @samp{nondet} or @samp{multi}.
|
|
The @samp{pragma memo} and @samp{pragma loop_check} declarations
|
|
should not be used on such procedures.
|
|
@end cartouche
|
|
|
|
The syntax for each of these declarations is
|
|
|
|
@example
|
|
:- pragma memo(@var{Name}/@var{Arity}).
|
|
:- pragma loop_check(@var{Name}/@var{Arity}).
|
|
:- pragma minimal_model(@var{Name}/@var{Arity}).
|
|
@end example
|
|
|
|
@noindent
|
|
where @var{Name}/@var{Arity} specifies the predicate or
|
|
function to which the declaration applies. The declaration
|
|
applies to all modes of the predicate and/or function named.
|
|
At most one of these declarations may be specified
|
|
for any given predicate or function.
|
|
|
|
Note that a @samp{pragma minimal_model} declaration
|
|
changes the declarative semantics of the specified predicate or
|
|
function: instead of using the completion of the clauses
|
|
as the basis for the semantics, as is normally the case
|
|
in Mercury, the declarative semantics that is used is
|
|
the ``minimal model'' semantics. Anything which is
|
|
true or false in the completion semantics is also true
|
|
or false (respectively) in the minimal model semantics,
|
|
but there are goals for which the minimal model specifies
|
|
that the result is true or false, whereas the completion semantics
|
|
leaves the result unspecified.
|
|
For these goals, the usual Mercury semantics requires the
|
|
implementation to either loop or report an error message,
|
|
but the minimal model semantics requires a particular
|
|
answer to be returned.
|
|
In particular, the minimal model semantics says that any
|
|
call that is not true in @emph{all} models is false.
|
|
|
|
Programmers should therefore use a @samp{pragma minimal_model}
|
|
declaration only in cases where their intended interpretation for a
|
|
procedure coincides with the minimal model for that procedure.
|
|
Fortunately, however, this is usually what programmers intend.
|
|
|
|
@c XXX give an example
|
|
|
|
For more information on tabling, see K. Sagonas's PhD thesis
|
|
@c XXX this citation doesn't come out properly in DVI format
|
|
@cite{The SLG-WAM: A Search-Efficient Engine for Well-Founded Evaluation
|
|
of Normal Logic Programs.} @xref{[4]}.
|
|
The operational semantics of procedures with a @samp{pragma minimal_model}
|
|
declaration corresponds to what Sagonas calls ``SLGd resolution''.
|
|
|
|
In the general case, the execution mechanism required by
|
|
minimal model tabling is quite complicated, requiring
|
|
the ability to delay goals and then wake them up again.
|
|
The Mercury implementation uses a technique based on copying
|
|
relevant parts of the stack to the heap when delaying goals,
|
|
similar to the one described in
|
|
@c XXX this citation doesn't come out properly in DVI format
|
|
@cite{CAT: the copying approach to tabling},
|
|
by B. Demoen and K. Sagonas. @xref{[5]}.
|
|
This ensures that code which does not use tabling does not pay any
|
|
runtime overheads from the more complicated execution mechanism
|
|
required by (minimal model) tabling.
|
|
|
|
@cartouche
|
|
@strong{Please note:}
|
|
the current implementation of tabling does not support all the
|
|
possible compilation grades (see the "Compilation model options"
|
|
section of the Mercury User's Guide) allowed by the Mercury
|
|
implementation. In particular, if you enable the use of trailing,
|
|
or if you select a garbage collection method other than the default
|
|
(conservative), then any use of tabling will result in a
|
|
``Sorry, not implemented'' error at runtime.
|
|
|
|
@c XXX we should fix this bug...
|
|
@strong{Reminder}: the current implementation of
|
|
@samp{pragma minimal_model} is broken,
|
|
and the current implementation of @samp{pragma memo}
|
|
and @samp{pragma loop_check} is broken for procedures
|
|
with determinism @samp{nondet} or @samp{multi}.
|
|
@end cartouche
|
|
|
|
@node Termination analysis
|
|
@section Termination analysis
|
|
|
|
The compiler includes a termination analyser which can be used to prove
|
|
termination of predicates and functions. Details of the analysis is
|
|
available in ``Termination Analysis for Mercury'' by Chris Speirs, Zoltan
|
|
Somogyi and Harald Sondergaard. @xref{[1]}.
|
|
@c XXX this citation doesn't come out properly in DVI format
|
|
|
|
The analysis is based around an algorithm proposed by Gerhard Groger
|
|
and Lutz Plumer in their paper ``Handling of mutual recursion in
|
|
automatic termination proofs for logic programs.'' @xref{[2]}.
|
|
@c XXX this citation doesn't come out properly in DVI format
|
|
|
|
For an introduction to termination analysis for logic programs, please
|
|
refer to ``Termination Analysis for Logic Programs'' by Chris Speirs.
|
|
@c XXX this citation doesn't come out properly in DVI format
|
|
@xref{[3]}.
|
|
|
|
Information about the termination properties of a predicate or function
|
|
can be given to the compiler. Pragmas are also available to require
|
|
the compiler to prove termination of a given predicate or function, or
|
|
to give an error message if it cannot do so.
|
|
|
|
The analyser is enabled by the option @samp{--enable-termination}, which
|
|
can be abbreviated to @samp{--enable-term}. When termination analysis
|
|
is enabled, any predicates or functions with a @samp{check_termination}
|
|
pragma defined on them will have their termination checked, and if
|
|
termination cannot be proved, the compiler will emit an error message
|
|
detailing the reason that termination could not be proved.
|
|
|
|
The option @samp{--check-termination} option, which may be abbreviated
|
|
to @samp{--check-term} or @samp{--chk-term}, forces the compiler to
|
|
check the termination of all predicates in the module.
|
|
It is common for the compiler to be unable to prove termination of some
|
|
predicates and functions because they call other predicates which could
|
|
not be proved to terminate or because they use language features (such
|
|
as higher order calls) which cannot be usefully analysed.
|
|
In this case, the compiler only emits a warning for these
|
|
predicates and functions if the @samp{--verbose-check-termination}
|
|
option is enabled. For every predicate or function that the compiler
|
|
cannot prove the termination of, a warning message is emitted, but
|
|
compilation continues. The @samp{--check-termination} option implies
|
|
the @samp{--enable-termination} option.
|
|
|
|
The accuracy of the termination analysis is substantially degraded if
|
|
intermodule optimization is not enabled. Unless intermodule
|
|
optimization is enabled, the compiler must assume that any imported
|
|
predicate may not terminate.
|
|
|
|
Currently the compiler assumes that all procedures defined using the C
|
|
interface (@samp{pragma c_code}) terminate for all input.
|
|
If this is not the case, a @samp{pragma does_not_terminate} declaration
|
|
should be used to inform the compiler that this C code may not terminate.
|
|
|
|
The following declarations can be used to inform the compiler of the
|
|
termination properties of a predicate or function, or to force the
|
|
compiler to prove termination of a given predicate or function.
|
|
|
|
@example
|
|
:- pragma terminates(@var{Name}/@var{Arity}).
|
|
@end example
|
|
This declaration may be used to inform the compiler that this predicate
|
|
or function is guaranteed to terminate for any input. This is useful
|
|
when the compiler cannot prove termination of some predicates or
|
|
functions which are in turn preventing the compiler from proving
|
|
termination of other predicates or functions.
|
|
|
|
@example
|
|
:- pragma does_not_terminate(@var{Name}/@var{Arity}).
|
|
@end example
|
|
This declaration may be used to inform the compiler that this predicate
|
|
does not necessarily terminate. This is useful for procedures defined
|
|
using the C interface, which the compiler assumes to terminate by
|
|
default.
|
|
|
|
@example
|
|
:- pragma check_termination(@var{Name}/@var{Arity}).
|
|
@end example
|
|
This pragma forces the compiler to prove termination of this predicate.
|
|
If it cannot prove the termination of the specified predicate or
|
|
function then the compiler will quit with an error message.
|
|
|
|
@ifset aditi
|
|
@node Aditi deductive database interface
|
|
@section Aditi deductive database interface
|
|
|
|
@menu
|
|
* Aditi overview::
|
|
* Aditi pragma declarations:: Controlling Aditi compilation.
|
|
* Aditi update syntax:: Changing the contents of Aditi relations.
|
|
* Aditi glossary:: Glossary of Aditi terms.
|
|
@end menu
|
|
|
|
@node Aditi overview
|
|
@subsection Aditi overview
|
|
|
|
The University of Melbourne Mercury implementation includes support for
|
|
compiling Mercury predicates for bottom-up evaluation using the Aditi
|
|
deductive database system. The Aditi system is not yet publicly available,
|
|
so this is currently not very useful to anyone other than the Mercury and
|
|
Aditi developers.
|
|
|
|
Evaluation by a deductive database system is useful for predicates which
|
|
use large amounts of data, since the database system can use efficient join
|
|
algorithms instead of backtracking. Also, some predicates which loop when
|
|
executed top-down may terminate when executed bottom-up by the database (this
|
|
effect can also be achieved using tabling (@pxref{Tabled evaluation})).
|
|
Bottom-up evaluation computes the answers to a predicate a set at a time,
|
|
rather than a tuple at a time as in the normal top-down execution of a
|
|
Mercury program.
|
|
|
|
There are several restrictions on predicates to be evaluated using Aditi.
|
|
Argument types may not include polymorphic, higher-order or abstract types.
|
|
Type classes are not supported within database predicates. The argument
|
|
modes must not contain partially instantiated insts. Aditi predicates must
|
|
be stratified (@pxref{Aditi glossary}) and must not be mutually recursive
|
|
with predicates in other modules.
|
|
|
|
Every predicate with a @samp{pragma aditi} or
|
|
@samp{pragma base_relation} declaration must have an input
|
|
argument of type @samp{aditi__state}. This ensures that Aditi predicates
|
|
are only called from within transactions and that updates and database
|
|
calls are ordered correctly, in the same way that @samp{io__state} arguments
|
|
are used to ensure ordering of I/O operations. Within the clauses for
|
|
predicates with a @samp{pragma aditi} declaration variables with
|
|
type @samp{aditi__state} may only be passed to other database predicates --
|
|
they may not be packaged into terms or passed to top-down Mercury predicates.
|
|
This allows the compiler to remove all instances of @samp{aditi__state}
|
|
variables from database predicates, and enforces the restriction that
|
|
top-down Mercury code called from within the database cannot call bottom-up
|
|
code, which is currently impossible for Aditi to handle.
|
|
|
|
Some useful predicates are defined in @file{extras/aditi/aditi.m} in the
|
|
@samp{mercury-extras} distribution.
|
|
|
|
The Aditi interface currently has the major restriction that recursive or
|
|
imported top-down Mercury predicates or functions cannot be called from
|
|
predicates with @samp{pragma aditi} declarations.
|
|
The following predicates and functions from the standard library
|
|
can be called from Aditi:
|
|
|
|
@samp{builtin__compare/3},
|
|
|
|
@samp{int:'<'/2},
|
|
@samp{int:'>'/2},
|
|
@samp{int:'=<'/2},
|
|
@samp{int:'>='/2},
|
|
@samp{int__abs/2},
|
|
@samp{int__max/3},
|
|
@samp{int__min/3},
|
|
@samp{int__to_float/2},
|
|
@samp{int__pow/2},
|
|
@samp{int__log2/2},
|
|
@samp{int:'+'/2},
|
|
@samp{int:'+'/1},
|
|
@samp{int:'-'/2},
|
|
@samp{int:'-'/1},
|
|
@samp{int:'*'/2},
|
|
@samp{int:'//'/2},
|
|
@samp{int__rem/2},
|
|
|
|
@samp{float:'<'/2},
|
|
@samp{float:'>'/2},
|
|
@samp{float:'>='/2},
|
|
@samp{float:'=<'/2},
|
|
@samp{float__abs/1},
|
|
@samp{float__abs/2},
|
|
@samp{float__max/2},
|
|
@samp{float__max/3},
|
|
@samp{float__min/2},
|
|
@samp{float__min/3},
|
|
@samp{float__pow/2},
|
|
@samp{float__log2/2},
|
|
@samp{float__float/1},
|
|
@samp{float__truncate_to_int/1},
|
|
@samp{float__truncate_to_int/2},
|
|
@samp{float:'+'/2},
|
|
@samp{float:'+'/1},
|
|
@samp{float:'-'/2},
|
|
@samp{float:'-'/1},
|
|
@samp{float:'*'/2},
|
|
@samp{float:'/'/2},
|
|
|
|
@samp{math__ceiling/1},
|
|
@samp{math__round/1},
|
|
@samp{math__floor/1},
|
|
@samp{math__sqrt/1},
|
|
@samp{math__pow/2},
|
|
@samp{math__exp/1},
|
|
@samp{math__ln/1},
|
|
@samp{math__log10/1},
|
|
@samp{math__log2/1},
|
|
@samp{math__sin/1},
|
|
@samp{math__cos/1},
|
|
@samp{math__tan/1},
|
|
@samp{math__asin/1},
|
|
@samp{math__acos/1},
|
|
@samp{math__atan/1},
|
|
@samp{math__sinh/1},
|
|
@samp{math__cosh/1},
|
|
@samp{math__tanh/1},
|
|
|
|
@samp{string__length/2}.
|
|
|
|
@node Aditi pragma declarations
|
|
@subsection Aditi pragma declarations
|
|
|
|
The following pragma declarations control compilation of Aditi predicates.
|
|
|
|
@example
|
|
:- pragma aditi(@var{Name}/@var{Arity}).
|
|
@end example
|
|
|
|
This predicate should be evaluated using the Aditi deductive database.
|
|
|
|
@c `pragma base_relation' is intended to be used only in files automatically
|
|
@c generated by the Aditi system, so this documentation should disappear
|
|
@c eventually.
|
|
@example
|
|
:- pragma base_relation(@var{Name}/@var{Arity}).
|
|
@end example
|
|
|
|
This predicate is an Aditi base relation.
|
|
|
|
@example
|
|
:- pragma supp_magic(@var{Name}/@var{Arity}).
|
|
:- pragma context(@var{Name}/@var{Arity}).
|
|
@end example
|
|
|
|
Perform either the supplementary magic sets or context transformations.
|
|
One of these transformations must be performed on every Aditi predicate.
|
|
@samp{supp_magic} is the default.
|
|
There are restrictions on predicates to which the context transformation
|
|
can be applied; these are described in @cite{Right-, left-, and multi-linear
|
|
rule transformations that maintain context information.} @ref{[6]}.
|
|
|
|
@example
|
|
:- pragma naive(@var{Name}/@var{Arity}).
|
|
:- pragma psn(@var{Name}/@var{Arity}).
|
|
@end example
|
|
|
|
Specify naive or predicate semi-naive evaluation (@pxref{Aditi glossary})
|
|
for the predicate.
|
|
@samp{psn} is the default.
|
|
|
|
@example
|
|
:- pragma aditi_memo(@var{Name}/@var{Arity}).
|
|
:- pragma aditi_no_memo(@var{Name}/@var{Arity}).
|
|
@end example
|
|
|
|
The Aditi deductive database can store the results of procedures within
|
|
a transaction to avoid unnecessary recomputations. This is unrelated to
|
|
the type of memoing described in @ref{Tabled evaluation}.
|
|
@samp{aditi_no_memo} is the default.
|
|
@c XXX this will probably change
|
|
|
|
@example
|
|
:- pragma owner(@var{Name}/@var{Arity}, @var{UserName}).
|
|
@end example
|
|
|
|
The predicate is owned by the named user. A predicate in the database
|
|
is identified by owner, module name, predicate name and arity. The owner
|
|
field is used for security checks. If no @samp{pragma owner}
|
|
declaration is given, the owner is taken from the @samp{--aditi-user}
|
|
option, which defaults to the value of the environment variable @samp{USER},
|
|
or ``guest'' if that is not set.
|
|
|
|
@c `pragma aditi_index' is intended to be used only in files automatically
|
|
@c generated by the Aditi system, so this documentation should disappear
|
|
@c eventually.
|
|
@example
|
|
:- pragma aditi_index(@var{Name}/@var{Arity}, @var{IndexType}, @var{Attributes}).
|
|
@end example
|
|
|
|
The base relation has the given B-tree index. B-tree indexes allow efficient
|
|
retrieval of a tuple or range of tuples from a base relation.
|
|
@samp{@var{IndexType}} must be one of @samp{unique_B_tree} or
|
|
@samp{non_unique_B_tree}. @samp{@var{Attributes}} is a list of argument
|
|
numbers (argument numbers are counted from one).
|
|
|
|
@node Aditi update syntax
|
|
@subsection Aditi update syntax
|
|
|
|
The Melbourne Mercury compiler provides special syntax to specify updates
|
|
of Aditi base relations.
|
|
|
|
Note: Only error checking is implemented for Aditi updates --- no code is
|
|
generated yet.
|
|
|
|
@menu
|
|
* Aditi update notes::
|
|
* Insertion::
|
|
* Deletion::
|
|
* Bulk insertion and deletion::
|
|
* Modification::
|
|
@end menu
|
|
|
|
@node Aditi update notes
|
|
@subsubsection Aditi update notes
|
|
|
|
All Aditi update goals have determinism @samp{det}.
|
|
|
|
There must be a @w{@samp{pragma base_relation}} declaration for
|
|
any relation to be updated.
|
|
|
|
It is currently up to the application to ensure that any modifications
|
|
do not violate the determinism of a base relation. If any modification
|
|
does violate the determinism of a base relation, then the behaviour
|
|
is undefined. However, updates of relations with unique B-tree indexes
|
|
are checked to ensure that a key is not given multiple values. The transaction
|
|
will abort if this occurs.
|
|
|
|
Predicate and function names in Aditi update goals may be module qualified.
|
|
|
|
The examples make use of the following declarations:
|
|
@example
|
|
:- pred p(aditi__state::aditi_ui, int::out, int::out) is nondet.
|
|
:- pragma base_relation(p/3).
|
|
|
|
:- func f(aditi__state::aditi_ui, int::out) = (int::out) is nondet.
|
|
:- pragma base_relation(f/2).
|
|
|
|
:- pred ancestor(aditi__state::aditi_ui, int::out, int::out) is nondet.
|
|
:- pragma aditi(ancestor/3).
|
|
@end example
|
|
|
|
@node Insertion
|
|
@subsubsection Insertion
|
|
|
|
@example
|
|
aditi_insert(@var{PredName}(@var{Arg1}, @var{Arg2}, @dots{}), @var{DB0}, @var{DB}).
|
|
|
|
aditi_insert(@var{FuncName}(@var{Arg1}, @var{Arg2}, @dots{}) = @var{RetVal}, @var{DB0}, @var{DB}).
|
|
@end example
|
|
|
|
Insert the specified tuple into a relation.
|
|
|
|
@itemize @bullet
|
|
@item
|
|
@samp{@var{PredName}} must be the name of a predicate.
|
|
|
|
@item
|
|
@samp{@var{FuncName}} must be the name of a function.
|
|
|
|
@item
|
|
@samp{@var{Arg1}}, @samp{@var{Arg2}}, @dots{} and @samp{@var{RetVal}}
|
|
must be data-terms.
|
|
|
|
The tuple to be inserted must have the same type signature as the relation
|
|
being inserted into. All the arguments of the tuple (including the return value
|
|
of a function) have mode @samp{in}, except the @samp{aditi__state} argument
|
|
which has mode @samp{unused}.
|
|
|
|
@item
|
|
@samp{@var{DB0}} and @samp{@var{DB}} must be data-terms of type
|
|
@samp{aditi__state}. They have mode @w{@samp{aditi_di, aditi_uo}}.
|
|
@end itemize
|
|
|
|
Note that @w{@samp{@var{PredName}(@var{Arg1}, @var{Arg2}, @dots{})}}
|
|
in an @samp{aditi_insert} goal is not a higher-order term.
|
|
@w{@samp{Pred = p(DB0, X, Y), aditi_insert(Pred, DB0, DB)}}
|
|
is a syntax error.
|
|
|
|
Examples:
|
|
@example
|
|
insert_example_1(DB0, DB) :-
|
|
aditi_insert(p(_, 1, 2), DB0, DB).
|
|
|
|
insert_example_2(DB0, DB) :-
|
|
aditi_insert(f(_, 1) = 2, DB0, DB).
|
|
@end example
|
|
|
|
@node Deletion
|
|
@subsubsection Deletion
|
|
|
|
@example
|
|
aditi_delete((@var{PredName}(@var{Arg1}, @var{Arg2}, @dots{}) :- @var{Goal}), @var{DB0}, @var{DB}).
|
|
|
|
aditi_delete((@var{FuncName}(@var{Arg1}, @var{Arg2}, @dots{}) = @var{RetVal} :- @var{Goal}), @var{DB0}, @var{DB}).
|
|
|
|
aditi_delete(@var{PredOrFunc} @var{Name}/@var{Arity}, @var{Closure}, @var{DB0}, @var{DB}).
|
|
@end example
|
|
|
|
Delete all tuples for which @samp{@var{Goal}} or @samp{@var{Closure}}
|
|
succeeds from the named base relation.
|
|
|
|
@itemize @bullet
|
|
@item
|
|
@samp{@var{PredName}} must be the name of a predicate.
|
|
|
|
@item
|
|
@samp{@var{FuncName}} must be the name of a function.
|
|
|
|
@item
|
|
@samp{@var{PredOrFunc}} must be either @samp{pred} or @samp{func}.
|
|
If it is @samp{pred}, then @samp{@var{Name}} must be the name of
|
|
a predicate, and if it is @samp{func}, then @samp{@var{Name}}
|
|
must be the name of a function.
|
|
|
|
@item
|
|
@samp{@var{Arity}} must be the arity of the predicate or function
|
|
being updated.
|
|
|
|
@item
|
|
@samp{@var{Arg1}}, @samp{@var{Arg2}}, @dots{} and @samp{@var{RetVal}}
|
|
must be data-terms. The head of the deletion rule must have the same
|
|
type signature as the relation being deleted from. The arguments
|
|
(including the return value of a function) all have mode @samp{in},
|
|
except for the @samp{aditi__state} argument, which has mode
|
|
@samp{unused} --- it is not possible to call an Aditi relation
|
|
from the deletion goal.
|
|
|
|
@item
|
|
@samp{@var{Goal}} must be a Mercury goal.
|
|
|
|
@item
|
|
@samp{@var{Closure}} must be a data-term which has a higher-order type.
|
|
|
|
When deleting from a predicate with type declaration
|
|
@w{@samp{:- pred p(aditi__state, @var{Type1}, @dots{})}},
|
|
@samp{@var{Closure}} must have type
|
|
@w{@samp{aditi_top_down pred(aditi__state, @var{Type1}, @dots{})}},
|
|
and inst @w{@samp{pred(unused, in, @dots{}) is semidet}}.
|
|
|
|
When deleting from a function with type declaration
|
|
@w{@samp{:- func p(aditi__state, @var{Type1}, @dots{}) = @var{Type2}}},
|
|
@samp{@var{Closure}} must have type
|
|
@w{@samp{aditi_top_down func(aditi__state, @var{Type1}, @dots{}) = @var{Type2}}},
|
|
and inst @w{@samp{func(unused, in, @dots{}) = in is semidet}}.
|
|
|
|
The @samp{aditi_top_down} annotation on the lambda expression is needed to
|
|
tell the compiler to generate code for execution by the
|
|
Aditi database using the normal Mercury execution algorithm.
|
|
|
|
The @samp{aditi__state} argument of @samp{@var{Closure}} must have
|
|
mode @samp{unused} --- it is not possible to call an Aditi
|
|
relation from the deletion condition. All other arguments of
|
|
@samp{@var{Closure}} must have mode @samp{in}.
|
|
|
|
If the construction of @samp{@var{Closure}} is in the same conjunction
|
|
as the @samp{aditi_delete} call, the compiler may be able to do a better
|
|
job of optimizing the deletion using indexes.
|
|
|
|
@item
|
|
@samp{@var{DB0}} and @samp{@var{DB}} must be data-terms of type
|
|
@samp{aditi__state}. They have mode @w{@samp{aditi_di, aditi_uo}}.
|
|
@end itemize
|
|
|
|
Examples:
|
|
@example
|
|
delete_example_1(DB0, DB) :-
|
|
aditi_delete((p(_, X, Y) :- X + Y = 2), DB0, DB).
|
|
|
|
delete_example_2(DB0, DB) :-
|
|
aditi_delete(f(_, 2) = _Y, DB0, DB).
|
|
|
|
delete_example_3(DB0, DB) :-
|
|
DeleteP = (aditi_top_down
|
|
pred(_::unused, X::in, Y::in) is semidet :-
|
|
X = 2
|
|
),
|
|
aditi_delete(pred p/3, DeleteP, DB0, DB).
|
|
|
|
delete_example_4(DB0, DB) :-
|
|
DeleteQ = (aditi_top_down
|
|
func(_::unused, X::in) = (Y::in) is semidet :-
|
|
X = 2
|
|
),
|
|
aditi_delete(func f/2, DeleteQ, DB0, DB).
|
|
|
|
delete_example_5 -->
|
|
aditi_delete((p(_, X, Y) :- X = 2, Y = 2)).
|
|
|
|
@end example
|
|
|
|
The type of @samp{DeleteP} is
|
|
@w{@samp{aditi_top_down pred(aditi__state, int, int)}}.
|
|
Its inst is @w{@samp{pred(unused, in, in) is semidet}}, as for a normal
|
|
lambda expression.
|
|
|
|
Note that in @samp{delete_example_5} the extra set of parentheses around
|
|
the goal are needed, otherwise the second goal in the conjunction
|
|
in the deletion goal would be parsed as an extra argument of the
|
|
@samp{aditi_delete} call, resulting in a syntax error.
|
|
|
|
@node Bulk insertion and deletion
|
|
@subsubsection Bulk insertion and deletion
|
|
|
|
@example
|
|
aditi_bulk_insert(@var{PredOrFunc} @var{Name}/@var{Arity}, @var{Closure}, @var{DB0}, @var{DB}).
|
|
@end example
|
|
|
|
Insert all solutions of @samp{@var{Closure}} into the named relation.
|
|
|
|
@example
|
|
aditi_bulk_delete(@var{PredOrFunc} @var{Name}/@var{Arity}, @var{Closure}, @var{DB0}, @var{DB}).
|
|
@end example
|
|
|
|
Delete all solutions of @samp{@var{Closure}} from the named relation.
|
|
|
|
@itemize @bullet
|
|
@item
|
|
@samp{@var{PredOrFunc}} must be either @samp{pred} or @samp{func}.
|
|
If it is @samp{pred}, then @samp{@var{Name}} must be the name of
|
|
a predicate, and if it is @samp{func}, then @samp{@var{Name}}
|
|
must be the name of a function.
|
|
|
|
@item
|
|
@samp{@var{Arity}} must be the arity of the predicate or function
|
|
being updated.
|
|
|
|
@item
|
|
@samp{@var{Closure}} must be a data-term which has a higher-order type with
|
|
the same type signature as the base relation being updated.
|
|
|
|
The @samp{aditi__state} argument of @samp{@var{Closure}} must have
|
|
mode @samp{aditi_ui}. All other arguments must have mode @samp{out}.
|
|
The determinism of @samp{@var{Closure}} must be @samp{nondet}.
|
|
|
|
@samp{@var{Closure}} must be evaluable bottom-up by the Aditi
|
|
system --- the predicate or function passed must have a
|
|
@w{@samp{pragma aditi}} declaration. Lambda expressions can be
|
|
marked as evaluable by Aditi using an @samp{aditi_bottom_up} annotation
|
|
on the lambda expression.
|
|
|
|
@item
|
|
@samp{@var{DB0}} and @samp{@var{DB}} must be data-terms of type
|
|
@samp{aditi__state}. They have mode @w{@samp{aditi_di, aditi_uo}}.
|
|
@end itemize
|
|
|
|
Examples:
|
|
@example
|
|
bulk_insert_example_1(DB0, DB) :-
|
|
aditi_bulk_insert(pred p/3, ancestor, DB0, DB).
|
|
|
|
bulk_delete_example_1(DB0, DB) :-
|
|
aditi_bulk_delete(pred p/3, ancestor, DB0, DB).
|
|
|
|
bulk_insert_example_2(DB0, DB) :-
|
|
InsertP = (aditi_bottom_up
|
|
pred(DB1::aditi_ui, X::out, Y::out) is nondet :-
|
|
ancestor(DB1, X, Y)
|
|
),
|
|
aditi_bulk_insert(pred p/3, InsertP, DB0, DB).
|
|
|
|
bulk_delete_example_2(DB0, DB) :-
|
|
DeleteQ = (aditi_bottom_up
|
|
func(DB1::aditi_ui, X::out) = (Y::out) is nondet :-
|
|
ancestor(DB1, X, Y)
|
|
),
|
|
aditi_bulk_delete(func f/2, DeleteQ, DB0, DB).
|
|
@end example
|
|
|
|
The type of @samp{InsertP} is
|
|
@w{@samp{aditi_bottom_up pred(aditi__state, int, int)}}.
|
|
Its inst is @w{@samp{pred(aditi_ui, out, out) is nondet}},
|
|
as for a normal lambda expression.
|
|
|
|
@node Modification
|
|
@subsubsection Modification
|
|
|
|
@example
|
|
aditi_modify(
|
|
(@var{PredName}(@var{OldArg1}, @var{OldArg2}, @dots{}) ==>
|
|
@var{PredName}(@var{NewArg1}, @var{NewArg2}, @dots{}) :-
|
|
@var{Goal}
|
|
),
|
|
@var{DB0}, @var{DB}).
|
|
|
|
aditi_modify(
|
|
((@var{FuncName}(@var{OldArg1}, @var{OldArg2}, @dots{}) = @var{OldRetVal}) ==>
|
|
(@var{FuncName}(@var{NewArg1}, @var{NewArg2}, @dots{}) = @var{NewRetVal}) :-
|
|
@var{Goal}
|
|
),
|
|
@var{DB0}, @var{DB}).
|
|
|
|
aditi_modify(@var{PredOrFunc} @var{PredName}/@var{Arity}, @var{Closure}, @var{DB0}, @var{DB}).
|
|
|
|
@end example
|
|
|
|
Modify tuples for which @samp{@var{Goal}} or @samp{@var{Closure}} succeeds,
|
|
leaving any other tuples unchanged.
|
|
|
|
@itemize @bullet
|
|
@item
|
|
@samp{@var{PredName}} must be the name of a predicate.
|
|
|
|
@item
|
|
@samp{@var{FuncName}} must be the name of a function.
|
|
|
|
@item
|
|
@samp{@var{PredOrFunc}} must be either @samp{pred} or @samp{func}.
|
|
If it is @samp{pred}, then @samp{@var{Name}} must be the name of
|
|
a predicate, and if it is @samp{func}, then @samp{@var{Name}}
|
|
must be the name of a function.
|
|
|
|
@item
|
|
@samp{@var{Arity}} must be the arity of the predicate or function
|
|
being updated.
|
|
|
|
@item
|
|
@samp{@var{OldArg1}}, @samp{@var{OldArg2}}, @dots{}, @samp{@var{OldRetVal}},
|
|
@samp{@var{NewArg1}}, @samp{@var{NewArg2}}, @dots{}, and @samp{@var{NewRetVal}}
|
|
must be data-terms.
|
|
|
|
The original tuple is given by the first set of arguments, which
|
|
have mode @samp{in}. The updated tuple is given by the second set
|
|
of arguments, which have mode @samp{out}. The @samp{aditi__state}
|
|
arguments for both tuples have mode @samp{unused} --- it is not possible
|
|
to call an Aditi relation from the modification goal.
|
|
|
|
The argument types of each tuple must match the argument types
|
|
of the base relation being modified.
|
|
|
|
@item
|
|
@samp{@var{Goal}} must be a Mercury goal.
|
|
|
|
@item
|
|
@samp{@var{Closure}} must be a data-term which has a higher-order type.
|
|
|
|
When modifying a predicate with type declaration
|
|
@w{@samp{:- pred p(aditi__state, @var{Type1}, @dots{})}}, @samp{@var{Closure}}
|
|
must have type
|
|
@samp{aditi_top_down pred(aditi__state, @var{Type1}, @dots{}, aditi__state, @var{Type1}, @dots{})},
|
|
and inst @w{@samp{pred(unused, in, @dots{}, unused, out, @dots{}) is semidet}}.
|
|
|
|
When modifying a function with type declaration
|
|
@w{@samp{:- func p(aditi__state, @var{Type1}, @dots{}) = @var{Type2}}},
|
|
@samp{@var{Closure}} must have type
|
|
@samp{aditi_top_down pred(aditi__state, @var{Type1}, @dots{}, @var{Type2}, aditi__state, @var{Type1}, @dots{}, @var{Type2})},
|
|
and inst
|
|
@w{@samp{pred(unused, in, @dots{}, in, unused, out, @dots{}, out) is semidet}}.
|
|
|
|
The @samp{aditi__state} arguments of @samp{@var{Closure}} must have
|
|
mode @samp{unused} --- it is not possible to call an Aditi
|
|
relation from the modification goal.
|
|
|
|
If the construction of @samp{@var{Closure}} is in the same conjunction
|
|
as the @samp{aditi_modify} call, the compiler may be able to do a better
|
|
job of optimizing the modification using indexes.
|
|
|
|
@item
|
|
@samp{@var{DB0}} and @samp{@var{DB}} must be data-terms of type
|
|
@samp{aditi__state}. They have mode @w{@samp{aditi_di, aditi_uo}}.
|
|
@end itemize
|
|
|
|
Examples:
|
|
@example
|
|
modify_example_1(DB0, DB) :-
|
|
aditi_modify(
|
|
(p(_DB0, X, Y0) ==> p(_DB, X, Y) :-
|
|
X > 2, X < 5, Y = Y0 + 1
|
|
), DB0, DB).
|
|
|
|
modify_example_2(DB0, DB) :-
|
|
aditi_modify(
|
|
((f(_DB0, X) = Y0) ==> (f(_DB, X) = Y) :-
|
|
X > 2, X < 5, Y = Y0 + 1
|
|
), DB0, DB).
|
|
|
|
modify_example_3(DB0, DB) :-
|
|
ModifyP = (aditi_top_down pred(_::unused, X::in, Y0::in,
|
|
_::unused, X::out, Y::out) is semidet :-
|
|
X > 2, X < 5, Y = Y0 + 1
|
|
),
|
|
aditi_modify(pred p/3, ModifyP, DB0, DB).
|
|
|
|
modify_example_4(DB0, DB) :-
|
|
ModifyQ = (aditi_top_down pred(_::unused, X::in, Y0::in,
|
|
_::unused, X::out, Y::out) is semidet :-
|
|
X > 2, X < 5, Y = Y0 + 1
|
|
),
|
|
aditi_modify(func f/2, ModifyQ, DB0, DB).
|
|
|
|
modify_example_5 -->
|
|
aditi_modify(
|
|
(p(_DB0, X, Y0) ==> p(_DB, X, Y) :-
|
|
X > 2, X < 5, Y = Y0 + 1
|
|
)).
|
|
@end example
|
|
|
|
Note that in @samp{modify_example_5} the extra set of parentheses around
|
|
the goal are needed, otherwise the second and third goals in
|
|
the conjunction in the modification goal would be parsed as extra arguments
|
|
of the @samp{aditi_modify} call, resulting in a syntax error.
|
|
|
|
@node Aditi glossary
|
|
@subsection Aditi glossary
|
|
|
|
@table @asis
|
|
|
|
@item Aditi-RL
|
|
Aditi Relational Language is used by the Aditi system to execute queries.
|
|
The basic instructions in Aditi-RL are relational database operations such as
|
|
@samp{join}, @samp{select} and @samp{project}.
|
|
|
|
@item aggregate
|
|
Aggregates are used to compute a value such as a sum over all the solutions
|
|
for a predicate. Aggregates can be computed over Aditi predicates using
|
|
@samp{aditi__aggregate_compute_initial} defined in @file{extras/aditi/aditi.m}
|
|
in the @samp{mercury-extras} distribution.
|
|
|
|
@item base relation
|
|
A base relation is a predicate consisting of a set of facts
|
|
stored in a database. There must be no clauses for a base relation.
|
|
|
|
@item derived relation
|
|
A derived relation is an Aditi predicate for which there are clauses.
|
|
Derived relations are compiled to Aditi-RL for execution by an Aditi database.
|
|
|
|
@item predicate semi-naive evaluation
|
|
When a recursive predicate is called, the Aditi system produces the set of all
|
|
solutions using fixed point iteration. The set of solutions is initialised
|
|
to those tuples which can be derived using the non-recursive rules of the
|
|
predicate. In each iteration, new tuples are derived for the predicate using
|
|
the recursive rules for the predicate and the tuples derived in previous
|
|
iterations. Evaluation finishes when no new tuples are generated.
|
|
Predicate semi-naive evaluation (@pxref{[8]}) is a method of evaluating
|
|
recursive predicates which uses just the new tuples in each iteration
|
|
where possible. This improves efficiency by reducing the size of joins.
|
|
|
|
@item schema
|
|
A schema is a representation of the types of the attributes of a relation.
|
|
|
|
@item stratification
|
|
A program is stratified if no predicate can call itself through a negation
|
|
or an aggregate.
|
|
|
|
@item transaction
|
|
A transaction is a database operation which is executed atomically. If
|
|
part of a transaction fails, the database reverts to its original state
|
|
before the transaction. For details on how transactions are implemented
|
|
in Mercury, see @cite{Database transactions in a purely declarative logic
|
|
programming language} @ref{[7]} and @file{extras/aditi/aditi.m} in the
|
|
@samp{mercury-extras} distribution.
|
|
|
|
@end table
|
|
|
|
@end ifset
|
|
@c aditi
|
|
|
|
@node Bibliography
|
|
@chapter Bibliography
|
|
|
|
@menu
|
|
* [1]:: Spiers, Somogyi, and Sondergaard,
|
|
@cite{Termination Analysis for Mercury}.
|
|
* [2]:: Groger and Plumer, @cite{Handling of mutual recursion in
|
|
automatic termination proofs for logic programs}.
|
|
* [3]:: Spiers, @cite{Termination Analysis for logic programs}.
|
|
* [4]:: Sagonas, @cite{The SLG-WAM: A Search-Efficient Engine
|
|
for Well-Founded Evaluation of Normal Logic Programs}.
|
|
* [5]:: Demoen and Sagonas, @cite{CAT: the copying approach to tabling}.
|
|
@ifset aditi
|
|
* [6]:: Kemp, Ramamohanarao and Somogyi,
|
|
@cite{Right-, left-, and multi-linear rule transformations
|
|
that maintain context information}.
|
|
* [7]:: Kemp, Conway, Harris, Henderson, Ramamohanarao and Somogyi
|
|
@cite{Database transactions in a purely declarative
|
|
logic programming language}.
|
|
* [8]:: Ramakrishnan, Srivistava and Sudarshan,
|
|
@cite{Rule ordering in bottom-up fixpoint evaluation
|
|
of logic programs}.
|
|
@end ifset
|
|
@end menu
|
|
|
|
@node [1]
|
|
@unnumberedsec [1]
|
|
Chris Speirs, Zoltan Somogyi and Harald Sondergaard, @cite{Termination
|
|
Analysis for Mercury}. In P. Van Hentenryck, editor, @cite{Static
|
|
Analysis: Proceedings of the 4th International Symposium}, Lecture
|
|
Notes in Computer Science. Springer, 1997. A longer version is
|
|
available for download from
|
|
<http://www.cs.mu.oz.au/publications/tr_db/mu_97_09.ps.gz>.
|
|
|
|
@node [2]
|
|
@unnumberedsec [2]
|
|
Gerhard Groger and Lutz Plumer, @cite{Handling of mutual recursion in
|
|
automatic termination proofs for logic programs.} In K. Apt, editor,
|
|
@cite{The Proceedings of the Joint International Conference and Symposium on
|
|
Logic Programming}, pages 336--350. MIT Press, 1992.
|
|
|
|
@node [3]
|
|
@unnumberedsec [3]
|
|
Chris Speirs, @cite{Termination Analysis for Logic Programs},
|
|
Technical Report 97/23, Department of Computer Science, The University
|
|
of Melbourne, Melbourne, Australia, 1997. Available from
|
|
<http://www.cs.mu.oz.au/mercury/papers/mu_97_23.ps.gz>.
|
|
|
|
@node [4]
|
|
@unnumberedsec [4]
|
|
K. Sagonas, @cite{The SLG-WAM: A Search-Efficient Engine
|
|
for Well-Founded Evaluation of Normal Logic Programs},
|
|
PhD thesis, SUNY at Stony Brook, 1996. Available from @*
|
|
<http://www.cs.kuleuven.ac.be/~kostis/Thesis/thesis.ps.gz>.
|
|
|
|
@node [5]
|
|
@unnumberedsec [5]
|
|
B. Demoen and K. Sagonas, @cite{CAT: the copying approach to tabling},
|
|
submitted for publication,
|
|
Katholieke Universiteit Leuven, 1998.
|
|
|
|
@ifset aditi
|
|
@node [6]
|
|
@unnumberedsec [6]
|
|
David B. Kemp and Kotagiri Ramamohanarao and Zoltan Somogyi.
|
|
@cite{Right-, left-, and multi-linear rule transformations that maintain
|
|
context information},
|
|
The Proceedings of the Sixteenth Conference on Very Large Databases, pages
|
|
380--391, August 1990.
|
|
Available from <http://www.cs.mu.oz.au/mercury/papers/tr90-2.ps.gz>.
|
|
|
|
@node [7]
|
|
@unnumberedsec [7]
|
|
|
|
David B. Kemp, Thomas Conway, Evan Harris, Fergus Henderson,
|
|
Kotagiri Ramamohanarao and Zoltan Somogyi,
|
|
@cite{Database transactions in a purely declarative
|
|
logic programming language},
|
|
Technical Report 96/45, Department of Computer Science,
|
|
University of Melbourne, December 1996,
|
|
Available from <http://www.cs.mu.OZ.AU/publications/tr_db/mu_96_45.ps.gz>.
|
|
|
|
@node [8]
|
|
@unnumberedsec [8]
|
|
|
|
R. Ramakrishnan, D. Srivistava and S. Sudarshan,
|
|
@cite{Rule ordering in bottom-up fixpoint evaluation of logic programs}.
|
|
In @cite{Proceedings of the Sixteenth International Conference on
|
|
Very Large Data Bases}, page 359--371, August 1990.
|
|
|
|
@end ifset
|
|
@c aditi
|
|
|
|
@contents
|
|
@bye
|