mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 01:13:30 +00:00
LICENSE:
compiler/print_help.m:
doc/*.texi:
profiler/mercury_profile.m:
slice/mcov.m:
slice/mdice.m:
slice/mslice.m:
slice/mtc_diff.m:
slice/mtc_union.m:
trace/mercury_trace_Internal.c:
As above.
14283 lines
513 KiB
Plaintext
14283 lines
513 KiB
Plaintext
\input texinfo
|
|
@setfilename mercury_reference_manual.info
|
|
@settitle The Mercury Language Reference Manual
|
|
@c vim: ts=4 sw=4 expandtab ft=texinfo
|
|
|
|
@dircategory The Mercury Programming Language
|
|
@direntry
|
|
* Mercury Language: (mercury_reference_manual). The Mercury Language Reference Manual.
|
|
@end direntry
|
|
|
|
@c @smallbook
|
|
@c @cropmarks
|
|
@finalout
|
|
@setchapternewpage on
|
|
@ifnottex
|
|
This file documents the Mercury programming language, version <VERSION>.
|
|
|
|
Copyright @copyright{} 1995--2012 The University of Melbourne.@*
|
|
Copyright @copyright{} 2013--2026 The Mercury team.
|
|
|
|
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 ifnottex
|
|
|
|
@titlepage
|
|
@title The Mercury Language Reference Manual
|
|
@subtitle Version <VERSION>
|
|
@author Fergus Henderson
|
|
@author Thomas Conway
|
|
@author Zoltan Somogyi
|
|
@author David Jeffery
|
|
@author Peter Schachte
|
|
@author Simon Taylor
|
|
@author Chris Speirs
|
|
@author Tyson Dowd
|
|
@author Ralph Becket
|
|
@author Mark Brown
|
|
@author Peter Wang
|
|
@page
|
|
@vskip 0pt plus 1filll
|
|
Copyright @copyright{} 1995--2012 The University of Melbourne.@*
|
|
Copyright @copyright{} 2013--2026 The Mercury team.
|
|
|
|
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
|
|
@contents
|
|
@page
|
|
@c ---------------------------------------------------------------------------
|
|
|
|
@ifnottex
|
|
@node Top,,, (mercury)
|
|
@top The Mercury Language Reference Manual, version <VERSION>
|
|
@end ifnottex
|
|
@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:: A description of Mercury's syntax.
|
|
* Clauses:: A description of Mercury's clauses.
|
|
* 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.
|
|
* User-defined equality and comparison::
|
|
User-defined types can have user-defined equality and
|
|
comparison 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.
|
|
* Type conversions:: Converting between subtypes and supertypes.
|
|
* Exception handling:: Catching exceptions to recover from exceptional
|
|
situations.
|
|
* Formal semantics:: Declarative and operational semantics of Mercury
|
|
programs.
|
|
* Foreign language interface:: Calling code written in other programming
|
|
languages from Mercury code
|
|
* Impurity:: Users can write impure Mercury code.
|
|
* Solver types:: Support for constraint logic programming
|
|
* Trace goals:: Trace goals allow programmers to add debugging and
|
|
logging code to their programs.
|
|
* Pragmas:: Various compiler directives, used for example to
|
|
control optimization.
|
|
* Implementation-dependent extensions::
|
|
The Melbourne Mercury implementation supports
|
|
several extensions to the Mercury language.
|
|
* Bibliography:: References for further reading.
|
|
@end menu
|
|
|
|
@node Introduction
|
|
@chapter Introduction
|
|
|
|
Mercury is a general-purpose programming language,
|
|
originally 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::
|
|
* Character set::
|
|
* Whitespace::
|
|
* Comments::
|
|
* Line number directives::
|
|
* Variables::
|
|
* Names::
|
|
* Literals::
|
|
* Punctuation symbols::
|
|
* Operators::
|
|
* Terms::
|
|
* Items::
|
|
@end menu
|
|
|
|
@node Syntax overview
|
|
@section Syntax overview
|
|
|
|
A Mercury program consists of a set of source files,
|
|
each of which contains a module.
|
|
A module consists of a sequence of tokens,
|
|
each of which is a variable, name, literal, or punctuation symbol.
|
|
Tokens may be separated by any amount of
|
|
whitespace, comments, and line number directives.
|
|
These separators are mostly ignored by the parser,
|
|
but in some cases whitespace may be required to separate tokens
|
|
that would otherwise be ambiguous.
|
|
In other cases whitespace is not allowed,
|
|
e.g., before the @var{open-ct} token,
|
|
or after a @samp{.} operator
|
|
that would otherwise be interpreted as an @var{end} token.
|
|
|
|
@node Character set
|
|
@section Character set
|
|
|
|
Mercury program source files must be written
|
|
using the UTF-8 encoding of the Unicode character set.
|
|
In the rest of this chapter,
|
|
``letters'', ``digits'', ``underscore'' and other kinds of punctuation
|
|
refer to characters in the Basic Latin code block.
|
|
|
|
@node Whitespace
|
|
@section Whitespace
|
|
|
|
Whitespace is defined to be the following characters:
|
|
|
|
@multitable {CHARACTER_TABULATION} {Unicode_code_point} {Horizontal-tab}
|
|
@headitem Unicode name @tab Unicode code point @tab Notes
|
|
@item @sc{space} @tab U+0020 @tab
|
|
@item @sc{character tabulation} @tab U+0009 @tab Horizontal-tab
|
|
@item @sc{line feed} @tab U+000A @tab
|
|
@item @sc{line tabulation} @tab U+000B @tab Vertical-tab
|
|
@item @sc{form feed} @tab U+000C @tab
|
|
@item @sc{carriage return} @tab U+000D @tab
|
|
@end multitable
|
|
|
|
@node Comments
|
|
@section Comments
|
|
|
|
The @samp{%} character starts a comment that continues to the end of the line.
|
|
The @samp{/*} character sequence starts a comment that continues until
|
|
the next occurrence of @samp{*/}.
|
|
For example:
|
|
|
|
@example
|
|
% Calculate the answer.
|
|
Result = 42 % This is the answer!
|
|
|
|
/*
|
|
omit this declaration for now
|
|
:- mode append(out, in, in) is semidet.
|
|
*/
|
|
@end example
|
|
|
|
@node Line number directives
|
|
@section Line number directives
|
|
|
|
A line number directive consists of the character @samp{#},
|
|
a positive integer specifying the line number, and then a newline.
|
|
Line number directives set the current line number;
|
|
they are used in conjunction with the @samp{pragma source_file} declaration
|
|
(@pxref{Source file name})
|
|
to indicate that errors in the Mercury code following the directive
|
|
should be reported relative to the line number set by the directive.
|
|
This is useful if the code in question was generated by another tool,
|
|
in which case the line number can be set to the corresponding location
|
|
in the original source file from which the Mercury code was derived.
|
|
The Mercury compiler can thereby issue more informative error messages
|
|
using locations in the original source file.
|
|
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.
|
|
|
|
@node Variables
|
|
@section Variables
|
|
|
|
A variable is an uppercase letter or underscore
|
|
followed by zero or more letters, underscores, and digits.
|
|
For example,
|
|
@samp{Sum}, @samp{_NotNeeded}, @samp{_a}, and @samp{_123} are variables,
|
|
whereas @samp{x} and @samp{_#} are not.
|
|
A variable token consisting of single underscore is treated specially:
|
|
each instance of @samp{_} denotes a distinct variable.
|
|
|
|
Variables starting with an uppercase letter
|
|
are expected to occur more than once;
|
|
the compiler will issue a warning if this is not the case,
|
|
as it often indicates a simple error.
|
|
Variables starting with an underscore
|
|
are presumed to be ``don't-care'' variables;
|
|
the compiler will issue a warning
|
|
if a variable starting with an underscore,
|
|
excluding single underscore variables,
|
|
occurs more than once in the same scope.
|
|
|
|
@node Names
|
|
@section Names
|
|
|
|
@c In these paragraphs, we use @t instead of @samp or @code
|
|
@c to wrap examples as @t will not put quotes around its argument,
|
|
@c and we cannot expect readers to figure out which quotes
|
|
@c are subject matter and which are decoration.
|
|
A name token is either an unquoted name, a quoted name, a graphic name,
|
|
or a single semicolon character.
|
|
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 (@t{'}).
|
|
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.
|
|
A graphic name is a sequence of one or more of the following characters
|
|
@example
|
|
! & * + - : < = > ? @@ ^ ~ \ # $ . /
|
|
@end example
|
|
|
|
@noindent
|
|
where the first character is not @samp{#}.
|
|
|
|
As a special case, the character sequences @samp{<<u} and @samp{>>u},
|
|
are also graphic names.
|
|
(They are intended to denote left and right shifts
|
|
by unsigned amounts respectively.)
|
|
|
|
An unquoted name, graphic name, or semicolon
|
|
is treated as equivalent to a quoted name containing
|
|
the same sequence of characters.
|
|
|
|
@node Literals
|
|
@section Literals
|
|
|
|
The different literals in Mercury are as follows.
|
|
|
|
@table @var
|
|
@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{\e} for escape,
|
|
@samp{\f} for form-feed,
|
|
@samp{\n} for newline,
|
|
@samp{\r} for carriage-return,
|
|
@samp{\t} for tab,
|
|
@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.
|
|
|
|
The sequences @samp{\u} and @samp{\U} begin a Unicode escape.
|
|
@samp{\u} must be followed by the Unicode character code
|
|
expressed as four hexadecimal digits.
|
|
@samp{\U} must be followed by the Unicode character code
|
|
expressed as eight hexadecimal digits.
|
|
The highest allowed value is @samp{\U0010FFFF}.
|
|
|
|
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 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.
|
|
|
|
Decimal, binary, octal and hexadecimal literals
|
|
may be optionally terminated by a suffix
|
|
that indicates whether the literal represents a signed or unsigned integer
|
|
and what the size of that integer is.
|
|
These suffixes are:
|
|
@multitable {i_or_no_suffix} {Unsigned} {Implementation_defined}
|
|
@headitem Suffix @tab Signedness @tab Size
|
|
@item @code{i} or no suffix @tab Signed @tab Implementation-defined
|
|
@item @code{i8} @tab Signed @tab 8-bit
|
|
@item @code{i16} @tab Signed @tab 16-bit
|
|
@item @code{i32} @tab Signed @tab 32-bit
|
|
@item @code{i64} @tab Signed @tab 64-bit
|
|
@item @code{u} @tab Unsigned @tab Implementation-defined
|
|
@item @code{u8} @tab Unsigned @tab 8-bit
|
|
@item @code{u16} @tab Unsigned @tab 16-bit
|
|
@item @code{u32} @tab Unsigned @tab 32-bit
|
|
@item @code{u64} @tab Unsigned @tab 64-bit
|
|
@end multitable
|
|
|
|
For decimal, binary, octal and hexadecimal literals,
|
|
an arbitrary number of underscores (@samp{_})
|
|
may be inserted between the digits.
|
|
An arbitrary number of underscores may also be inserted
|
|
between the radix prefix (i.e.@: @samp{0b}, @samp{0o} and @samp{0x})
|
|
and the initial digit.
|
|
Similarly, an arbitrary number of underscores
|
|
may be inserted between the final digit and the signedness suffix.
|
|
The purpose of the underscores is to improve readability;
|
|
they do not affect the numeric value of the literal.
|
|
|
|
@c TODO: we should support hexadecimal float literals too.
|
|
@item float
|
|
A floating point literal consists of a sequence of decimal digits,
|
|
a decimal point (@samp{.}) and a sequence of digits (the fraction part),
|
|
and the letter @samp{E} (or @samp{e}),
|
|
an optional sign (@samp{+} or @samp{-}),
|
|
and then another sequence of decimal digits (the exponent).
|
|
The fraction part or the exponent (but not both) may be omitted.
|
|
|
|
An arbitrary number of underscores (@samp{_})
|
|
may be inserted between the digits in a floating point literal.
|
|
Underscores may @emph{not} occur adjacent to any non-digit characters
|
|
(i.e.@: @samp{.}, @samp{e}, @samp{E}, @samp{+} or @samp{-})
|
|
in a floating point literal,
|
|
with one exception: underscores may occur between a digit
|
|
and an @samp{e} or @samp{E} that introduces the exponent part of the number.
|
|
The purpose of the underscores is to improve readability;
|
|
they do not affect the numeric value of the literal.
|
|
|
|
@item implementation-defined-literal
|
|
An implementation-defined literal
|
|
consists of a dollar sign (@samp{$}) followed by an unquoted name.
|
|
|
|
@end table
|
|
|
|
@node Punctuation symbols
|
|
@section Punctuation symbols
|
|
|
|
The following punctuation symbols are used in Mercury's syntax.
|
|
|
|
@table @var
|
|
@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 backquote
|
|
A backquote character, @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{.}.
|
|
|
|
@end table
|
|
|
|
@node Operators
|
|
@section Operators
|
|
|
|
An operator is either a builtin operator or a user-defined operator.
|
|
A user-defined operator is a name,
|
|
module qualified name (@pxref{The module system}), or variable,
|
|
enclosed in backquotes (grave accents).
|
|
User-defined operators are left-associative infix operators
|
|
that bind more strongly than most other operators (see below).
|
|
|
|
The builtin operators, with the exception of comma, are all names,
|
|
and as such they can be used without arguments supplied.
|
|
For example, @samp{f(+)} is syntactically valid.
|
|
In some cases parentheses may be required
|
|
to limit the scope of an operator without arguments,
|
|
e.g. if it appears as an argument to another operator.
|
|
The comma operator is not a name and therefore requires single quotes
|
|
in order to be used without arguments.
|
|
An operator in single quotes is still an operator,
|
|
so any requirement for parentheses will remain unchanged.
|
|
|
|
Operators are a syntactic concept.
|
|
The @samp{+} infix operator, for example, is only a symbol;
|
|
it does not mean addition, unless you write or import code
|
|
that defines it as addition.
|
|
Modules in the Mercury standard library,
|
|
such as @code{int}, @code{uint} and @code{float},
|
|
provide such arithmetic definitions.
|
|
Other, non-arithmetic definitions can also be provided,
|
|
for example,
|
|
the @samp{-} infix operator is defined as subtraction by those modules
|
|
but is defined as a pair constructor by the @code{pair} module.
|
|
|
|
The following table lists all of Mercury's builtin operators,
|
|
as well as user-defined operators of the form @code{`@var{op}`}.
|
|
Operators with a higher priority bind more tightly
|
|
than those with a lower priority.
|
|
(This is a recent change;
|
|
previously, Mercury followed the Prolog tradition
|
|
in using higher priorities to denote operators that bind @emph{less} tightly.)
|
|
For example, given that
|
|
@code{+} has priority 1000 and @code{*} has priority 1100,
|
|
the term @code{2 * X + Y} parenthesises as @code{(2 * X) + Y}.
|
|
Note that the module qualification operator, @samp{.},
|
|
binds more tightly than any other operator.
|
|
Therefore, operator terms using builtin operators
|
|
need to be parenthesized in order to be module qualified,
|
|
for example,
|
|
integer subtraction can be written as @samp{int.(A - B)}
|
|
whereas pair construction can be written as @samp{pair.(A - B)}.
|
|
(@xref{The module system}).
|
|
|
|
The ``Specifier'' field indicates
|
|
what structure terms constructed with an operator are allowed to take.
|
|
``f'' represents the operator and ``x'' and ``y'' represent arguments.
|
|
``x'' represents an argument
|
|
whose priority must be strictly higher than that of the operator.
|
|
``y'' represents an argument
|
|
whose priority is higher than or equal to that of the operator.
|
|
For example, ``yfx'' indicates a left-associative infix operator,
|
|
while ``xfy'' indicates a right-associative infix operator.
|
|
|
|
@example
|
|
|
|
Operator Specifier Priority
|
|
|
|
. yfx 1490
|
|
! fx 1460
|
|
!. fx 1460
|
|
!: fx 1460
|
|
@@ xfx 1410
|
|
^ xfy 1401
|
|
^ fx 1400
|
|
event fx 1400
|
|
: yfx 1380
|
|
`@var{op}` yfx 1380
|
|
** xfy 1300
|
|
- fx 1300
|
|
\ fx 1300
|
|
* yfx 1100
|
|
/ yfx 1100
|
|
// yfx 1100
|
|
<< yfx 1100
|
|
<<u yfx 1100
|
|
>> yfx 1100
|
|
>>u yfx 1100
|
|
div yfx 1100
|
|
mod xfx 1100
|
|
rem xfx 1100
|
|
for xfx 1000
|
|
+ fx 1000
|
|
+ yfx 1000
|
|
++ xfy 1000
|
|
- yfx 1000
|
|
-- yfx 1000
|
|
/\ yfx 1000
|
|
\/ yfx 1000
|
|
.. xfx 950
|
|
:= xfx 850
|
|
=^ xfx 850
|
|
< xfx 800
|
|
= xfx 800
|
|
=.. xfx 800
|
|
=:= xfx 800
|
|
=< xfx 800
|
|
== xfx 800
|
|
=\= xfx 800
|
|
> xfx 800
|
|
>= xfx 800
|
|
@@< xfx 800
|
|
@@=< xfx 800
|
|
@@> xfx 800
|
|
@@>= xfx 800
|
|
\= xfx 800
|
|
\== xfx 800
|
|
~= xfx 800
|
|
is xfx 799
|
|
and xfy 780
|
|
or xfy 760
|
|
func fx 700
|
|
impure fy 700
|
|
pred fx 700
|
|
semipure fy 700
|
|
\+ fy 600
|
|
not fy 600
|
|
when xfx 600
|
|
~ fy 600
|
|
<= xfy 580
|
|
<=> xfy 580
|
|
=> xfy 580
|
|
all fxy 550
|
|
arbitrary fxy 550
|
|
atomic fxy 550
|
|
disable_warning fxy 550
|
|
disable_warnings fxy 550
|
|
promise_equivalent_solutions fxy 550
|
|
promise_equivalent_solution_sets fxy 550
|
|
promise_exclusive fy 550
|
|
promise_exclusive_exhaustive fy 550
|
|
promise_exhaustive fy 550
|
|
promise_impure fx 550
|
|
promise_pure fx 550
|
|
promise_semipure fx 550
|
|
require_complete_switch fxy 550
|
|
require_switch_arms_det fxy 550
|
|
require_switch_arms_semidet fxy 550
|
|
require_switch_arms_multi fxy 550
|
|
require_switch_arms_nondet fxy 550
|
|
require_switch_arms_cc_multi fxy 550
|
|
require_switch_arms_cc_nondet fxy 550
|
|
require_switch_arms_erroneous fxy 550
|
|
require_switch_arms_failure fxy 550
|
|
require_det fx 550
|
|
require_semidet fx 550
|
|
require_multi fx 550
|
|
require_nondet fx 550
|
|
require_cc_multi fx 550
|
|
require_cc_nondet fx 550
|
|
require_erroneous fx 550
|
|
require_failure fx 550
|
|
trace fxy 550
|
|
try fxy 550
|
|
some fxy 550
|
|
, xfy 500
|
|
& xfy 475
|
|
-> xfy 450
|
|
; xfy 400
|
|
or_else xfy 400
|
|
then xfx 350
|
|
if fx 340
|
|
else xfy 330
|
|
:: xfx 325
|
|
==> xfx 325
|
|
where xfx 325
|
|
---> xfy 321
|
|
catch xfy 320
|
|
type fx 320
|
|
solver fy 319
|
|
catch_any xfy 310
|
|
end_module fx 301
|
|
import_module fx 301
|
|
include_module fx 301
|
|
initialise fx 301
|
|
initialize fx 301
|
|
finalise fx 301
|
|
finalize fx 301
|
|
inst fx 301
|
|
instance fx 301
|
|
mode fx 301
|
|
module fx 301
|
|
pragma fx 301
|
|
promise fx 301
|
|
rule fx 301
|
|
typeclass fx 301
|
|
use_module fx 301
|
|
--> xfx 300
|
|
:- fx 300
|
|
:- xfx 300
|
|
?- fx 300
|
|
|
|
@end example
|
|
|
|
@node Terms
|
|
@section Terms
|
|
|
|
Terms are the basic construct used in Mercury syntax.
|
|
The term syntax is summarized by the following rules.
|
|
(All of this information can be found in the descriptions below the rules.)
|
|
|
|
@display
|
|
@var{term} = @var{core-term} | @var{special-term}
|
|
|
|
@var{core-term} = @var{variable} | @var{literal} | @var{functor-term}
|
|
|
|
@var{literal} = @var{string} | @var{integer} | @var{float} | @var{implementation-defined-literal}
|
|
|
|
@var{functor-term} = @var{name} | @var{name} @var{open-ct} @var{functor-args} @var{close}
|
|
|
|
@var{functor-args} = @var{functor-arg} | @var{functor-arg} @samp{,} @var{functor-args}
|
|
|
|
@c The following definition of functor arg is more restrictive than our
|
|
@c implementation, which allows operators with priority > 1000 other
|
|
@c than the '::' which is explicitly allowed here. In future we may
|
|
@c lower the priority of '::' and implement the restriction; for this
|
|
@c reason, we impose the restriction now.
|
|
@c
|
|
@c A similar situation applies to list elements and the arguments to
|
|
@c apply terms. For tuples we already implement the restriction.
|
|
@c
|
|
@var{functor-arg} = @var{arg} | @var{arg} @samp{::} @var{arg}
|
|
|
|
@var{args} = @var{arg} | @var{arg} @samp{,} @var{args}
|
|
|
|
@var{arg} = @var{term}, where the term is not an operator term with priority >= 1000
|
|
|
|
@var{special-term} = @var{operator-term} | @var{list-term} | @var{tuple-term} | @var{apply-term} | @var{paren-term}
|
|
|
|
@var{operator-term} = @var{term} @var{operator} @var{term} | @var{operator} @var{term} | @var{operator} @var{term} @var{term},
|
|
where the term is constructed according to the requirements of the operator
|
|
(@pxref{Operators})
|
|
|
|
@var{list-term} = @samp{[} @var{list-body}? @samp{]}
|
|
|
|
@var{list-body} = @var{arg} | @var{arg} @samp{,} @var{list-body} | @var{arg} @var{ht-sep} @var{term}
|
|
|
|
@var{tuple-term} = @samp{@{} @var{args}? @samp{@}}
|
|
|
|
@var{apply-term} = @var{term} @var{open-ct} @var{args} @var{close},
|
|
where the term is not a name or operator term
|
|
|
|
@var{paren-term} = @samp{(} @var{term} @samp{)}
|
|
@end display
|
|
|
|
@noindent
|
|
Terms can be described in the following way.
|
|
|
|
@table @var
|
|
@item term
|
|
A term is either a @var{core term} or a @var{special term}.
|
|
A term normalization procedure, given below,
|
|
translates terms that may contain special terms
|
|
into terms that are only constructed from core terms;
|
|
two terms are considered syntactically equivalent
|
|
if they translate to the same term.
|
|
Syntactically equivalent terms can be used interchangeably
|
|
anywhere in a module
|
|
(e.g.@: operator syntax can be used in declarations and clauses,
|
|
in particular those that define an operator).
|
|
|
|
Note that there can be further equivalences in some contexts,
|
|
e.g.@: an if-then-else can be written in either of two equivalent forms.
|
|
Such equivalences will be covered in the relevant chapters.
|
|
|
|
@item core-term
|
|
A core term is a @var{variable}, a @var{literal}, or a @var{functor-term}.
|
|
|
|
@item literal
|
|
A literal is
|
|
a @var{string},
|
|
an @var{integer},
|
|
a @var{float},
|
|
or an @var{implementation-defined-literal}.
|
|
|
|
@item functor-term
|
|
A functor term is either a name or a compound term.
|
|
A compound term is a name followed without any intervening whitespace
|
|
by an open parenthesis (i.e.@: an @var{open-ct} token),
|
|
then followed by a functor argument list and a close parenthesis.
|
|
E.g., @samp{foo(X,Y)} is a compound term,
|
|
whereas @samp{foo (X,Y)} and @samp{foo()} are not
|
|
(the first because the space after @samp{foo} is not allowed,
|
|
the second because the parentheses must be omitted if there are no arguments).
|
|
|
|
The @dfn{principal functor} of a functor term
|
|
is the name and arity of the term, separated by a slash,
|
|
where the arity is the number of arguments
|
|
(or zero if there are no arguments).
|
|
For example, the principal functor of @samp{foo(bar,baz)} is @samp{foo/2},
|
|
while the principal functor of @samp{foo} is @samp{foo/0}.
|
|
The principal functor of a special term is determined
|
|
@emph{after} term normalization.
|
|
For module qualified terms,
|
|
the principal functor is defined slightly differently
|
|
(@pxref{The module system}).
|
|
|
|
Note that the word ``functor'' has a number of definitions,
|
|
but in Mercury it just means
|
|
a symbol to which arguments can be applied,
|
|
and which has no intrinsic meaning of its own.
|
|
It is a syntactic concept that applies to all functor terms.
|
|
In specific contexts functors may also be referred to as
|
|
type constructors, data constructors (or just constructors),
|
|
predicates, functions, etc.
|
|
The principal functor may also be referred to
|
|
as the ``top-level constructor''.
|
|
|
|
@item functor-args
|
|
A functor argument list is a sequence of one or more functor arguments,
|
|
separated by commas.
|
|
|
|
@item functor-arg
|
|
A functor argument is either a single argument
|
|
or two arguments separated by a @samp{::} operator
|
|
(the latter form is for mode qualifiers; @pxref{Different clauses for different modes}).
|
|
|
|
@item args
|
|
An argument list is a sequence of one or more arguments,
|
|
separated by commas.
|
|
|
|
@item arg
|
|
An argument is any term, except operator terms where
|
|
the operator does not bind more tightly than comma
|
|
(i.e., where the priority is greater than or equal to 1000).
|
|
In such a situation parentheses can be used,
|
|
e.g.@: @samp{f((A,B))} is a compound term
|
|
with one argument that is a parenthesized operator term,
|
|
whereas @samp{f(A,B)} is a compound term
|
|
with two arguments (and no operators).
|
|
|
|
@item special-term
|
|
A special term is an operator term, a list term, a tuple term,
|
|
an apply term, or a parenthesized term.
|
|
The term normalization procedure, below, defines how these terms
|
|
are represented internally as core terms.
|
|
|
|
@item operator-term
|
|
An operator term is a term constructed using an operator,
|
|
which complies with the rules for constructing terms using that operator
|
|
(@pxref{Operators}).
|
|
Operator terms can be infix, such as @samp{A + B},
|
|
unary-prefix, such as @samp{not P},
|
|
or binary-prefix, such as @samp{some Vars Goal}.
|
|
|
|
@item list-term
|
|
A list term is an open square bracket (an @var{open-list} token),
|
|
followed by an optional list body,
|
|
followed by a close square bracket (a @var{close-list} token).
|
|
If the list body is omitted it is the empty list.
|
|
If present, the list body is an argument list,
|
|
optionally followed by a vertical bar (a @var{ht-sep} token)
|
|
followed by a term.
|
|
E.g., @samp{[]}, @samp{[X]}, and @samp{[1, 2 | Tail]}
|
|
are all list terms.
|
|
The argument list gives the elements appearing at the front of the list.
|
|
The term following the vertical bar, if present,
|
|
gives the @dfn{tail} of the list (i.e.@: the remaining elements),
|
|
otherwise the tail is the empty list.
|
|
Note that technically the tail does not have to be a list
|
|
for this to be syntactically valid,
|
|
although generally it would need to be in order to be type correct.
|
|
|
|
@item tuple-term
|
|
A tuple term is an open curly bracket (an @var{open-curly} token),
|
|
followed by an optional argument list,
|
|
followed by a close curly bracket (a @var{close-curly} token).
|
|
If the argument list is omitted it is the empty tuple,
|
|
otherwise the arguments give the components of the tuple.
|
|
E.g., @code{@{@}} and @code{@{1,'2',"three"@}} are tuple terms.
|
|
|
|
@item apply-term
|
|
An apply-term is a ``closure'' term,
|
|
which can be any term other than a name or an operator term,
|
|
followed without any intervening whitespace
|
|
by an open parenthesis (an @var{open-ct} token),
|
|
an argument list, and a close parenthesis (a @var{close} token).
|
|
E.g., @samp{A(B,C)} is an apply-term.
|
|
An apply-term represents the closure (i.e.@: a higher-order value)
|
|
applied to the arguments.
|
|
|
|
Note that although the closure term cannot be an operator term,
|
|
it @emph{can} be a parenthesized term.
|
|
Thus @samp{(Var ^ foo)(Arg1, Arg2)} is a valid apply-term,
|
|
whereas @samp{Var ^ foo(Arg1, Arg2)} is not
|
|
(it is an operator term whose second argument is a compound term).
|
|
|
|
@item paren-term
|
|
A parenthesized term is just a term enclosed in parentheses.
|
|
E.g., @code{(X-Y)} is a parenthesized term.
|
|
|
|
@end table
|
|
|
|
@noindent
|
|
The term normalization procedure works by rewriting special terms
|
|
that occur anywhere within a term
|
|
(i.e.@: at the top level or as some descendant)
|
|
according to a set of rewriting rules,
|
|
and repeating until no rules can be further applied.
|
|
The rules are as follows.
|
|
|
|
@example
|
|
@var{term1} `@var{name}` @var{term2} @expansion{} @var{name}(@var{term1}, @var{term2})
|
|
@var{term1} `@var{var}` @var{term2} @expansion{} @var{var}(@var{term1}, @var{term2})
|
|
@var{term1} @var{operator} @var{term2} @expansion{} '@var{operator}'(@var{term1}, @var{term2})
|
|
@var{operator} @var{term} @expansion{} '@var{operator}'(@var{term})
|
|
@var{operator} @var{term1} @var{term2} @expansion{} '@var{operator}'(@var{term1}, @var{term2})
|
|
|
|
[ ] @expansion{} '[]'
|
|
[ @var{arg} ] @expansion{} '[|]'(@var{arg}, '[]')
|
|
[ @var{arg} , @var{list-body} ] @expansion{} '[|]'(@var{arg}, [@var{list-body}])
|
|
[ @var{arg} | @var{term} ] @expansion{} '[|]'(@var{arg}, @var{term})
|
|
|
|
@{ @} @expansion{} '@{@}'
|
|
@{ @var{args} @} @expansion{} '@{@}'(@var{args})
|
|
|
|
@var{term}(@var{args}) @expansion{} ''(@var{term}, @var{args})
|
|
|
|
( @var{term} ) @expansion{} @var{term}
|
|
@end example
|
|
|
|
@noindent
|
|
For example, the following terms are all syntactically equivalent
|
|
(i.e.@: they are equal after term normalization).
|
|
The last is constructed from core terms;
|
|
the others all normalize to this term.
|
|
The last one shows that
|
|
the principal functor of all of them is @t{'[|]'/2}.
|
|
@example
|
|
[1, 2, 3]
|
|
[1, 2, 3 | []]
|
|
[1, 2 | [3]]
|
|
[1 | [2, 3]]
|
|
'[|]'(1, '[|]'(2, '[|]'(3, '[]')))
|
|
@end example
|
|
|
|
@noindent
|
|
Similarly, the following terms are all syntactically equivalent.
|
|
The principal functor in this case is @t{'+'/2}.
|
|
@example
|
|
A * B + C
|
|
(A * B) + C
|
|
'+'('*'(A, B), C)
|
|
@end example
|
|
|
|
@node Items
|
|
@section Items
|
|
|
|
Mercury modules are parsed as a sequence of @dfn{items}.
|
|
Each item is a term followed by an @var{end} token (a period).
|
|
If the principal functor of the term is @samp{:-/1},
|
|
it is a declaration item and the argument is the @dfn{declaration}.
|
|
Otherwise it is a clause item
|
|
and the term is the @dfn{clause}.
|
|
Note that we often use ``declaration'' and ``clause'' informally
|
|
to refer to the items themselves
|
|
(i.e., including the @var{end} token).
|
|
|
|
Declarations are used in relation to a number of features.
|
|
Details of their syntax are covered in the relevant chapters.
|
|
|
|
A clause provides part of the definition of a function or predicate,
|
|
and takes one of the following forms.
|
|
The first form is a DCG-rule and is not discussed further here
|
|
(@pxref{Definite clause grammars}).
|
|
|
|
@example
|
|
@var{DCG_Head} --> @var{DCG_Body}.
|
|
|
|
@var{Head} :- @var{Body}.
|
|
@var{Head}.
|
|
@end example
|
|
|
|
@noindent
|
|
@var{Head} is the @dfn{head} of the clause
|
|
and @var{Body}, if present, is the @dfn{body} of the clause.
|
|
If the principal functor is @samp{:-/2},
|
|
the clause is a @dfn{rule} and the body is a goal
|
|
(@pxref{Goals}).
|
|
If the principal functor is not
|
|
@samp{:-/1}, @samp{:-/2}, or @samp{-->/2},
|
|
the clause is a @dfn{fact}.
|
|
A fact is equivalent to a rule that has the same head
|
|
and a body of @samp{true}.
|
|
|
|
A clause head takes one of the following forms.
|
|
|
|
@example
|
|
@var{FunctorTerm} = @var{Result}
|
|
@var{FunctorTerm}
|
|
@end example
|
|
|
|
@noindent
|
|
@code{@var{FunctorTerm}} is a functor term
|
|
whose arguments are expressions
|
|
(@pxref{Expressions}),
|
|
optionally annotated with mode qualifiers
|
|
(@pxref{Different clauses for different modes}).
|
|
If the principal functor is @samp{=/2},
|
|
then the clause is a function rule or a function fact,
|
|
and @code{@var{Result}} is an expression,
|
|
optionally annotated with a mode qualifier.
|
|
Otherwise,
|
|
the clause is a predicate rule or a predicate fact.
|
|
The principal functor of @code{@var{FunctorTerm}}
|
|
determines which function or predicate is being defined.
|
|
|
|
@noindent
|
|
For example, the following three items are clauses.
|
|
The first is a function fact that defines a function named @samp{loop/1},
|
|
a not particularly useful function.
|
|
The second is a predicate fact and the third is a predicate rule,
|
|
that between them define a predicate named @samp{append/3}.
|
|
|
|
@example
|
|
loop(X) = 1 + loop(X).
|
|
|
|
append([], Bs, Bs).
|
|
append([X | As], Bs, [X | Cs]) :-
|
|
append(As, Bs, Cs).
|
|
@end example
|
|
|
|
@noindent
|
|
The following example contains a number of declaration and clause items,
|
|
and forms a syntactically valid module.
|
|
(The semantics of the clauses will be covered in the next chapter.
|
|
Note that the @code{length/1} function in the standard library
|
|
is implemented more efficiently.)
|
|
|
|
@example
|
|
:- module slow_length.
|
|
:- interface.
|
|
:- import_module list.
|
|
|
|
:- func length(list(T)) = int.
|
|
|
|
:- implementation.
|
|
:- import_module int. % for '+'
|
|
|
|
length([]) = 0.
|
|
length([_ | Xs]) = 1 + length(Xs).
|
|
|
|
:- end_module slow_length.
|
|
@end example
|
|
|
|
@node Clauses
|
|
@chapter Clauses
|
|
|
|
This chapter covers the semantics of Mercury clauses,
|
|
and the goals and expressions they contain.
|
|
The first section gives an informal overview of the semantics;
|
|
if you are already familiar with logic programming
|
|
you may wish to skip it and start with @ref{Goals}.
|
|
|
|
Full details of the language semantics
|
|
can be found in @ref{Formal semantics}.
|
|
|
|
@menu
|
|
* Overview of Mercury semantics::
|
|
* Goals::
|
|
* Expressions::
|
|
* State variables::
|
|
* Variable scoping::
|
|
* Implicit quantification::
|
|
* Elimination of double negation::
|
|
* Definite clause grammars::
|
|
@end menu
|
|
|
|
@node Overview of Mercury semantics
|
|
@section Overview of Mercury semantics
|
|
|
|
There is no agreed upon definition of ``declarative programming''.
|
|
One notable characteristic of Mercury as a declarative language, however,
|
|
is that it has both a @dfn{declarative} and an @dfn{operational} semantics.
|
|
The declarative semantics is conceptually the simpler of the two:
|
|
it is only concerned with the relationship between inputs and outputs,
|
|
and not the steps taken to execute a program.
|
|
The operational semantics is additionally concerned with these steps.
|
|
This is often expressed by saying that
|
|
the declarative semantics is about ``what''
|
|
whereas the operational semantics is about ``how''.
|
|
|
|
In the remainder of this section we introduce
|
|
each of these semantics.
|
|
|
|
@subheading Declarative semantics
|
|
|
|
The declarative semantics is concerned with ``truth''.
|
|
For example, it is true that 1 plus 1 is 2,
|
|
and that the length of the list [1, 2, 3] is 3.
|
|
Statements that are either true or false like this
|
|
are known as @dfn{propositions},
|
|
e.g., 1 + 1 = 2 and 1 + 2 = 5 are both propositions;
|
|
if + is interpreted as integer addition
|
|
then the first proposition is true and the second is false.
|
|
|
|
Mercury clauses state things that are true about
|
|
the function or predicate being defined.
|
|
To illustrate we will use an example from the previous chapter.
|
|
(Note that, here and below,
|
|
some declarations would need to be added to make this compile.)
|
|
|
|
@example
|
|
length([]) = 0.
|
|
length([_ | Xs]) = 1 + length(Xs).
|
|
@end example
|
|
|
|
@noindent
|
|
Both of these clauses are facts about the function @code{length/1}.
|
|
The first simply states that the length of an empty list is zero.
|
|
The second states that no matter what expressions we substitute for
|
|
the variables @samp{Xs} and @samp{_},
|
|
the length of @samp{[_ | Xs]} will be one greater than
|
|
the length of @samp{Xs}.
|
|
In other words, the length of a non-empty list
|
|
is one greater than the length of its tail.
|
|
|
|
These two statements are true according to our intuitive idea of length.
|
|
Furthermore, we can see that the clauses cover every possible list,
|
|
since every list is either empty or non-empty,
|
|
and every non-empty list has a tail that is also a list.
|
|
Perhaps surprisingly,
|
|
this is enough to conclude that
|
|
our implementation of list length is correct,
|
|
at least as far as its arguments and return values are concerned.
|
|
|
|
As another example,
|
|
the following clauses define a predicate named @code{append/3},
|
|
which is intended to be true if
|
|
the third argument is the list that results from appending
|
|
the first and second arguments.
|
|
(Equivalently, we could say that it is intended to be true if
|
|
it is possible to split the list in the third argument
|
|
to produce the first and second arguments.)
|
|
|
|
@example
|
|
append([], Bs, Bs).
|
|
append([X | As], Bs, [X | Cs]) :-
|
|
append(As, Bs, Cs).
|
|
@end example
|
|
|
|
@noindent
|
|
The first clause is a fact that states
|
|
if you append the empty list and any other list,
|
|
the result will be the same as that other list.
|
|
The second clause is a rule;
|
|
these are taken as logical implications
|
|
in which the body implies the head
|
|
(i.e.@: @samp{:-} is interpreted as reverse implication).
|
|
So this is stating that, for any substitution,
|
|
if @samp{Cs} is the result of appending @samp{As} and @samp{Bs},
|
|
then @samp{[X | Cs]} is the result of appending @samp{[X | As]} and @samp{Bs}.
|
|
|
|
Again, both clauses are true according to
|
|
the @dfn{intended interpretation},
|
|
which is defined as all of the propositions about
|
|
the functions and predicates in the program
|
|
that the programmer intends to be true.
|
|
And the definition is @dfn{complete},
|
|
meaning that for every proposition that is intended to be true
|
|
there is either a fact that covers it,
|
|
or a rule whose head covers it and (under the same substitution)
|
|
whose body is intended to be true.
|
|
Thus we can conclude in a similar way to above that our code is correct.
|
|
|
|
The declarative semantics of a Mercury program is defined as
|
|
all of the propositions that can be inferred to be true
|
|
from the clauses of the program
|
|
(with some additional axioms).
|
|
If the program is producing incorrect output,
|
|
this implies that there is a difference between
|
|
the declarative semantics and the intended interpretation.
|
|
From the above discussion,
|
|
there must be some clause that is false in the intended interpretation,
|
|
or some definition that is incomplete.
|
|
|
|
This is the reason for having a declarative semantics.
|
|
Despite it being relatively simple---you only need
|
|
to know about which propositions are true and which are false,
|
|
and not how the program actually executes---it is
|
|
still effective in reasoning about your program,
|
|
even so far as to be able to localize a bug observed in the output
|
|
down to individual clauses or definitions.
|
|
|
|
@subheading Operational semantics
|
|
|
|
The declarative semantics does not tell us
|
|
whether our program will terminate, for example,
|
|
or what its computational complexity is.
|
|
For that we need the operational semantics,
|
|
which tells us how the program will be executed.
|
|
|
|
Execution in Mercury starts with a @dfn{goal},
|
|
which is a proposition that may contain some variables.
|
|
The aim of execution is to find a substitution
|
|
for which the proposition is true.
|
|
If it does, we refer to this as @dfn{success},
|
|
and we refer to the substitution that was found as a @dfn{solution}.
|
|
If execution determines that there are no such substitutions,
|
|
we refer to this as @dfn{failure}.
|
|
|
|
Say, for example,
|
|
we start with a goal of @samp{N = length([1, 2])}.
|
|
Function evaluation is strict,
|
|
depth-first, and left-to-right,
|
|
so we want to call the @samp{length/1} function first.
|
|
To do this, we match the argument with
|
|
the heads of the clauses that define the function
|
|
to find the clause that is applicable.
|
|
In this case the second clause matches,
|
|
with the substitution of @code{Xs @expansion{} [2]}
|
|
(the substitution for @samp{_} is irrelevant,
|
|
since any other occurrence of @samp{_}
|
|
is considered a distinct variable).
|
|
Applying this substitution to the body
|
|
then replacing it in the goal gives us a new goal,
|
|
namely @samp{N = 1 + length([2])}.
|
|
|
|
Repeating this process a second time
|
|
gives us the goal @samp{N = 1 + 1 + length([])}.
|
|
When we call the function the third time
|
|
it will match the @emph{first} clause,
|
|
and the new goal will be @samp{N = 1 + 1 + 0}.
|
|
At this point we can evaluate the @samp{+/2} calls
|
|
and get a result of @samp{N = 2}.
|
|
It is trivial to find a substitution that makes this proposition true:
|
|
just map @code{N} to the literal @code{2}.
|
|
|
|
Now consider the goal @samp{append(As, Bs, [1])}.
|
|
In this case the first two arguments are @dfn{free},
|
|
meaning that they are variables that
|
|
are not mapped to anything in the current substitution,
|
|
and the third argument is @dfn{ground},
|
|
meaning that it does not contain any variables
|
|
after applying the current substitution.
|
|
In this case when we try to match (or @dfn{unify})
|
|
the goal with a clause,
|
|
both clauses match.
|
|
We arbitrarily pick the first one,
|
|
but we also push a @dfn{choice point} onto a stack,
|
|
which will allow us to return to this point later on
|
|
and try the other clause if we need to.
|
|
Matching with the first clause gives us
|
|
the substitution @code{As @expansion{} [], Bs @expansion{} [1]};
|
|
since this clause is a fact,
|
|
we succeed with this substitution as our solution.
|
|
|
|
If a later goal fails,
|
|
we pop the previous choice point off the stack
|
|
in order to search for a different solution.
|
|
This time we want to try unifying our goal with
|
|
the head of the second clause,
|
|
that is, we want to find a substitution such that
|
|
|
|
@example
|
|
append(As, Bs, [1]) = append([X1 | As1], Bs1, [X1 | Cs1])
|
|
@end example
|
|
|
|
@noindent
|
|
(the variables from the clause have been given a numerical suffix,
|
|
which is to indicate that they came from a different scope
|
|
and are not the same variables as those in the goal).
|
|
The substitution we use is
|
|
@code{As @expansion{} [1 | As1], Bs @expansion{} Bs1, X1 @expansion{} 1, Cs1 @expansion{} []};
|
|
you can check that this does indeed unify the two terms.
|
|
Note that information is effectively flowing in both directions:
|
|
variables from both the goal and the clause
|
|
(i.e.@: the caller and callee) are bound by this substitution.
|
|
This is different from pattern matching in many other languages,
|
|
in which only variables in the pattern are bound.
|
|
|
|
Applying this substitution to the body of the selected clause
|
|
gives us our new goal,
|
|
@samp{append(As1, Bs1, [])}.
|
|
Only the first clause matches,
|
|
with the substitution of @code{As1 @expansion{} [], Bs1 @expansion{} []},
|
|
and the clause is a fact,
|
|
so this is a solution to @emph{this} call to append.
|
|
To find the solution to the parent goal we compose this substitution
|
|
with the one from before,
|
|
giving @code{As @expansion{} [1], Bs @expansion{} []}.
|
|
We have now found two solutions for our goal:
|
|
one with @code{As} being the empty list and @code{Bs} being @code{[1]},
|
|
and the other with @code{As} being @code{[1]}
|
|
and @code{Bs} being the empty list.
|
|
These are all of the possible solutions;
|
|
if we wanted to search for another
|
|
we would find the choice point stack to be empty,
|
|
hence we would fail.
|
|
|
|
@node Goals
|
|
@section Goals
|
|
|
|
A goal is a term that takes one of the following forms.
|
|
|
|
@table @code
|
|
@item @var{Call}
|
|
Any goal which is a functor term
|
|
that does not match any of the other forms below
|
|
is a first-order predicate call.
|
|
The principal functor determines the predicate called,
|
|
which must be visible (@pxref{Modules}).
|
|
The arguments, if present, are expressions.
|
|
|
|
@item call(Closure)
|
|
@itemx call(Closure1, Arg1)
|
|
@itemx call(Closure2, Arg1, Arg2)
|
|
@itemx call(Closure3, Arg1, Arg2, Arg3)
|
|
@itemx @dots{}
|
|
@itemx Closure
|
|
@itemx Closure1(Arg1)
|
|
@itemx Closure2(Arg1, Arg2)
|
|
@itemx Closure3(Arg1, Arg2, Arg3)
|
|
@itemx @dots{}
|
|
A higher-order predicate call.
|
|
The closure and arguments are expressions.
|
|
@samp{call(Closure)} and @samp{Closure} just call the specified closure.
|
|
The other forms append the specified arguments
|
|
onto the argument list of the closure before calling it.
|
|
A higher-order predicate call written using
|
|
an apply term with @code{N} arguments
|
|
is equivalent to the form using @code{call/N+1}.
|
|
@xref{Higher-order}.
|
|
|
|
@item @var{Expr1} = @var{Expr2}
|
|
A unification.
|
|
@var{Expr1} and @var{Expr2} are expressions.
|
|
|
|
@item !@var{Var} ^ @var{field_list} := Expr
|
|
A state variable field update.
|
|
@xref{State variables}.
|
|
|
|
@item @var{Goal1}, @var{Goal2}
|
|
A conjunction.
|
|
@var{Goal1} and @var{Goal2} are goals.
|
|
|
|
@item @var{Goal1} & @var{Goal2}
|
|
A parallel conjunction.
|
|
@var{Goal1} and @var{Goal2} are goals.
|
|
This has the same declarative semantics as normal conjunction.
|
|
Operationally,
|
|
implementations may execute @var{Goal1} & @var{Goal2} in parallel.
|
|
The order in which parallel conjuncts begin execution is not fixed.
|
|
It is an error for @var{Goal1} or @var{Goal2}
|
|
to have a determinism other than @code{det} or @code{cc_multi}.
|
|
@xref{Determinism categories}.
|
|
|
|
@item @var{Goal1} ; @var{Goal2}
|
|
A disjunction,
|
|
where @var{Goal1} is not of the form
|
|
@samp{@var{Goal1a} -> @var{Goal1b}}
|
|
(since that would make it an if-then-else, below).
|
|
@var{Goal1} and @var{Goal2} are goals.
|
|
|
|
@item true
|
|
The empty conjunction.
|
|
Always succeeds exactly once.
|
|
|
|
@item fail
|
|
The empty disjunction.
|
|
Always fails.
|
|
|
|
@item if @var{CondGoal} then @var{ThenGoal} else @var{ElseGoal}
|
|
@itemx @var{CondGoal} -> @var{ThenGoal} ; @var{ElseGoal}
|
|
An if-then-else.
|
|
The two different syntaxes have identical semantics.
|
|
@var{CondGoal}, @var{ThenGoal}, and @var{ElseGoal} are 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 is 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 without producing any solutions,
|
|
it executes the @var{ElseGoal}.
|
|
Note that @var{CondGoal} can be nondeterministic---if the @var{CondGoal}
|
|
succeeds more than once then
|
|
the @var{ThenGoal} is executed once for each of the solutions.
|
|
|
|
If @var{CondGoal} is an explicit existential quantification,
|
|
@code{some @var{Vars} @var{QuantifiedCondGoal}}, then the variables @var{Vars}
|
|
are existentially quantified over the conjunction of the goals
|
|
@var{QuantifiedCondGoal} and @var{ThenGoal}
|
|
(see existential quantifications, below).
|
|
Explicit existential quantifications that occur as subgoals of @var{CondGoal}
|
|
do @emph{not} affect the scope of variables in the ``then'' part.
|
|
For example, in
|
|
@example
|
|
( if some [V] @var{C} then @var{T} else @var{E} )
|
|
@end example
|
|
@noindent
|
|
the variable @var{V} is quantified
|
|
over the conjunction of the goals @var{C} and @var{T}
|
|
because the top-level goal of the condition
|
|
is an explicit existential quantification,
|
|
but in
|
|
@example
|
|
( if true, some [V] @var{C} then @var{T} else @var{E} )
|
|
@end example
|
|
@noindent
|
|
the variable @var{V} is only quantified over @var{C}
|
|
because the top-level goal of the condition
|
|
is not an explicit existential quantification.
|
|
|
|
@item not @var{Goal}
|
|
@itemx \+ @var{Goal}
|
|
A negation.
|
|
@var{Goal} is a goal.
|
|
The two different syntaxes have identical semantics:
|
|
both forms are operationally equivalent to
|
|
@samp{if @var{Goal} then fail else true}.
|
|
|
|
@item @var{Expr1} \= @var{Expr2}
|
|
An inequality.
|
|
@var{Expr1} and @var{Expr2} are expressions.
|
|
This is an abbreviation for @samp{not (@var{Expr1} = @var{Expr2})}.
|
|
|
|
@item try @var{Params} @var{Goal} @dots{} catch @var{Expr} -> @var{CGoal} @dots{}
|
|
A try goal.
|
|
Exceptions thrown during the execution of @var{Goal} may be caught and handled.
|
|
A summary of the try goal syntax is:
|
|
|
|
@example
|
|
@group
|
|
try @var{Params} @var{Goal}
|
|
then @var{ThenGoal}
|
|
else @var{ElseGoal}
|
|
catch @var{Expr} -> @var{CatchGoal}
|
|
@dots{}
|
|
catch_any @var{CatchAnyVar} -> @var{CatchAnyGoal}
|
|
@end group
|
|
@end example
|
|
|
|
See @ref{Exception handling} for the full details.
|
|
|
|
@item some @var{Vars} @var{Goal}
|
|
An existential quantification.
|
|
@var{Goal} is a goal
|
|
and @var{Vars} is a list
|
|
whose elements are either variables or state variables
|
|
(a single list may contain both).
|
|
The case where there are state variables
|
|
is described in @ref{State variables};
|
|
here we discuss the case where they are all plain variables.
|
|
|
|
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 all @var{Vars} @var{Goal}
|
|
A universal quantification.
|
|
@var{Goal} is a goal
|
|
and @var{Vars} is a list of variables
|
|
(they may @emph{not} be state variables).
|
|
This goal is an abbreviation for @samp{not (some @var{Vars} not @var{Goal})}.
|
|
|
|
@item @var{Goal1} => @var{Goal2}
|
|
An implication.
|
|
@var{Goal1} and @var{Goal2} are goals.
|
|
This is an abbreviation for @samp{not (@var{Goal1}, not @var{Goal2})}.
|
|
|
|
@item @var{Goal1} <= @var{Goal2}
|
|
A reverse implication.
|
|
@var{Goal1} and @var{Goal2} are goals.
|
|
This is an abbreviation for @samp{not (@var{Goal2}, not @var{Goal1})}.
|
|
|
|
@item @var{Goal1} <=> @var{Goal2}
|
|
A logical equivalence.
|
|
@var{Goal1} and @var{Goal2} are goals.
|
|
This is an abbreviation for
|
|
@samp{(@var{Goal1} => @var{Goal2}), (@var{Goal1} <= @var{Goal2}}).
|
|
|
|
@item promise_pure @var{Goal}
|
|
A purity cast.
|
|
@var{Goal} is a goal.
|
|
This goal promises that @var{Goal} implements a pure interface,
|
|
even though it may include impure and semipure components.
|
|
|
|
@item promise_semipure @var{Goal}
|
|
A purity cast.
|
|
@var{Goal} is a goal.
|
|
This goal promises that @var{Goal} implements a semipure interface,
|
|
even though it may include impure components.
|
|
|
|
@item promise_impure @var{Goal}
|
|
A purity cast.
|
|
@var{Goal} is a goal.
|
|
This goal instructs the compiler to treat @var{Goal} as though it were impure,
|
|
regardless of its actual purity.
|
|
|
|
@item promise_equivalent_solutions @var{Vars} @var{Goal}
|
|
A determinism cast.
|
|
@var{Vars} is a list of variables
|
|
and @var{Goal} is a goal.
|
|
This goal promises that @var{Vars}
|
|
is the set of variables bound by @var{Goal},
|
|
and that while @var{Goal} may have more than one solution,
|
|
all of these solutions are equivalent
|
|
with respect to the equality theories of the variables in @var{Vars}.
|
|
It is an error for @var{Vars} to include a variable not bound by @var{Goal}
|
|
or for @var{Goal} to bind a non-local variable
|
|
that is not listed in @var{Vars}
|
|
(non-local variables with inst @code{any} are assumed to be further constrained
|
|
by @var{Goal} and must also be included in @var{Vars}).
|
|
If @var{Goal} has determinism @code{multi} or @code{cc_multi} then
|
|
@code{promise_equivalent_solutions @var{Vars} @var{Goal}}
|
|
has determinism @code{det}.
|
|
If @var{Goal} has determinism @code{nondet} or @code{cc_nondet} then
|
|
@code{promise_equivalent_solutions @var{Vars} @var{Goal}}
|
|
has determinism @code{semidet}.
|
|
|
|
@item promise_equivalent_solution_sets @var{Vars} @var{Goal}
|
|
A determinism cast,
|
|
of the kind performed by @code{promise_equivalent_solutions},
|
|
on any goals of the form
|
|
@code{arbitrary @var{ArbVars} @var{ArbGoal}} inside @var{Goal},
|
|
of which there should be at least one.
|
|
@c XXX "should" or "must"?
|
|
@var{Vars} and @var{ArbVars} must be lists of variables,
|
|
and @var{Goal} and @var{ArbGoal} must be goals.
|
|
@var{Vars} must be the set of variables bound by @var{Goal},
|
|
and @var{ArbVars} must be the set of variables bound by @var{ArbGoal},
|
|
It is an error for @var{Vars} to include a variable not bound by @var{Goal}
|
|
or for @var{Goal} to bind a non-local variable
|
|
that is not listed in @var{Vars},
|
|
and similarly for @var{ArbVars} and @var{ArbGoal}.
|
|
The intersection of @var{Vars} and the @var{ArbVars} list
|
|
of any @code{arbitrary @var{ArbVars} @var{ArbGoal}} goal
|
|
included inside @var{Goal} must be empty.
|
|
|
|
The overall @var{promise_equivalent_solution_sets} goal promises that
|
|
the set of solutions computed for @var{Vars} by @var{Goal}
|
|
is not influenced by which of the possible solutions
|
|
for @var{ArbVars} is computed by each @var{ArbGoal};
|
|
while different choices of solutions for some of the @var{ArbGoal}s
|
|
may lead to syntactically different solutions for @var{Vars} for @var{Goal},
|
|
all of these solutions are equivalent
|
|
with respect to the equality theories of the variables in @var{Vars}.
|
|
If an @var{ArbGoal} has determinism @code{multi} or @code{cc_multi} then
|
|
@code{arbitrary @var{ArbVars} @var{ArbGoal}} has determinism @code{det}.
|
|
If @var{ArbGoal} has determinism @code{nondet} or @code{cc_nondet} then
|
|
@code{arbitrary @var{ArbVars} @var{ArbGoal}} has determinism @code{semidet}.
|
|
@var{Goal} itself may have any determinism.
|
|
|
|
There is no requirement that given one of the @var{ArbGoal}s,
|
|
all its solutions must be equivalent with respect to the equality theories
|
|
of the corresponding @var{ArbVars};
|
|
in fact, in typical usage, this won't be the case.
|
|
The different solutions of the nested @var{arbitrary} goals
|
|
are not required to be equivalent in any context
|
|
except the @var{promise_equivalent_solution_sets} goal they are nested inside.
|
|
|
|
@item arbitrary @var{ArbVars} @var{ArbGoal}
|
|
Goals of this form are only allowed to occur inside
|
|
@code{promise_equivalent_solution_sets @var{Vars} @var{Goal}} goals.
|
|
See the preceding description for details.
|
|
|
|
@item require_det @var{Goal}
|
|
@itemx require_semidet @var{Goal}
|
|
@itemx require_multi @var{Goal}
|
|
@itemx require_nondet @var{Goal}
|
|
@itemx require_cc_multi @var{Goal}
|
|
@itemx require_cc_nondet @var{Goal}
|
|
@itemx require_erroneous @var{Goal}
|
|
@itemx require_failure @var{Goal}
|
|
A determinism check, typically used to enhance the robustness of code.
|
|
@var{Goal} is a goal.
|
|
If @var{Goal} is det, then
|
|
@code{require_det @var{Goal}} is equivalent to just @var{Goal}.
|
|
If @var{Goal} is not det,
|
|
then the compiler is required to generate an error message.
|
|
|
|
The @code{require_det} keyword may be replaced with
|
|
@code{require_semidet},
|
|
@code{require_multi},
|
|
@code{require_nondet},
|
|
@code{require_cc_multi},
|
|
@code{require_cc_nondet},
|
|
@code{require_erroneous} or
|
|
@code{require_failure},
|
|
each of which requires @var{Goal} to have the named determinism.
|
|
|
|
@item require_complete_switch [@var{Var}] @var{Goal}
|
|
A switch completeness check, typically used to enhance the robustness of code.
|
|
@var{Var} is a variable and @var{Goal} is a goal.
|
|
If @var{Goal} is a switch on @var{Var}
|
|
and the switch is @emph{complete},
|
|
i.e.@: the switch has an arm for every function symbol that @var{Var}
|
|
could be bound to at this point in the code,
|
|
then @code{require_complete_switch [@var{Var}] @var{Goal}}
|
|
is equivalent to @var{Goal}.
|
|
If @var{Goal} is a switch on @var{Var} but is @emph{not} complete,
|
|
or @var{Goal} is not a switch on @var{Var} at all,
|
|
then the compiler is required to generate an error message.
|
|
|
|
@item require_switch_arms_det [@var{Var}] @var{Goal}
|
|
@itemx require_switch_arms_semidet [@var{Var}] @var{Goal}
|
|
@itemx require_switch_arms_multi [@var{Var}] @var{Goal}
|
|
@itemx require_switch_arms_nondet [@var{Var}] @var{Goal}
|
|
@itemx require_switch_arms_cc_multi [@var{Var}] @var{Goal}
|
|
@itemx require_switch_arms_cc_nondet [@var{Var}] @var{Goal}
|
|
@itemx require_switch_arms_erroneous [@var{Var}] @var{Goal}
|
|
@itemx require_switch_arms_failure [@var{Var}] @var{Goal}
|
|
@code{require_switch_arms_det} is a determinism check,
|
|
typically used to enhance the robustness of code.
|
|
@var{Var} is a variable and @var{Goal} is a goal.
|
|
If @var{Goal} is a switch on @var{Var},
|
|
and all arms of the switch would be allowable in a det context,
|
|
@code{require_switch_arms_det [@var{Var}] @var{Goal}}
|
|
is equivalent to @var{Goal}.
|
|
If @var{Goal} is not a switch on @var{Var},
|
|
or if it is a switch on @var{Var}
|
|
but some of its arms would @emph{not} be allowable in a det context,
|
|
then the compiler is required to generate an error message.
|
|
|
|
The @code{require_switch_arms_det} keyword may be replaced with
|
|
@code{require_switch_arms_semidet},
|
|
@code{require_switch_arms_multi},
|
|
@code{require_switch_arms_nondet},
|
|
@code{require_switch_arms_cc_multi},
|
|
@code{require_switch_arms_cc_nondet},
|
|
@code{require_switch_arms_erroneous} or
|
|
@code{require_switch_arms_failure},
|
|
each of which requires
|
|
the arms of the switch on @var{Var} to have a determinism
|
|
that is @emph{at least as tight} as the named determinism.
|
|
The determinism match need not be exact;
|
|
the requirement is that the arms' determinisms should make
|
|
all the promises about the minimum and maximum number of solutions
|
|
as the named determinism does.
|
|
For example, it is ok to have a det switch arm
|
|
in a @code{require_switch_arms_semidet} scope,
|
|
even though it would not be ok
|
|
to have a det goal in a @code{require_semidet} scope.
|
|
|
|
@item disable_warnings [@var{Warnings}] @var{Goal}
|
|
@itemx disable_warning [@var{Warnings}] @var{Goal}
|
|
@var{Goal} is a goal
|
|
and @var{Warnings} is a comma-separated list of names.
|
|
The Mercury compiler can generate warnings
|
|
about several kinds of constructs that whose legal Mercury semantics
|
|
is likely to differ from the semantics intended by the programmer.
|
|
While such warnings are useful most of the time,
|
|
they are a distraction in cases where the programmer's intention
|
|
@emph{does} match the legal semantics.
|
|
Programmers can disable all warnings of a particular kind for an entire module
|
|
by compiling that module with the appropriate compiler option,
|
|
but in many cases this is not a good idea,
|
|
since some of the warnings it disables may @emph{not} have been mistaken.
|
|
This is what these goals are for.
|
|
The goal @code{disable_warnings [@var{Warnings}] @var{Goal}}
|
|
is equivalent to @code{@var{Goal}} in all respects, with one exception:
|
|
the Mercury compiler will not generate warnings of any of the categories
|
|
whose names appear in @code{[@var{Warnings}]}.
|
|
|
|
At the moment, the Mercury compiler supports the disabling of
|
|
the following warning categories:
|
|
@table @code
|
|
@item singleton_vars
|
|
Disable the generation of warnings
|
|
for variables that occur only once
|
|
despite their names not starting with an underscore.
|
|
@item repeated_singleton_vars
|
|
Disable the generation of warnings
|
|
for variables that occur more than once
|
|
despite their names starting with an underscore.
|
|
@item suspected_occurs_check_failure
|
|
Disable the generation of warnings about code that looks like
|
|
it unifies a variable with a term that contains that same variable.
|
|
@c @item @code{non_tail_recursive_calls}
|
|
@c Disable the generation of warnings about recursive calls
|
|
@c that are not @emph{tail}-recursive calls.
|
|
@item suspicious_recursion
|
|
Disable the generation of warnings about suspicious recursive calls.
|
|
@item no_solution_disjunct
|
|
Disable the generation of warnings about disjuncts that can have no solution.
|
|
This is usually done to shut up such a warning in a multi-mode predicate
|
|
where the disjunct in question is a switch arm in another mode.
|
|
(The difference is that a disjunct that cannot succeed has no meaningful use,
|
|
but a switch arm that cannot succeed does have one:
|
|
a switch may need that arm to make it complete.)
|
|
@item unknown_format_calls
|
|
Disable the generation of warnings about calls to
|
|
@code{string.format}, @code{io.format} or @code{stream.string_writer.format}
|
|
for which the compiler cannot tell whether there are any mismatches
|
|
between the format string and the supplied values.
|
|
@end table
|
|
|
|
The keyword starting this scope may be written
|
|
either as @code{disable_warnings} or as @code{disable_warning}.
|
|
This is intended to make the code read more naturally
|
|
regardless of whether the list contains the name of
|
|
more than one warning category.
|
|
|
|
@item trace @var{Params} @var{Goal}
|
|
A trace goal, typically used for debugging or logging.
|
|
@var{Goal} is a goal
|
|
and @var{Params} is a list of trace parameters.
|
|
@c should we move the rest of the paragraph except the last sentence
|
|
@c into the Trace goals chapter?
|
|
Some trace parameters specify compile time or run time conditions;
|
|
if any of these conditions are false, @var{Goal} will not be executed.
|
|
Since in some program invocations
|
|
@var{Goal} may be replaced by @samp{true} in this way,
|
|
@var{Goal} may not bind or change the instantiation state
|
|
of any variables it shares with the surrounding context.
|
|
The things it may do are thus restricted to side effects;
|
|
good programming style requires these side effects
|
|
to not have any effect on the execution of the program itself,
|
|
but to be confined to the provision of extra information
|
|
for the user of the program.
|
|
See @ref{Trace goals} for the details.
|
|
|
|
@item event @var{Goal}
|
|
An event goal.
|
|
@var{Goal} is a predicate call.
|
|
Event goals are an extension used by the Melbourne Mercury implementation
|
|
to support user-defined events in the Mercury debugger, @samp{mdb}.
|
|
See the ``Debugging'' chapter of the Mercury User's Guide for further details.
|
|
|
|
@end table
|
|
|
|
@node Expressions
|
|
@section Expressions
|
|
|
|
Syntactically, an expression is just a term.
|
|
Semantically, an expression is
|
|
a variable,
|
|
a literal,
|
|
a functor expression,
|
|
or a special expression.
|
|
A special expression is
|
|
a conditional expression,
|
|
a unification expression,
|
|
a state variable,
|
|
an explicit type qualification,
|
|
a type conversion expression,
|
|
a lambda expression,
|
|
an apply expression,
|
|
or a field access expression.
|
|
|
|
A literal is a string, an integer, a float,
|
|
or an implementation-defined literal
|
|
(note that character literals are just single character names; see below).
|
|
|
|
Implementation-defined literals are symbolic names
|
|
whose value represents a property of the compilation environment
|
|
or the context in which it appears.
|
|
The implementation replaces these symbolic names
|
|
with actual literals during compilation.
|
|
Implementation-defined literals can only appear within clauses.
|
|
The following must be supported by all Mercury implementations:
|
|
|
|
@table @samp
|
|
@item $file
|
|
A string that gives the name of the file
|
|
that contains the module being compiled.
|
|
If the name of the file cannot be determined,
|
|
then it is replaced by an arbitrary string.
|
|
|
|
@item $line
|
|
The line number (integer) of the goal in which the literal appears,
|
|
or -1 if it cannot be determined.
|
|
|
|
@item $module
|
|
A string representation of the fully qualified module name.
|
|
|
|
@item $pred
|
|
A string containing the fully qualified predicate or function name and arity.
|
|
|
|
@end table
|
|
|
|
@noindent
|
|
The Melbourne Mercury implementation
|
|
additionally supports the following extension:
|
|
|
|
@table @samp
|
|
@item $grade
|
|
The grade (string) in which the module is compiled.
|
|
|
|
@end table
|
|
|
|
A functor expression is a name or a compound expression.
|
|
A compound expression is a compound term
|
|
that does not match the form of a special expression,
|
|
and whose arguments are expressions.
|
|
If a functor expression is not a character literal,
|
|
its principal functor must be the name of
|
|
a visible function, predicate, or data constructor
|
|
(except for field specifiers,
|
|
for which the corresponding field access function must be visible;
|
|
see below).
|
|
|
|
Character literals in Mercury are single character names,
|
|
possibly quoted.
|
|
Since they sometimes require quotes
|
|
and sometimes require parentheses,
|
|
for code consistency we recommend
|
|
writing all character literals with quotes and
|
|
(except where used as arguments)
|
|
parentheses.
|
|
For example, @code{Char = ('+') ; Char = ('''')}.
|
|
|
|
Special expressions
|
|
(not including field access expressions,
|
|
which are covered below)
|
|
take one of the following forms.
|
|
|
|
@table @code
|
|
@item if @var{Goal} then @var{ThenExpr} else @var{ElseExpr}
|
|
@itemx @var{Goal} -> @var{ThenExpr} ; @var{ElseExpr}
|
|
A conditional expression.
|
|
@var{Goal} is a goal;
|
|
@var{ThenExpr} and @var{ElseExpr} are both expressions.
|
|
The two forms are equivalent.
|
|
The meaning of a conditional expression is that
|
|
if @var{Goal} is true it is equivalent to @var{ThenExpr},
|
|
otherwise it is equivalent to @var{ElseExpr}.
|
|
|
|
If @var{Goal} takes the form @code{some [X, Y, Z] @dots{}}
|
|
then the scope of @var{X}, @var{Y}, and @var{Z} includes @var{ThenExpr}.
|
|
See the related discussion regarding if-then-else goals.
|
|
|
|
@item @var{X} @@ @var{Y}
|
|
A unification expression.
|
|
@var{X} and @var{Y} are both expressions.
|
|
The meaning of a unification expression is that the arguments are unified,
|
|
and the expression is equivalent to the unified value.
|
|
|
|
The strict sequential operational semantics (@pxref{Formal semantics})
|
|
of an expression @w{@code{@var{X} @@ @var{Y}}}
|
|
is that the expression is replaced by a fresh variable @code{Z},
|
|
and immediately after @code{Z} is evaluated,
|
|
the conjunction @w{@code{Z = @var{X}, Z = @var{Y}}} is evaluated.
|
|
|
|
For example
|
|
|
|
@example
|
|
p(X @@ f(_, _), X).
|
|
@end example
|
|
|
|
@noindent
|
|
is equivalent to
|
|
|
|
@example
|
|
p(Z, X) :-
|
|
Z = X,
|
|
Z = f(_, _).
|
|
@end example
|
|
|
|
Unification expressions are particularly useful when writing switches
|
|
(@pxref{Determinism checking and inference}),
|
|
as the arguments of a unification expression
|
|
are examined when checking for switches.
|
|
The arguments of an equivalent user-defined function would not be.
|
|
|
|
@item !.@var{S}
|
|
@itemx !:@var{S}
|
|
A state variable.
|
|
@var{S} is a variable.
|
|
@xref{State variables}.
|
|
|
|
@item @var{Expr} : @var{Type}
|
|
An explicit type qualification.
|
|
@var{Expr} is an expression,
|
|
and @var{Type} is a type (@pxref{Types}).
|
|
An explicit type qualification constrains
|
|
the specified expression to have the specified type;
|
|
these expressions are occasionally useful to resolve ambiguities
|
|
that can arise from polymorphic types or overloading.
|
|
Apart from that,
|
|
the explicit type qualification is equivalent to @var{Expr}.
|
|
|
|
Currently we also support
|
|
@code{@var{Expr} `with_type` @var{Type}}
|
|
as an alternative syntax for explicit type qualification.
|
|
|
|
@item coerce(Expr)
|
|
A type conversion expression.
|
|
@var{Expr} is an expression.
|
|
@xref{Type conversions}.
|
|
|
|
@item pred(Arg1::Mode1, Arg2::Mode2, @dots{}) is Det :- Goal
|
|
@itemx pred(Arg1::Mode1, Arg2::Mode2, @dots{}, DCGMode0, DCGMode1) is Det --> DCGGoal
|
|
@itemx func(Arg1::Mode1, Arg2::Mode2, @dots{}) = (Result::Mode) is Det :- Goal
|
|
@itemx func(Arg1, Arg2, @dots{}) = (Result) is Det :- Goal
|
|
@itemx func(Arg1, Arg2, @dots{}) = Result :- Goal
|
|
A lambda expression.
|
|
@var{Arg1}, @var{Arg2}, @dots{} are zero or more expressions,
|
|
@var{Result} is an expression,
|
|
@var{Goal} is a goal,
|
|
@var{DCGGoal} is a DCG-goal,
|
|
@var{Mode1}, @var{Mode2}, @dots{}, @var{DCGMode0}, and @var{DCGMode1}
|
|
are modes (@pxref{Modes}),
|
|
and @var{Det} is a determinism category (@pxref{Determinism}).
|
|
The @w{@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 @var{Arg1}, @var{Arg2}, @dots{}
|
|
are locally quantified, i.e.@:
|
|
they are distinct from other variables with the same name
|
|
that occur outside of the lambda expression.
|
|
For variables which occur in @var{Result} or @var{Goal},
|
|
but not in the arguments,
|
|
the usual Mercury rules for implicit quantification apply
|
|
(@pxref{Implicit quantification}).
|
|
|
|
The form of lambda expression using @samp{-->} as its top level functor
|
|
is a syntactic abbreviation.
|
|
It is equivalent to
|
|
|
|
@example
|
|
pred(Var1::Mode1, Var2::Mode2, @dots{},
|
|
DCGVar0::DCGMode0, DCGVar1::DCGMode1) is Det :- Goal
|
|
@end example
|
|
|
|
@noindent
|
|
where @code{DCGVar0} and @code{DCGVar1} are fresh variables,
|
|
and @code{Goal} is @code{transform(DCGVar0, DCGVar1, DCGGoal)}
|
|
where @code{transform} is the function
|
|
specified in @ref{Definite clause grammars}.
|
|
|
|
@item apply(@var{Func}, @var{Arg1}, @var{Arg2}, @dots{}, @var{ArgN})
|
|
@itemx @var{Func}(@var{Arg1}, @var{Arg2}, @dots{}, @var{ArgN})
|
|
An apply expression (i.e.@: a higher-order function call).
|
|
@var{N} >= 0,
|
|
@var{Func} is an expression of type @samp{func(T1, T2, @dots{}, Tn) = T},
|
|
and @var{Arg1}, @var{Arg2}, @dots{}, @var{ArgN}
|
|
are expressions of types @samp{T1}, @samp{T2}, @dots{}, @samp{Tn}.
|
|
The type of the apply expression is @var{T}.
|
|
It denotes the result of applying the specified function
|
|
to the specified arguments.
|
|
@xref{Higher-order}.
|
|
|
|
@end table
|
|
|
|
@anchor{Field access expressions}
|
|
@subheading Field access expressions
|
|
|
|
Field access expressions provide a convenient way
|
|
to select or update fields of data constructors,
|
|
independent of the definition of the constructor.
|
|
The compiler transforms field access expressions into
|
|
sequences of calls to field selection or update functions
|
|
(@pxref{Field access functions}).
|
|
|
|
A field specifier is a functor expression.
|
|
A field list is a sequence of field specifiers
|
|
separated by @code{^} (circumflex).
|
|
E.g., @samp{field}, @samp{field1 ^ field2}
|
|
and @samp{field1(A) ^ field2(B, C)}
|
|
are all field lists.
|
|
|
|
If the principal functor of a field specifier is @code{@var{field}/N},
|
|
there must be a visible selection function @w{@code{@var{field}/(N + 1)}}.
|
|
If the field specifier occurs in a field update expression,
|
|
there must also be a visible update function
|
|
named @w{@code{'@var{field} :='/(N + 2)}}.
|
|
|
|
Field access expressions have one of the following forms.
|
|
There are also DCG goals for field access (@pxref{Definite clause grammars}),
|
|
which provide similar functionality to field access expressions,
|
|
except that they act on the DCG arguments of a DCG clause.
|
|
|
|
@table @code
|
|
@item @var{Expr} ^ @var{field_list}
|
|
|
|
A field selection.
|
|
@var{Expr} is an expression
|
|
and @var{field_list} is a field list.
|
|
For each field specifier in @var{field_list},
|
|
apply the corresponding selection function in turn.
|
|
|
|
A field selection is transformed using the following rules:
|
|
@example
|
|
transform(Expr ^ @var{field}(Arg1, @dots{})) = @var{field}(Arg1, @dots{}, Expr).
|
|
transform(Expr ^ @var{field}(Arg1, @dots{}) ^ Rest) =
|
|
transform(@var{field}(Arg1, @dots{}, Expr) ^ Rest).
|
|
@end example
|
|
|
|
@item @var{Expr} ^ @var{field_list} := @var{FieldExpr}
|
|
|
|
A field update.
|
|
@var{Expr} and @var{FieldExpr} are expressions
|
|
and @var{field_list} is a field list.
|
|
Returns a copy of @var{Expr}
|
|
with the value of the field specified by @var{field_list}
|
|
replaced with @var{FieldExpr}.
|
|
|
|
A field update is transformed using the following rules:
|
|
@example
|
|
transform(Expr ^ @var{field}(Arg1, @dots{}) := FieldExpr) =
|
|
'@var{field}:='(Arg1, @dots{}, Expr, FieldExpr)).
|
|
|
|
transform(Expr0 ^ @var{field}(Arg1, @dots{}) ^ Rest := FieldExpr) = Expr :-
|
|
OldFieldValue = @var{field}(Arg1, @dots{}, Expr0),
|
|
NewFieldValue = transform(OldFieldValue ^ Rest := FieldExpr),
|
|
Expr = '@var{field} :='(Arg1, @dots{}, Expr0, NewFieldValue).
|
|
@end example
|
|
|
|
@end table
|
|
|
|
@noindent
|
|
Examples:
|
|
|
|
@example
|
|
transform(Expr ^ field) = field(Expr).
|
|
|
|
transform(Expr ^ field(Arg)) = field(Arg, Expr).
|
|
|
|
transform(Expr ^ field1(Arg1) ^ field2(Arg2, Arg3)) =
|
|
field2(Arg2, Arg3, field1(Arg1, Expr)).
|
|
|
|
transform(Expr ^ field := FieldExpr) = 'field :='(Expr, FieldExpr).
|
|
|
|
transform(Expr ^ field(Arg) := FieldExpr) = 'field :='(Arg, Expr, FieldExpr).
|
|
|
|
transform(Expr0 ^ field1(Arg1) ^ field2(Arg2) := FieldExpr) = Expr :-
|
|
OldField1 = field1(Arg1, Expr0),
|
|
NewField1 = 'field2 :='(Arg2, OldField1, FieldExpr),
|
|
Expr = 'field1 :='(Arg1, Expr0, NewField1).
|
|
@end example
|
|
|
|
@node State variables
|
|
@section State variables
|
|
|
|
Clauses may use @dfn{state variables}
|
|
as a shorthand for naming intermediate values in a sequence.
|
|
For example, the following clauses
|
|
@example
|
|
main(IO0, IO) :-
|
|
write_string("The answer is ", IO0, IO1),
|
|
write_int(42, IO1, IO2),
|
|
nl(IO3, IO).
|
|
@end example
|
|
@noindent
|
|
could be written equivalently using state variable syntax as
|
|
@example
|
|
main(!IO) :-
|
|
write_string("The answer is ", !IO),
|
|
write_int(42, !IO),
|
|
nl(!IO).
|
|
@end example
|
|
@noindent
|
|
One advantage of doing this is that
|
|
if in future more operations need to be added in the middle of the sequence,
|
|
the state variables will not need to be renumbered.
|
|
|
|
A state variable is written @samp{!.@var{X}} or @samp{!:@var{X}},
|
|
denoting the ``current'' or ``next'' value of the sequence labelled @var{X}.
|
|
A predicate argument @samp{!@var{X}} is shorthand
|
|
for two state variable arguments @samp{!.@var{X}, !:@var{X}};
|
|
that is,
|
|
@samp{p(@dots{}, !@var{X}, @dots{})}
|
|
is equivalent to
|
|
@samp{p(@dots{}, !.@var{X}, !:@var{X}, @dots{})}.
|
|
The variables @samp{!.@var{X}} and @samp{!:@var{X}}
|
|
are referred to as the current and next components of @samp{!@var{X}},
|
|
respectively.
|
|
Note that,
|
|
since predicate arguments of the form @samp{!@var{X}}
|
|
stand for two arguments,
|
|
the arity of a predicate may be greater than it appears.
|
|
E.g.@: @samp{p(!X)} is a call to the predicate @code{p/2}.
|
|
|
|
State variables obey special scope rules.
|
|
A state variable @var{X} must be explicitly introduced,
|
|
and this can happen in one of four ways:
|
|
@itemize
|
|
@item
|
|
As @samp{!@var{X}} in the head of a predicate clause.
|
|
In this case,
|
|
references to state variable @samp{!@var{X}} or to its components
|
|
may appear in the clause body.
|
|
@item
|
|
As either @samp{!.@var{X}} or @samp{!:@var{X}} or both
|
|
in the head of a predicate or function clause.
|
|
Again, in this case,
|
|
references to state variable @samp{!@var{X}} or to its components
|
|
may appear in the clause body.
|
|
@item
|
|
As either @samp{!.@var{X}} or @samp{!:@var{X}} or both
|
|
in the head of a lambda expression.
|
|
In this case,
|
|
references to state variable @samp{!@var{X}} or to its components
|
|
may appear in the lambda expression body.
|
|
(The reason that @samp{!@var{X}} may not appear
|
|
in the head of a lambda expression is that
|
|
there is no syntax for specifying the modes of the two implied parameters.)
|
|
@item
|
|
In an explicit quantification such as @samp{some [!@var{X}] @var{Goal}}.
|
|
In this case,
|
|
references to state variable @samp{!@var{X}} or to its components
|
|
may appear in @samp{@var{Goal}}.
|
|
@end itemize
|
|
|
|
Only the current component of
|
|
a state variable @var{X} in the enclosing scope
|
|
of a lambda or if-then-else expression
|
|
may be referred to
|
|
(unless the enclosing @var{X} is shadowed
|
|
by a more local state variable of the same name.)
|
|
|
|
For instance, the following clause employs a lambda expression
|
|
and is illegal because
|
|
it implicitly refers to the next component, @samp{!:@var{S}},
|
|
inside the lambda expression.
|
|
@example
|
|
p(@var{A}, @var{B}, !@var{S}) :-
|
|
P = ( pred(@var{C}::in, @var{D}::out) is det :-
|
|
q(@var{C}, @var{D}, !@var{S})
|
|
),
|
|
( if P(@var{A}, @var{E}) then
|
|
@var{B} = @var{E}
|
|
else
|
|
@var{B} = @var{A}
|
|
).
|
|
@end example
|
|
@noindent
|
|
However
|
|
@example
|
|
p(@var{A}, @var{B}, !@var{S}) :-
|
|
P = ( pred(@var{C}::in, @var{D}::out, !.@var{S}::in, !:@var{S}::out) is det :-
|
|
q(@var{C}, @var{D}, !@var{S})
|
|
),
|
|
( if P(@var{A}, @var{E}, !@var{S}) then
|
|
@var{B} = @var{E}
|
|
else
|
|
@var{B} = @var{A}
|
|
).
|
|
@end example
|
|
@noindent
|
|
is acceptable because
|
|
the state variable @var{S} accessed inside the lambda expression
|
|
is locally scoped to the lambda expression
|
|
(shadowing the state variable of the same name outside the lambda expression),
|
|
and the lambda expression may refer to
|
|
the next component of a local state variable.
|
|
|
|
There are two restrictions concerning state variables in functions,
|
|
whether they are defined by clauses or lambda expressions.
|
|
@itemize
|
|
@item
|
|
@samp{!@var{X}} is not a legal function result,
|
|
because it stands for two arguments, rather than one.
|
|
@item
|
|
Neither @samp{!@var{X}} nor @samp{!:@var{X}}
|
|
may appear as an argument in a function application,
|
|
because this would not make sense
|
|
given the usual interpretation of state variables and functions.
|
|
@c XXX it appears the implementation does actually allow !:X
|
|
(The default mode of functions is that all arguments are input,
|
|
while in typical usage, @samp{!:@var{X}} is output.)
|
|
@end itemize
|
|
|
|
Within each clause, the compiler
|
|
replaces each occurrence of !@var{X} in an argument list
|
|
with two arguments: !.@var{X}, !:@var{X},
|
|
where !.@var{X} represents the current version of the state of !@var{X},
|
|
and !:@var{X} represents its next state.
|
|
It then replaces all occurrences of !.@var{X} and !:@var{X}
|
|
with ordinary variables in way that (in the general case)
|
|
represents a sequence of updates to the state of @var{X}
|
|
from an initial state to a final state.
|
|
|
|
This replacement is done by code that is equivalent to
|
|
the @samp{transform_goal} and @samp{transform_clause} functions below.
|
|
The basic operation used by these functions is substitution:
|
|
@samp{substitute(@var{Goal},
|
|
[!.@var{X} -> @var{CurX}, !:@var{X} -> @var{NextX}])}
|
|
stands for a copy of @var{Goal} in which
|
|
every free occurrence of @samp{!.@var{X}} is replaced with @var{CurX}, and
|
|
every free occurrence of @samp{!:@var{X}} is replaced with @var{NextX}.
|
|
(A free occurrence is one not bound
|
|
by the head of a clause or lambda, or by an explicit quantification.)
|
|
|
|
The @samp{transform_goal(@var{Goal}, @var{X}, @var{CurX}, @var{NextX})}
|
|
function's inputs are
|
|
@itemize
|
|
@item the goal to transform @var{Goal},
|
|
@item the name of the state variable @var{X},
|
|
@item and the ordinary variables @var{CurX} and @var{NextX}
|
|
representing the current and next versions of that state variable.
|
|
@end itemize
|
|
It returns a transformed version of @var{Goal}.
|
|
|
|
@samp{transform_goal} has a case for each kind of Mercury goal.
|
|
These cases are as follows.
|
|
|
|
@table @code
|
|
|
|
@item Calls
|
|
Given a first order call such as
|
|
@samp{@var{predname}(@var{Arg1}, ..., @var{ArgN})}
|
|
or a higher-order call such as
|
|
@samp{@var{Expr}(@var{Arg1}, ..., @var{ArgN})},
|
|
if any of the arguments is !@var{X},
|
|
@samp{transform_goal} replaces that argument with two arguments:
|
|
!.@var{X} and !:@var{X}.
|
|
It then checks whether
|
|
@samp{!:@var{X}} appears in the updated @var{Call}.
|
|
@itemize
|
|
@item
|
|
If it does, then it replaces @var{Call} with
|
|
@example
|
|
substitute(@var{Call}, [!.@var{X} -> @var{CurX}, !:@var{X} -> @var{NextX}])
|
|
@end example
|
|
@item
|
|
If it does not, then it replaces @var{Call} with
|
|
@example
|
|
substitute(@var{Call}, [!.@var{X} -> @var{CurX}]),
|
|
@var{NextX} = @var{CurX}
|
|
@end example
|
|
@end itemize
|
|
Note that !.@var{X} can occur in @var{Call} on its own
|
|
(i.e.@: without !:@var{X}).
|
|
Likewise, !:@var{X} can occur in @var{Call} without !.@var{X},
|
|
but this does not need separate handling.
|
|
|
|
The expression @var{Expr} in a higher-order call
|
|
may not be of the form !@var{X}, !.@var{X} or !:@var{X}.
|
|
It may be parenthesised as (!.@var{X}), however.
|
|
|
|
@item Unifications
|
|
In a unification @samp{@var{ExprA} = @var{ExprB}},
|
|
each of @var{ExprA} and @var{ExprB}
|
|
are expressions that
|
|
may have one of the following four forms:
|
|
@itemize
|
|
@item
|
|
The expression may be !.@var{S} for some state variable @var{S}.
|
|
If @var{S} is @var{X},
|
|
then @samp{transform_goal} replaces the expression with @var{CurX}.
|
|
@item
|
|
The expression may be !:@var{S} for some state variable @var{S}.
|
|
If @var{S} is @var{X},
|
|
then @samp{transform_goal} replaces the expression with @var{NextX}.
|
|
@item
|
|
The expression may be a name, a constant,
|
|
or a variable that is not a state variable,
|
|
@samp{transform_goal} leaves such expressions unchanged.
|
|
@item
|
|
The expression may be a compound term, which means that
|
|
it must have the form
|
|
@samp{@var{f}(@var{ArgTerm1}, ..., @var{ArgTermN})}.
|
|
@samp{transform_goal} handles these the same way it handles
|
|
function applications.
|
|
@end itemize
|
|
Note that @var{ExprA} and @var{ExprB} may not have the form !@var{S}.
|
|
|
|
@item State variable field updates
|
|
A state variable field update goal has the form
|
|
@example
|
|
!@var{S} ^ @var{field_list} := @var{Expr}
|
|
@end example
|
|
where @var{field_list} is a valid field list @xref{Field access expressions}.
|
|
This means that
|
|
@example
|
|
!@var{S} ^ @var{field1} := @var{Expr}
|
|
!@var{S} ^ @var{field1} ^ @var{field2} := @var{Expr}
|
|
!@var{S} ^ @var{field1} ^ @var{field2} ^ @var{field3} := @var{Expr}
|
|
@end example
|
|
are all valid field update goals.
|
|
If @var{S} is @var{X},
|
|
@samp{transform_goal} replaces such goals with
|
|
@example
|
|
@var{NextX} = @var{CurX} ^ @var{field_list} := @var{Expr}
|
|
@end example
|
|
Otherwise, it leaves the goal unchanged.
|
|
|
|
@item Conjunctions
|
|
Given a nonempty conjunction,
|
|
whether a sequential conjunction such as
|
|
@var{Goal1}, @var{Goal2}
|
|
or a parallel conjunction such as @var{Goal1} & @var{Goal2},
|
|
@samp{transform_goal}
|
|
@itemize
|
|
@item creates a fresh variable @var{MidX},
|
|
@item replaces @var{Goal1} with
|
|
@example
|
|
substitute(@var{Goal1}, [!.@var{X} -> @var{CurX}, !:@var{X} -> @var{MidX}])
|
|
@end example
|
|
@item replaces @var{Goal2} with
|
|
@example
|
|
substitute(@var{Goal2}, [!.@var{X} -> @var{MidX}, !:@var{X} -> @var{NextX}])
|
|
@end example
|
|
@end itemize
|
|
This implies that first @var{Goal1}
|
|
updates the state of @var{X} from @var{CurX} to @var{MidX},
|
|
and then @var{Goal2}
|
|
updates the state of @var{X} from @var{MidX} to @var{NextX}.
|
|
|
|
Given the empty conjunction, i.e. the goal @samp{true},
|
|
@samp{transform_goal} will replace it with
|
|
@example
|
|
@var{NextX} = @var{CurX}
|
|
@end example
|
|
|
|
@item Disjunctions
|
|
Given a disjunction such as @var{Goal1} ; @var{Goal2},
|
|
@samp{transform_goal}
|
|
@itemize
|
|
@item replaces @var{Goal1} with
|
|
@example
|
|
substitute(@var{Goal1}, [!.@var{X} -> @var{CurX}, !:@var{X} -> @var{NextX}])
|
|
@end example
|
|
@item replaces @var{Goal2} with
|
|
@example
|
|
substitute(@var{Goal2}, [!.@var{X} -> @var{CurX}, !:@var{X} -> @var{NextX}])
|
|
@end example
|
|
@end itemize
|
|
This shows that both disjuncts start with the @var{CurX},
|
|
and both end with @var{NextX}.
|
|
If a disjunct has no update of !@var{X},
|
|
then the value of @var{NextX} in that disjunct will be set to @var{CurX}.
|
|
|
|
The empty disjunction, i.e. the goal @samp{fail}, cannot succeed,
|
|
so what the value of !:@var{X} would be if it @emph{did} succeed is moot.
|
|
Therefore @samp{transform_goal} returns empty disjunctions unchanged.
|
|
|
|
@item Negations
|
|
Given a negated goal of the form @samp{not @var{NegatedGoal}},
|
|
@samp{transform_goal}
|
|
@itemize
|
|
@item creates a fresh variable @var{DummyX}, and then
|
|
@item replaces @samp{not @var{NegatedGoal}} with
|
|
@example
|
|
@samp{not} substitute(@samp{NegatedGoal}, [!.@var{X} -> @var{CurX}, !:@var{X} -> @var{DummyX}]),
|
|
@var{NextX} = @var{CurX}
|
|
@end example
|
|
@end itemize
|
|
It does this because negated goals
|
|
may not generate any outputs visible from the rest of the code,
|
|
which means that any output they @emph{do} generate
|
|
must be local to the negated goal.
|
|
|
|
Negations that use @samp{\+ @var{NegatedGoal}} notation
|
|
are handled exactly the same way,
|
|
|
|
@item If-then-elses
|
|
Given an if-then-else, whether it uses
|
|
( if @var{Cond} then @var{Then} else @var{Else} ) syntax or
|
|
( @var{Cond} -> @var{Then} ; @var{Else} ) syntax,
|
|
@samp{transform_goal}
|
|
@itemize
|
|
@item creates a fresh variable @var{MidX},
|
|
@item replaces @var{Cond} with
|
|
@example
|
|
substitute(@var{Cond}, [!.@var{X} -> @var{CurX}, !:@var{X} -> @var{MidX}])
|
|
@end example
|
|
@item replaces @var{Then} with
|
|
@example
|
|
substitute(@var{Then}, [!.@var{X} -> @var{MidX}, !:@var{X} -> @var{NextX}])
|
|
@end example
|
|
@item replaces @var{Else} with
|
|
@example
|
|
substitute(@var{Else}, [!.@var{X} -> @var{CurX}, !:@var{X} -> @var{NextX}])
|
|
@end example
|
|
@end itemize
|
|
This effectively treats an if-then-else as being a disjunction,
|
|
with the first disjunct being
|
|
the conjunction of the @var{Cond} and @var{Then} goals,
|
|
and the second disjunct being the @var{Else} goal.
|
|
(The @var{Else} goal is implicitly conjoined inside the second disjunct
|
|
with the negation of the existential closure of @var{Cond},
|
|
since the else case is executed only if the condition has no solution.)
|
|
|
|
@item Bidirectional implications
|
|
@samp{transform_goal} treats a bidirectional implication goal,
|
|
which has the form @var{GoalA} <=> @var{GoalB},
|
|
as it were the conjunction of its two constituent unidirectional implications:
|
|
@var{GoalA} => @var{GoalB}, @var{GoalA} <= @var{GoalB}.
|
|
|
|
@item Unidirectional implications
|
|
@samp{transform_goal} treats a unidirectional implication,
|
|
which has one of the two forms
|
|
@samp{@var{GoalA} => @var{GoalB}} and @samp{@var{GoalB} <= @var{GoalA}},
|
|
as if they were written as
|
|
@samp{not (@var{GoalA}, not @var{GoalB})}.
|
|
|
|
@item Universal quantifications
|
|
@samp{transform_goal} treats universal quantifications,
|
|
which have the form @samp{all @var{Vars} @var{SubGoal}}
|
|
as if they were written as
|
|
@samp{not (some @var{Vars} (not @var{SubGoal}))}.
|
|
Note that in universal quantifications,
|
|
@var{Vars} must a list of ordinary variables.
|
|
@c XXX the state var transformation does not enforce this.
|
|
|
|
@item Existential quantifications
|
|
In existential quantifications,
|
|
which have the form @samp{some @var{Vars} @var{SubGoal}},
|
|
@var{Vars} must be a list, in which every element
|
|
must be either ordinary variable (such as @var{A}),
|
|
or a state variable (such as !@var{B}).
|
|
(Note that @var{Vars} may not contain
|
|
any element whose form is !.@var{B} or !:@var{B}.)
|
|
@itemize
|
|
@item
|
|
If @var{Vars} does not contain !@var{X},
|
|
then @samp{transform_goal} will replace @var{SubGoal} with
|
|
@example
|
|
substitute(@var{SubGoal}, [!.@var{X} -> @var{CurX}, !:@var{X} -> @var{NextX}])
|
|
@end example
|
|
@item
|
|
If @var{Vars} does contain !@var{X},
|
|
then @samp{transform_goal} will leave @var{SubGoal} unchanged, because
|
|
any references to !.@var{X}, !:@var{X} and !@var{X} inside @var{SubGoal}
|
|
refer to the state variable @var{X} introduced by this scope,
|
|
not the one visible outside.
|
|
Effectively, this state variable @var{X}
|
|
@emph{shadows} the one visible outside.
|
|
@end itemize
|
|
Note that state variables in @var{Vars}
|
|
are handled by @samp{transform_clause} below.
|
|
|
|
@end table
|
|
|
|
The @samp{transform_clause} function's input is a clause,
|
|
which may be a non-DCG clause or a DCG clause, which have the forms
|
|
@example
|
|
@var{predname}(@var{ArgTerm1}, ..., @var{ArgTermN}) :- @var{BodyGoal}.
|
|
@end example
|
|
and
|
|
@example
|
|
@var{predname}(@var{ArgTerm1}, ..., @var{ArgTermN}) --> @var{BodyGoal}.
|
|
@end example
|
|
respectively.
|
|
@samp{transform_clause} handles both the same way.
|
|
|
|
@itemize
|
|
@item While any of the @var{ArgTerms}
|
|
has one of the forms !.@var{X}, !:@var{X} and !@var{X},
|
|
@itemize
|
|
@item @samp{transform_clause} will create two fresh variables,
|
|
@var{InitX} and @var{FinalX},
|
|
@item it will replace
|
|
any one of the @var{ArgTerms} that is !.@var{X} with @var{InitX},
|
|
any one of the @var{ArgTerms} that is !:@var{X} with @var{FinalX}, and
|
|
any one of the @var{ArgTerms} that is !@var{X} with
|
|
the argument pair @var{InitX}, @var{FinalX}, and
|
|
@item it will replace @var{BodyGoal} with the result of
|
|
@samp{transform_goal(@var{BodyGoal}, @var{X}, @var{InitX}, @var{FinalX})}.
|
|
@end itemize
|
|
@item While @var{BodyGoal} contains a lambda expression
|
|
whose argument list contains either !.@var{X} or !:@var{X} or both:
|
|
@itemize
|
|
@item @samp{transform_clause} will create two fresh variables,
|
|
@var{InitX} and @var{FinalX},
|
|
@item it will replace
|
|
any one of the arguments that is !.@var{X} with @var{InitX}, and
|
|
any one of the arguments that is !:@var{X} with @var{FinalX}
|
|
(there may not be any argument that is !@var{X}), and
|
|
@item it will replace the lambda goal @var{BodyGoal} with the result of
|
|
@samp{transform_goal(@var{BodyGoal}, @var{X}, @var{InitX}, @var{FinalX})}.
|
|
@end itemize
|
|
@item While @var{BodyGoal} contains an existential quantification goal
|
|
@samp{some @var{Vars} @var{SubGoal}}
|
|
where @var{Vars} contains a state variable such as !@var{B},
|
|
@itemize
|
|
@item @samp{transform_clause} will create two fresh variables,
|
|
@var{InitB} and @var{FinalB},
|
|
@item it will replace @var{SubGoal} with the result of
|
|
@samp{transform_goal(@var{SubGoal}, @var{B}, @var{InitB}, @var{FinalB})},
|
|
and then
|
|
@item it will delete !@var{B} from @var{Vars}.
|
|
@end itemize
|
|
@end itemize
|
|
|
|
Actual application of this transformation would, in the general case,
|
|
result in the generation of many different versions of each state variable,
|
|
for which we need more names than just
|
|
@samp{@var{CurX}}, @samp{@var{TmpX}} and @samp{@var{NextX}}.
|
|
The Mercury compiler therefore uses
|
|
@itemize
|
|
@item
|
|
@samp{@var{STATE_VARIABLE_X_0}} as the initial value of a state variable,
|
|
@item
|
|
@samp{@var{STATE_VARIABLE_X_N}},
|
|
where @samp{@var{N}} is a nonzero positive integer,
|
|
as its intermediate values, and
|
|
@item
|
|
@samp{@var{STATE_VARIABLE_X}} as its final value.
|
|
@end itemize
|
|
|
|
This transformation can lead
|
|
to the introduction of chains of unifications for variables
|
|
that do not otherwise play a role in the definition,
|
|
such as
|
|
@samp{@var{STATE_VARIABLE_X_5} = @var{STATE_VARIABLE_X_6},
|
|
@var{STATE_VARIABLE_X_6} = @var{STATE_VARIABLE_X_7},
|
|
@var{STATE_VARIABLE_X_7} = @var{STATE_VARIABLE_X_8}}.
|
|
Where possible, the compiler automatically shortcircuits such sequences
|
|
by removing any unneeded intermediate variables.
|
|
In the above case, this would yield
|
|
@samp{@var{STATE_VARIABLE_X_5} = @var{STATE_VARIABLE_X_8}}.
|
|
|
|
The following code fragments illustrate
|
|
some appropriate uses of state variable syntax.
|
|
|
|
@table @b
|
|
@item Threading the I/O state
|
|
@example
|
|
main(!IO) :-
|
|
io.write_string("The 100th prime is ", !IO),
|
|
X = prime(100),
|
|
io.write_int(X, !IO),
|
|
io.nl(!IO).
|
|
@end example
|
|
|
|
@item Handling accumulators (1)
|
|
@example
|
|
foldl2(_, [], !A, !B).
|
|
foldl2(P, [X | Xs], !A, !B) :-
|
|
P(X, !A, !B),
|
|
foldl2(P, Xs, !A, !B).
|
|
@end example
|
|
|
|
@item Handling accumulators (2)
|
|
@example
|
|
iterate_while2(Test, Update, !A, !B) :-
|
|
( if Test(!.A, !.B) then
|
|
Update(!A, !B),
|
|
iterate_while2(Test, Update, !A, !B)
|
|
else
|
|
true
|
|
).
|
|
@end example
|
|
|
|
@item Introducing state
|
|
@example
|
|
compute_out(InA, InB, InsC, Out) :-
|
|
some [!State]
|
|
(
|
|
init_state(!:State),
|
|
update_state_a(InA, !State),
|
|
update_state_b(InB, !State),
|
|
list.foldl(update_state_c, InC, !State),
|
|
compute_output(!.State, Out)
|
|
).
|
|
@end example
|
|
@end table
|
|
|
|
@node Variable scoping
|
|
@section Variable scoping
|
|
|
|
There are three sorts of variables in Mercury:
|
|
ordinary variables, type variables, and inst variables.
|
|
|
|
Variables occurring in types,
|
|
type classes, and instances are called type variables.
|
|
Variables occurring in insts or modes are called inst variables.
|
|
Variables that occur in expressions,
|
|
and that are not inst variables or type variables,
|
|
are called ordinary variables.
|
|
|
|
Note that type variables can occur in expressions
|
|
in the right-hand (@var{Type}) operand of an explicit type qualification.
|
|
Inst variables can occur in expressions
|
|
in the right-hand (@var{Mode}) operand of an explicit mode qualification.
|
|
Apart from that, all other variables in expressions are ordinary variables.
|
|
|
|
The three different variable sorts occupy different namespaces:
|
|
there is no semantic relationship between two variables of different sorts
|
|
(e.g.@: a type variable and an ordinary variable)
|
|
even if they happen to share the same name.
|
|
However, as a matter of programming style, it is generally a bad idea
|
|
to use the same name for variables of different sorts in the same clause.
|
|
|
|
The scope of ordinary variables
|
|
is the clause or declaration in which they occur,
|
|
unless they are quantified,
|
|
either explicitly (@pxref{Goals})
|
|
or implicitly (@pxref{Implicit quantification}).
|
|
|
|
The scope of type variables in a predicate or function's type declaration
|
|
extends over any explicit type qualifications
|
|
(@pxref{Expressions})
|
|
in the clauses for that predicate or function,
|
|
and over @samp{pragma type_spec} (@pxref{Type specialization}) declarations
|
|
for that predicate or function,
|
|
so that explicit type qualifications and @samp{pragma type_spec} declarations
|
|
can refer to those type variables.
|
|
The scope of any type variables in an explicit type qualification
|
|
which do not occur in the predicate or function's type declaration
|
|
is the clause in which they occur.
|
|
|
|
The scope of inst variables is the clause or declaration in which they occur.
|
|
|
|
@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 term 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 negated context.
|
|
|
|
@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 implicit quantification,
|
|
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. @xref{Modes}.)
|
|
|
|
@node Definite clause grammars
|
|
@section Definite clause grammars
|
|
|
|
A definite clause grammar (DCG)
|
|
is a way of expressing parsing rules,
|
|
and is intended for writing parsers and sequence generators.
|
|
In the past it has also been used to thread an implicit state variable,
|
|
typically the I/O state, through code.
|
|
We now recommend that
|
|
DCGs only be used for writing parsers and sequence generators,
|
|
and that state variable syntax (@pxref{State variables}),
|
|
which performs a similar transformation but is more flexible,
|
|
be used for other purposes such as threading state variables.
|
|
|
|
A DCG-rule is a clause that takes the form
|
|
|
|
@example
|
|
DCG_Head --> DCG_Body.
|
|
@end example
|
|
|
|
@noindent
|
|
where @var{DCG_Head} is a predicate head term
|
|
and @var{DCG_Body} is a DCG-goal.
|
|
It is an abbreviation for the rule
|
|
|
|
@example
|
|
Head --> Body.
|
|
@end example
|
|
|
|
@noindent
|
|
where @var{Head} is @var{DCG_Head}
|
|
with two fresh variables,
|
|
@code{V_in} and @code{V_out},
|
|
appended to the argument list,
|
|
and @var{Body} is @code{transform(V_in, V_out, DCG_Body)},
|
|
where @code{transform} is the function defined below.
|
|
|
|
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} is a list of variables
|
|
and @var{DCG-goal} is a DCG-goal.
|
|
|
|
@item all @var{Vars} @var{DCG-goal}
|
|
A DCG universal quantification.
|
|
@var{Vars} is a list of variables
|
|
and @var{DCG-goal} is a DCG-goal.
|
|
|
|
@item @var{DCG-goal1}, @var{DCG-goal2}
|
|
A DCG sequence.
|
|
@var{DCG-goal1} and @var{DCG-goal2} are DCG-goals.
|
|
Intuitively, this means ``parse @var{DCG-goal1} and then parse @var{DCG-goal2}''
|
|
or ``do @var{DCG-goal1} and then do @var{DCG-goal2}''.
|
|
(Note that the only way this construct actually forces the desired sequencing
|
|
is by the modes of the implicit DCG arguments.)
|
|
|
|
@item @var{DCG-goal1} ; @var{DCG-goal2}
|
|
A disjunction. @var{DCG-goal1} and @var{DCG-goal2} are DCG-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.)
|
|
|
|
@item @{ @var{Goal} @}
|
|
A brace-enclosed ordinary goal.
|
|
@var{Goal} is a goal.
|
|
|
|
@item [@var{Expr}, @dots{}]
|
|
A DCG input match.
|
|
@var{Expr} is an expression.
|
|
Unifies the implicit DCG input variable V_in,
|
|
which must have type @samp{list(_)},
|
|
with a list whose initial elements are the expressions specified
|
|
and whose tail is the implicit DCG output variable V_out.
|
|
|
|
@item []
|
|
The null DCG goal (an empty DCG input match).
|
|
Equivalent to @samp{@{ true @}}.
|
|
|
|
@item not @var{DCG-goal}
|
|
@itemx \+ @var{DCG-goal}
|
|
A DCG negation.
|
|
@var{DCG-goal} is a DCG-goal.
|
|
The two different syntaxes have identical semantics.
|
|
|
|
@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} are DCG-goals.
|
|
|
|
@item =(@var{Expr})
|
|
A DCG unification.
|
|
@var{Expr} is an expression.
|
|
Unifies @var{Expr} with the implicit DCG argument.
|
|
|
|
@item :=(@var{Expr})
|
|
A DCG output unification.
|
|
@var{Expr} is an expression.
|
|
Unifies @var{Expr} with the implicit DCG output argument,
|
|
ignoring the input DCG argument.
|
|
|
|
@item @var{Expr} =^ @var{field_list}
|
|
A DCG field selection.
|
|
@var{Expr} is an expression
|
|
and @var{field_list} is a field list.
|
|
Unifies @var{Expr} with the result of
|
|
applying the field selection @var{field_list} to the implicit DCG argument.
|
|
@xref{Field access expressions}.
|
|
|
|
@item ^ @var{field_list} := @var{Expr}
|
|
A DCG field update.
|
|
@var{Expr} is an expression
|
|
and @var{field_list} is a field list.
|
|
Replaces a field in the implicit DCG argument.
|
|
@xref{Field access expressions}.
|
|
|
|
@item @var{DCG-call}
|
|
A term which does not match any of the above forms
|
|
is a DCG predicate call.
|
|
If @var{DCG-call} 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.
|
|
|
|
@end table
|
|
|
|
The semantics is given by the following function,
|
|
where each occurrence of @var{V_new} is a fresh variable.
|
|
@example
|
|
transform(V_in, V_out, some Vars DCG_goal) =
|
|
some Vars transform(V_in, V_out, DCG_goal)
|
|
|
|
transform(V_in, V_out, all Vars DCG_goal) =
|
|
all Vars transform(V_in, V_out, DCG_goal)
|
|
|
|
transform(V_in, V_out, (DCG-goal1, DCG-goal2)) =
|
|
(transform(V_in, V_new, DCG_goal1), transform(V_new, V_out, DCG_goal2))
|
|
|
|
transform(V_in, V_out, (DCG_goal1 ; DCG_goal2)) =
|
|
( transform(V_in, V_out, DCG_goal1)
|
|
; transform(V_in, V_out, DCG_goal2)
|
|
)
|
|
|
|
transform(V_in, V_out, @{ Goal @}) = (Goal, V_out = V_in)
|
|
|
|
transform(V_in, V_out, [Expr, @dots{}]) = (V_in = [Expr, @dots{} | V_Out])
|
|
|
|
transform(V_in, V_out, []) = (V_out = V_in)
|
|
|
|
transform(V_in, V_out, not DCG_goal) =
|
|
(not transform(V_in, V_new, DCG_goal), V_out = V_in)
|
|
|
|
transform(V_in, V_out, if CondGoal then ThenGoal else ElseGoal) =
|
|
( if transform(V_in, V_new, CondGoal) then
|
|
transform(V_new, V_out, ThenGoal)
|
|
else
|
|
transform(V_in, V_out, ElseGoal)
|
|
)
|
|
|
|
transform(V_in, V_out, =(Expr)) = (Expr = V_in, V_out = V_in)
|
|
|
|
transform(V_in, V_out, :=(Expr)) = (V_out = Expr)
|
|
|
|
transform(V_in, V_out, Expr =^ field_list) =
|
|
(Expr = V_in ^ field_list, V_out = V_in)
|
|
|
|
transform(V_in, V_out, ^ field_list := Expr) =
|
|
(V_out = V_in ^ field_list := Expr)
|
|
|
|
transform(V_in, V_out, p(A1, @dots{}, AN)) =
|
|
p(A1, @dots{}, AN, V_in, V_out)
|
|
@end example
|
|
|
|
@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::
|
|
* The standard ordering::
|
|
@end menu
|
|
|
|
@node Builtin types
|
|
@section Builtin types
|
|
|
|
This section describes the special types
|
|
that are built into the Mercury implementation,
|
|
or are defined in the standard library.
|
|
|
|
@menu
|
|
* Primitive types::
|
|
* Other builtin types::
|
|
@end menu
|
|
|
|
@node Primitive types
|
|
@subsection Primitive types
|
|
|
|
There is a special syntax
|
|
for constants of all primitive types except @code{char}.
|
|
(For @code{char}, the standard syntax suffixes.)
|
|
|
|
@menu
|
|
* Signed integer types::
|
|
* Unsigned integer types::
|
|
* Floating-point type::
|
|
* Character type::
|
|
* String type::
|
|
@end menu
|
|
|
|
@node Signed integer types
|
|
@subsubsection Signed integer types
|
|
There are five primitive signed integer types:
|
|
@code{int}, @code{int8}, @code{int16}, @code{int32} and @code{int64}.
|
|
|
|
Except for @code{int},
|
|
the width in bits of each of these is given by the numeric suffix in its name.
|
|
|
|
The width in bits of @code{int} is implementation defined,
|
|
but must be at least 32-bits.
|
|
|
|
All signed integer types use two's-complement representation.
|
|
Their width must be equal to the width of the corresponding unsigned type.
|
|
|
|
Values of the type @code{int8} must be in the range
|
|
@math{-128} (@math{-(2^{8 - 1})}) to @math{127} (@math{2^{8 - 1} - 1}),
|
|
both inclusive.
|
|
|
|
Values of the type @code{int16} must be in the range
|
|
@math{-32768} (@math{-(2^{16 - 1})}) to @math{32767} (@math{2^{16 - 1} - 1}),
|
|
both inclusive.
|
|
|
|
Values of the type @code{int32} must be in the range
|
|
@math{-2147483648} (@math{-(2^{32 - 1})})
|
|
to @math{2147483647} (@math{2^{32 - 1} - 1}),
|
|
both inclusive.
|
|
|
|
Values of the type @code{int64} must be in the range
|
|
@math{-9223372036854775808} (@math{-(2^{64 - 1})})
|
|
to @math{9223372036854775807} (@math{2^{64 - 1} - 1}),
|
|
both inclusive.
|
|
|
|
Values of the type @code{int} must be in the range
|
|
to @math{-(2^{N - 1})} to @math{2^{N - 1} - 1},
|
|
both inclusive;
|
|
@math{N} being the width of @code{int} in bits.
|
|
|
|
@node Unsigned integer types
|
|
@subsubsection Unsigned integer types
|
|
There are five primitive unsigned integer types:
|
|
@code{uint}, @code{uint8}, @code{uint16}, @code{uint32} and @code{uint64}.
|
|
|
|
Except for @code{uint},
|
|
the width in bits of each of these is given by the numeric suffix in its name.
|
|
|
|
The width in bits of @code{uint} is implementation defined,
|
|
but must be at least 32-bits.
|
|
It must be equal to the width of the type @code{int}.
|
|
|
|
Values of the type @code{uint8} must be in the range
|
|
@math{0} (@math{2^0 - 1}) to @math{255} (@math{2^8 - 1}),
|
|
both inclusive.
|
|
|
|
Values of the type @code{uint16} must be in the range
|
|
@math{0} (@math{2^0- 1}) to @math{65535} (@math{2^16 - 1}),
|
|
both inclusive.
|
|
|
|
Values of the type @code{uint32} must be in the range
|
|
@math{0} (@math{2^0 - 1}) to @math{4294967295} (@math{2^32 - 1}),
|
|
both inclusive.
|
|
|
|
Values of the type @code{uint64} must be in the range
|
|
@math{0} (@math{2^0 - 1}) to @math{18446744073709551615} (@math{2^64 - 1}),
|
|
both inclusive.
|
|
|
|
Values of the type @math{uint} must be in the range
|
|
@math{0} (@math{2^0 - 1}) to @math{2^N - 1},
|
|
both inclusive;
|
|
@math{N} being the width of @code{uint} in bits.
|
|
|
|
@node Floating-point type
|
|
@subsubsection Floating-point type
|
|
There is one floating-point type: @code{float}.
|
|
|
|
It is represented using either the 32-bit single-precision IEEE 754 format
|
|
or the 64-bit double-precision IEEE 754 format.
|
|
|
|
The choice between the two formats is implementation dependent.
|
|
|
|
In the Melbourne Mercury implementation,
|
|
@code{float}s are represented
|
|
using the 32-bit single-precision IEEE 754 format
|
|
in grades that have @code{.spf} grade component,
|
|
and using the 64-bit double-precision IEEE 754 format in every other grade.
|
|
|
|
@node Character type
|
|
@subsubsection Character type
|
|
There is one character type: @code{char}.
|
|
|
|
Values of this type represent Unicode code points.
|
|
|
|
@node String type
|
|
@subsubsection String type
|
|
There is one string type: @code{string}.
|
|
|
|
A string is a sequence of characters encoded
|
|
using either the UTF-8 or UTF-16 encoding of Unicode.
|
|
|
|
The choice between the two encodings is implementation dependent.
|
|
|
|
In the Melbourne Mercury implementation,
|
|
@code{string}s are represented
|
|
using UTF-8 when generating code for C,
|
|
and using UTF-16 when generating code for C# or Java.
|
|
|
|
@node Other builtin types
|
|
@subsection Other builtin types
|
|
|
|
@menu
|
|
* Predicate and function types::
|
|
* Tuple types::
|
|
* The universal type::
|
|
* The ``state-of-the-world'' type::
|
|
@end menu
|
|
|
|
@node Predicate and function types
|
|
@subsubsection Predicate and function types
|
|
The predicate types are
|
|
@code{pred}, @code{pred(T)}, @code{pred(T1, T2)}, @dots{}
|
|
|
|
@noindent
|
|
The function types are
|
|
@code{(func) = T}, @code{func(T1) = T}, @code{func(T1, T2) = T}, @dots{}
|
|
|
|
Higher-order predicate and function types
|
|
are used to pass closures to other predicates and functions.
|
|
@xref{Higher-order}.
|
|
|
|
@node Tuple types
|
|
@subsubsection Tuple types
|
|
The tuple types are @code{@{@}}, @code{@{T@}}, @code{@{T1, T2@}}, @dots{}
|
|
|
|
A tuple type is equivalent to a discriminated union type
|
|
(@pxref{Discriminated unions}) with declaration
|
|
@example
|
|
:- type @{Arg1, Arg2, @dots{}, ArgN@}
|
|
---> @{ @{Arg1, Arg2, @dots{}, ArgN@} @}.
|
|
@end example
|
|
|
|
@node The universal type
|
|
@subsubsection The universal type
|
|
The type @code{univ} is defined in the standard library module @code{univ},
|
|
along with the predicates @code{type_to_univ/2} and @code{univ_to_type/2}.
|
|
With those predicates,
|
|
values of any type can be converted to the universal type, and back again.
|
|
The conversion from @code{univ} to the original type
|
|
will check that the value inside the @code{univ} has the expected type.
|
|
The universal type is useful for situations
|
|
where you need heterogeneous collections.
|
|
|
|
@node The ``state-of-the-world'' type
|
|
@subsubsection The ``state-of-the-world'' type
|
|
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 only reference to the current state of the world,
|
|
and produce a unique reference to the new state of the world.
|
|
In this way, we can give a declarative semantics to code that performs I/O.
|
|
|
|
@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::
|
|
* Subtypes::
|
|
@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 semicolons.
|
|
|
|
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}.
|
|
(The reverse is not the case:
|
|
a variable occurring in the @var{type}
|
|
need not also occur in the @var{body}.
|
|
Such variables are called @samp{phantom type parameters},
|
|
and their use is explained below.)
|
|
|
|
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 named.
|
|
These names 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
|
|
(@pxref{Field access functions}).
|
|
A named argument has the form @w{@code{@var{fieldname} :: @var{Type}}}.
|
|
It is an error for
|
|
two fields in the same type definition to have the same name,
|
|
even if the fields they name occur in different data constructors.
|
|
|
|
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 semicolon 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 semicolon.
|
|
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}.
|
|
We recommend against using constructors named @code{'@{@}'}
|
|
because of the possibility of confusion with the builtin tuple types.
|
|
|
|
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.)
|
|
@c XXX Was that restriction already lifted?
|
|
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.
|
|
|
|
@c XXX The `where direct_arg' attribute is not documented because it requires
|
|
@c the user has a detailed understanding of the type representation, and
|
|
@c is very implementation specific. The following is for implementors.
|
|
|
|
@c Discriminated union type definitions may be followed by a
|
|
@c @samp{direct_arg} attribute of the following form:
|
|
@c
|
|
@c @example
|
|
@c where direct_arg is @var{ctors}
|
|
@c @end example
|
|
@c
|
|
@c @noindent
|
|
@c where @var{ctors} is a list of @var{functor-name} / @var{functor-arity}.
|
|
@c The functor arities must always be one.
|
|
@c
|
|
@c The attribute notifies importing modules that each of the functors
|
|
@c listed is to be represented as a tagged pointer to its argument. The
|
|
@c argument type must be known, when compiling the module that the type is
|
|
@c defined in, to not require the use of the tag bits. The compiler will
|
|
@c emit an error message otherwise. The compiler will silently ignore
|
|
@c functors which require a secondary tag.
|
|
@c
|
|
@c The optimised type representation is usually only applied if the
|
|
@c argument type is defined in the interface section of the same module.
|
|
@c This attribute allows the programmer to also apply it when the argument
|
|
@c type is known to the defining module, but not necessarily modules which
|
|
@c import the top-level type.
|
|
@c
|
|
@c Ideally, the @samp{direct_arg} attribute would be automatically
|
|
@c generated when making an interface file, so the user would never need to
|
|
@c write it manually. At this time, the compiler does not have enough
|
|
@c information when making interface files.
|
|
|
|
Note that user-defined types may not have names that have meanings in Mercury.
|
|
(Most of these are documented in later sections.)
|
|
|
|
The list of reserved type names is
|
|
@example
|
|
int
|
|
int8
|
|
int16
|
|
int32
|
|
int64
|
|
uint
|
|
uint8
|
|
uint16
|
|
uint32
|
|
uint64
|
|
float
|
|
character
|
|
string
|
|
@{@}
|
|
=
|
|
=<
|
|
pred
|
|
func
|
|
pure
|
|
semipure
|
|
impure
|
|
''
|
|
@end example
|
|
|
|
Phantom type parameters are useful when you have
|
|
two distinct concepts that you want to keep separate,
|
|
but for which nevertheless you want to use the representation.
|
|
This is an example of their use, taken from the Mercury compiler:
|
|
|
|
@example
|
|
:- type var(T)
|
|
---> ...
|
|
|
|
:- type prog_var == var(prog_var_type).
|
|
:- type type_var == var(type_var_type).
|
|
|
|
:- type prog_var_type
|
|
---> prog_var_type.
|
|
:- type type_var_type
|
|
---> type_var_type.
|
|
@end example
|
|
|
|
The @code{var} type represents the generic notion of a variable.
|
|
It has a phantom type parameter, @code{T},
|
|
which does not occur in the body of its type definition.
|
|
The @code{prog_var} and @code{type_var} types represent
|
|
two different specific kinds of variables:
|
|
program variables, which occur in code (clauses),
|
|
and type variables, which occur in types, respectively.
|
|
They each bind a different type to the type parameter @code{T}.
|
|
These types, @code{prog_var_type} and @code{type_var_type},
|
|
each have a single function symbol of arity zero.
|
|
This means that each type has only one value,
|
|
which in turn means that values of these types contain no information at all.
|
|
But containing information is not the purpose of these types.
|
|
Their purpose is to ensure that
|
|
if ever a computation that expects program variables
|
|
is ever accidentally given type variables, or vice versa,
|
|
this mismatch is detected and reported by the compiler.
|
|
Two variables can be unified only if they have the same type.
|
|
While two @code{prog_var}s have the same type,
|
|
and two @code{type_var}s have the same type,
|
|
a @code{prog_var} and @code{type_var} have different types,
|
|
due to having different types
|
|
(@code{prog_var_type} and @code{type_var_type})
|
|
being bound to the phantom type parameter @code{T}.
|
|
|
|
@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 give a definition for all of 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.
|
|
|
|
@c -----------------------------------------------------------------------
|
|
|
|
@node Subtypes
|
|
@subsection Subtypes
|
|
|
|
(This is a new and experimental feature, subject to change.)
|
|
|
|
A subtype is a discriminated union type
|
|
that is a subset of a supertype,
|
|
in that every term of a subtype is a valid term in the supertype.
|
|
It is possible to convert terms between subtype and supertype
|
|
using type conversion expressions (@pxref{Type conversions}).
|
|
|
|
As previously described,
|
|
the syntax for non-subtype discriminated union types is
|
|
@example
|
|
:- type @var{type} ---> @var{body}.
|
|
@end example
|
|
where @var{type} is the name of a type constructor
|
|
applied to zero or more distinct type variables
|
|
(the @emph{parameters} of the type constructor),
|
|
and @var{body} is a sequence of constructor definitions
|
|
separated by semicolons.
|
|
All universally quantified type variables that occur in @var{body}
|
|
must be among @var{type}'s parameters.
|
|
|
|
The syntax for subtypes is similar but slightly different:
|
|
@example
|
|
:- type @var{subtype} =< @var{supertype} ---> @var{body}.
|
|
@end example
|
|
Since a subtype is also a discriminated union type,
|
|
the rules for discriminated union types apply to them as well:
|
|
@var{subtype} must be the name of a type constructor
|
|
applied to zero or more distinct type variables (its parameters),
|
|
@var{body} must be a sequence of constructor definitions
|
|
separated by semicolons,
|
|
and all universally quantified type variables that occur in @var{body}
|
|
must be among @var{subtype}'s parameters.
|
|
|
|
@var{supertype} must be a type constructor
|
|
applied to zero or more argument types,
|
|
which @emph{may} be type variables, but they do not have to be,
|
|
and if they are, do not need to be distinct.
|
|
After expanding out equivalences,
|
|
@var{supertype}'s principal type constructor
|
|
must specify a discriminated union type
|
|
whose definition is in scope where the subtype definition occurs,
|
|
by normal module visibility rules.
|
|
|
|
The discriminated union type specified by @var{supertype}
|
|
may itself be a subtype.
|
|
Following the chain of subtype definitions,
|
|
it must be possible to arrive at a @emph{base type},
|
|
which is a discriminated union type but @emph{not} a subtype.
|
|
|
|
The body of the subtype may differ from the body of its supertype in two ways.
|
|
@itemize @bullet
|
|
@item
|
|
It may omit one or more constructor definitions.
|
|
The ability to do this is the main motivation for the use of subtypes.
|
|
|
|
Since the subtype cannot @emph{add} definitions of constructors,
|
|
the set of constructor definitions in the subtype
|
|
must be a subset of the constructors definitions in the supertype.
|
|
We recommend that they should appear in the same relative order
|
|
as in the supertype definition.
|
|
@item
|
|
It may change the types of some of the arguments of some of the constructors,
|
|
@emph{provided} that each replacement replaces a type with one of its subtypes.
|
|
|
|
Formally, this means that
|
|
if the supertype @samp{t} has a constructor @samp{f(T1, ..., Tn)},
|
|
and the subtype @samp{s =< t} has a constructor @samp{f(S1, ..., Sn)},
|
|
then for each @var{Si}, the condition @samp{Si =< Ti} must hold,
|
|
where @samp{=<} is the subtype relation below.
|
|
@end itemize
|
|
|
|
This is an example of the first kind of difference:
|
|
@example
|
|
:- type fruit
|
|
---> apple
|
|
; pear
|
|
; lemon
|
|
; orange.
|
|
|
|
:- type citrus_fruit =< fruit
|
|
---> lemon
|
|
; orange.
|
|
@end example
|
|
|
|
And this is an example of the second:
|
|
@example
|
|
:- type fruit_basket
|
|
---> basket(fruit, int).
|
|
% What kind of fruit, and how many.
|
|
|
|
:- type citrus_fruit_basket =< fruit_basket
|
|
---> basket(citrus_fruit, int).
|
|
@end example
|
|
|
|
(There are more examples below.)
|
|
|
|
If the subtype retains a constructor from the supertype
|
|
that has one or more existentially quantified type variables,
|
|
then the subtype constructor must repeat
|
|
the list of existentially quantified type variables
|
|
from the supertype constructor,
|
|
and all existential class constraints,
|
|
with no additions, removals, or reordering.
|
|
(The type variables do not need to have the same names
|
|
in the subtype as the supertype,
|
|
but, stylistically, it makes more sense if they do.)
|
|
|
|
As mentioned above,
|
|
any universally quantified type variable
|
|
that occurs in @var{body} must occur also in @var{subtype}.
|
|
However, this is the only restriction
|
|
on the list of parameters in @var{subtype}.
|
|
For example, it need not have any particular relationship
|
|
with the list of parameters
|
|
of the principal type constructor of @var{supertype}.
|
|
For example, @var{subtype} may have
|
|
a phantom type parameter (@pxref{Discriminated unions})
|
|
that does not occur in @var{supertype}.
|
|
|
|
@c There should be some discussion here
|
|
@c of the possible uses of this flexibility.
|
|
|
|
(In the following discussion,
|
|
we assume that all equivalence types have been expanded out.)
|
|
|
|
The subtype relation @samp{S =< T} has four cases to consider:
|
|
when @samp{S} and @samp{T} are both discriminated union types,
|
|
when they are both tuple types,
|
|
when they are both higher-order types,
|
|
and all other types.
|
|
|
|
@c Manually numbered as @enumerate introduces another level of indentation
|
|
@c and leaves too little space between the items.
|
|
@noindent
|
|
1. For discriminated union types @samp{S} and @samp{T}:
|
|
@itemize
|
|
@item
|
|
If @samp{S} and @samp{T} have the same principal type constructor,
|
|
say @samp{f/n}, which implies that
|
|
@samp{S = f(S1, ..., Sn)} and @samp{T = f(T1, ..., Tn)},
|
|
then @samp{S =< T} holds if and only if
|
|
for all @var{i} in @samp{1..n}, @samp{Si =< Ti}.
|
|
@item
|
|
If @samp{S} and @samp{T} have different principal type constructors,
|
|
and if @samp{S = f(S1, ..., Sn)}, @samp{S =< T} holds if
|
|
@itemize @minus
|
|
@item
|
|
there is a visible subtype definition starting with
|
|
@w{@samp{:- type f(R1, ..., Rn) =< U}},
|
|
@item
|
|
for all @var{i} in @samp{1..n}, @w{@samp{Si = Ri}} (unification), and
|
|
@item
|
|
@samp{U =< T}.
|
|
@end itemize
|
|
In other words, if all occurrences of @var{Ri} in @var{U}
|
|
are replaced by the corresponding for @var{Si} to give @var{Usub},
|
|
then @samp{Usub =< T} must hold.
|
|
@end itemize
|
|
|
|
@noindent
|
|
2. For two tuple types
|
|
@samp{S = @{S1, ..., Sn@}} and @samp{T = @{T1, ..., Tn@}},
|
|
@samp{S =< T} holds if and only if
|
|
@samp{Si =< Ti} for all @samp{i} in @samp{1..n}.
|
|
This is analogous to the case for discriminated union types
|
|
with the same principal type constructor.
|
|
|
|
@noindent
|
|
3. A higher-order type @samp{S}
|
|
can be a subtype of another higher-order type @samp{T}
|
|
in only one way.
|
|
Since subtype definitions do not apply to higher-order types,
|
|
this way is analogous to the case for discriminated union types
|
|
with the same principal type constructor.
|
|
|
|
@itemize
|
|
@item
|
|
@samp{P =< Q} holds for two higher-order types @var{P} and @var{Q}
|
|
if and only if all of the following conditions hold:
|
|
@itemize @minus
|
|
@item
|
|
@var{P} and @var{Q} are either
|
|
both @samp{pred} types, or both @samp{func} types,
|
|
@item
|
|
they have the same arity,
|
|
@item
|
|
@var{P} and @var{Q} have the same argument types
|
|
(the current implementation does not allow subtyping
|
|
in higher-order arguments), and
|
|
@item
|
|
if either of @var{P} and @var{Q} has higher-order inst information,
|
|
then @var{P} and @var{Q} must have
|
|
the @emph{same} higher-order inst information,
|
|
i.e.@ their higher-order inst information must specify
|
|
the same argument modes, determinism, and purity.
|
|
@end itemize
|
|
@end itemize
|
|
|
|
@noindent
|
|
4. For all other types,
|
|
@samp{S =< T} if and only if @samp{S = T},
|
|
i.e.@ they are syntactically identical.
|
|
|
|
A subtype may be exported as an abstract type
|
|
by declaring only the name of the subtype in the
|
|
interface section of a module (without the @samp{=< @var{supertype}} part).
|
|
Then the subtype definition must be given in the implementation section of
|
|
the same module.
|
|
|
|
Example:
|
|
|
|
@example
|
|
:- interface.
|
|
|
|
:- type non_empty_list(T). % abstract type
|
|
|
|
:- implementation.
|
|
|
|
:- import list.
|
|
|
|
:- type non_empty_list(T) =< list(T)
|
|
---> [T | list(T)].
|
|
@end example
|
|
|
|
Subtypes must not have user-defined equality or comparison predicates.
|
|
The base type of a subtype may have user-defined equality or comparison.
|
|
In that case, values of the subtype will be tested for equality or
|
|
compared using those predicates.
|
|
|
|
There is no special interaction between subtypes and the type class system.
|
|
|
|
Some more examples of subtypes:
|
|
|
|
@example
|
|
:- type list(T)
|
|
---> []
|
|
; [T | list(T)].
|
|
|
|
:- type non_empty_list(T) =< list(T)
|
|
---> [T | list(T)].
|
|
|
|
:- type non_empty_list_of_foo =< list(foo)
|
|
---> [foo | list(foo)].
|
|
|
|
:- type maybe_foo
|
|
---> none
|
|
; some [T] foo(T) => fooable(T).
|
|
|
|
:- type foo =< maybe_foo
|
|
---> some [T] foo(T) => fooable(T).
|
|
|
|
:- type task
|
|
---> create(pred(int::in, io::di, io::uo) is det)
|
|
; delete(pred(int::in, io::di, io::uo) is det).
|
|
|
|
:- type create_task =< task
|
|
---> create(pred(int::in, io::di, io::uo) is det).
|
|
@end example
|
|
|
|
And one more complex example.
|
|
|
|
In the case of a set of mutually recursive types,
|
|
omitting some constructor definitions from a type may not be enough;
|
|
it may be necessary to replace some argument types with their subtypes as well.
|
|
Consider this pair of mutually recursive types representing a bipartite graph,
|
|
i.e.@ a graph in which there are two kinds of nodes,
|
|
and edges always connect two nodes of different kinds.
|
|
In this bipartite graph,
|
|
the two kinds of nodes are @var{or} nodes and @var{and} nodes,
|
|
and each kind of node can be connected to zero, two or more nodes
|
|
of the other kind.
|
|
|
|
@example
|
|
:- type or_node
|
|
---> or_source(source_id)
|
|
; logical_or(and_node, and_node)
|
|
; logical_or_list(and_node, and_node, and_node, list(and_node)).
|
|
|
|
:- type and_node
|
|
---> and_source(source_id)
|
|
; logical_and(or_node, or_node)
|
|
; logical_and_list(or_node, or_node, or_node, list(or_node)).
|
|
@end example
|
|
|
|
If we wanted a subtype to represent graphs in which
|
|
no @var{or} node could be connected to more than two @var{and} nodes,
|
|
one might think that it would be enough
|
|
to delete the @var{logical_or_list} constructor from the @var{or_node} type,
|
|
like this:
|
|
|
|
@example
|
|
:- type binary_or_node =< or_node
|
|
---> or_source(source_id)
|
|
; logical_or(and_node, and_node).
|
|
@end example
|
|
|
|
However, this would not work,
|
|
because the @var{and_node}s have constructors
|
|
whose arguments have type @var{or_node}, not @var{binary_or_node}.
|
|
One would have to create a subtype of the @var{and_node} type
|
|
that constructs @var{and} nodes
|
|
from @var{binary_or_node}s, not plain @var{or_node}s,
|
|
like this:
|
|
|
|
@example
|
|
:- type binary_or_node =< or_node
|
|
---> or_source(source_id)
|
|
; logical_or(binary_or_and_node, binary_or_and_node).
|
|
|
|
:- type binary_or_and_node =< and_node
|
|
---> and_source(source_id)
|
|
; logical_and(binary_or_node, binary_or_node)
|
|
; logical_and_list(binary_or_node, binary_or_node, binary_or_node,
|
|
list(binary_or_node)).
|
|
@end example
|
|
|
|
@c -----------------------------------------------------------------------
|
|
|
|
@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
|
|
|
|
A predicate or function can be declared
|
|
to have a given higher-order type (@pxref{Higher-order})
|
|
by using an explicit type qualification in the type declaration.
|
|
This is useful where several predicates or functions
|
|
need to have the same type signature,
|
|
which often occurs for type class method implementations
|
|
(@pxref{Type classes}),
|
|
and for predicates to be passed as higher-order terms.
|
|
|
|
For example,
|
|
|
|
@example
|
|
:- type foldl_pred(T, U) == pred(T, U, U).
|
|
:- type foldl_func(T, U) == (func(T, U) = U).
|
|
|
|
:- pred p(int) : foldl_pred(T, U).
|
|
:- func f(int) : foldl_func(T, U).
|
|
@end example
|
|
|
|
@noindent
|
|
is equivalent to
|
|
|
|
@example
|
|
:- pred p(int, T, U, U).
|
|
:- pred f(int, T, U) = U.
|
|
@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.
|
|
|
|
There must be at least one clause defined
|
|
for each declared predicate or function,
|
|
except for those defined using the foreign language interface
|
|
(@pxref{Foreign language interface}).
|
|
However, Mercury implementations are permitted to provide a method
|
|
of processing Mercury programs in which such errors are not reported
|
|
until and unless the predicate or function is actually called.
|
|
(The Melbourne Mercury implementation provides this
|
|
with its @samp{--allow-stubs} option.
|
|
This can be useful during program development,
|
|
since it allows you to execute parts of a program
|
|
while the program's implementation is still incomplete.)
|
|
|
|
Note that a predicate defined using DCG notation (@pxref{Items})
|
|
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 expressions,
|
|
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.
|
|
|
|
The type assigned to each expression with an explicit type qualification
|
|
(@pxref{Expressions})
|
|
must match the type specified by the type qualification
|
|
expression@footnote{The type of an explicitly
|
|
type qualified term may be an instance of the type specified by the
|
|
qualifier. This allows explicit type qualifications to constrain the
|
|
types of two expressions to be identical, without knowing the exact types
|
|
of the expressions. It also allows type qualifications to refer to the
|
|
types of the results of existentially typed predicates or functions.}.
|
|
|
|
(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 @var{A}
|
|
that makes it identical (up to renaming of parameters) to @var{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 named
|
|
(@pxref{Discriminated unions}).
|
|
These names 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{Field access expressions})
|
|
and to select and update fields of the DCG arguments of a clause
|
|
(@pxref{Definite clause grammars}).
|
|
|
|
@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 name @samp{@var{field}} in a constructor
|
|
tells the compiler to generate
|
|
a field selection function @samp{@var{field}/1},
|
|
which takes an expression of the same type as the constructor
|
|
and returns the value of the named 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 type and modes of this function may be explicitly declared,
|
|
in which case it will have only the declared modes.
|
|
|
|
To create a higher-order value from a field selection function,
|
|
an explicit lambda expression must be used,
|
|
unless a single mode declaration is supplied for the field selection function.
|
|
The reason for this is that normally,
|
|
field access functions are implemented directly as unifications,
|
|
without the code of a function being generated for them.
|
|
The declaration acts as the request for the generation of that code.
|
|
|
|
@node Field update
|
|
@subsection Field update
|
|
|
|
@example
|
|
'@var{field} :='(@var{Term}, @var{ValueTerm})
|
|
@end example
|
|
|
|
Each field name @samp{@var{field}} in a constructor
|
|
tells the compiler to generate
|
|
a field update function @samp{'@var{field} :='/2}.
|
|
The first argument of this function
|
|
is an expression of the same type as the constructor.
|
|
The second argument
|
|
is an expression of the same type as the named field.
|
|
The return value is a copy of the first argument
|
|
with the value of the named 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 named 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 type and modes of this function may be explicitly declared,
|
|
in which case it will have only the declared modes.
|
|
|
|
To create a higher-order value from a field update function,
|
|
users must write an explicit lambda expression,
|
|
unless a single mode declaration is supplied for the field update function.
|
|
The reason for this is that normally, as with field selection functions,
|
|
field update functions are implemented directly as unifications,
|
|
without the code of a function being generated for them.
|
|
The declaration acts as the request
|
|
for the compiler to generate that 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.
|
|
The user-supplied declarations will be used instead of
|
|
any automatically generated declarations.
|
|
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 type declaration and a single mode declaration
|
|
also allows higher-order terms to be created
|
|
from a field access function without using explicit lambda expressions.
|
|
|
|
If a field occurs in the interface section of a module,
|
|
then any declaration for a field access function for that field
|
|
must also occur in the interface section.
|
|
|
|
If there are multiple fields with the same name in the same module,
|
|
only one of those fields can have user-supplied declarations
|
|
for its selection function.
|
|
Similarly, only one of those fields can have user-supplied declarations
|
|
for its update function.
|
|
|
|
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.
|
|
|
|
User-declared field access functions may take extra arguments.
|
|
For example, the Mercury standard library module @code{map}
|
|
contains the following functions:
|
|
@example
|
|
:- func elem(K, map(K, V)) = V is semidet.
|
|
:- func 'elem :='(K, map(K, V), V) = map(K, V).
|
|
@end example
|
|
Field access syntax may be used
|
|
at the top-level of @code{func} and @code{mode} declarations
|
|
and in the head of clauses.
|
|
For instance:
|
|
@example
|
|
:- func map(K, V) ^ elem(K) = V.
|
|
:- mode in ^ in = out is semidet.
|
|
Map ^ elem(Key) = map.lookup(Map, Key).
|
|
|
|
:- func (map(K, V) ^ elem(K) := V) = V.
|
|
:- mode (in ^ in := in) = out is semidet.
|
|
(Map ^ elem(Key) := Value) = map.set(Map, Key, Value).
|
|
@end example
|
|
|
|
The Mercury standard library modules @code{array} and @code{bt_array}
|
|
define similar functions.
|
|
|
|
@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 type1 ^ field1 = type2.
|
|
type1(Field1, _) ^ field1 = Field1.
|
|
|
|
:- func (type1 ^ field1 := type2) = type1.
|
|
(type1(_, Field2) ^ field1 := Field1) = type1(Field1, Field2).
|
|
@end example
|
|
|
|
Using these functions and the syntactic sugar described in
|
|
@ref{Field access expressions},
|
|
programmers can write code such as
|
|
|
|
@example
|
|
:- func type1 ^ increment_field3 = type1.
|
|
|
|
Term0 ^ increment_field3 =
|
|
Term0 ^ field1 ^ field3 := Term0 ^ field1 ^ field3 + 1.
|
|
@end example
|
|
|
|
The compiler expands this into
|
|
|
|
@example
|
|
increment_field3(Term0) = Term :-
|
|
OldField3 = field3(field1(Term0)),
|
|
OldField1 = field1(Term0),
|
|
NewField1 = 'field3 :='(OldField1, OldField3 + 1),
|
|
Term = 'field1 :='(Term0, NewField1).
|
|
@end example
|
|
|
|
The field access functions defined
|
|
in the Mercury standard library module @samp{map}
|
|
can be used as follows:
|
|
|
|
@example
|
|
:- func update_field_in_map(map(int, type1), int, string)
|
|
= map(int, type1) is semidet.
|
|
|
|
update_field_in_map(Map, Index, Value) =
|
|
Map ^ elem(Index) ^ field2 := Value.
|
|
@end example
|
|
|
|
@node The standard ordering
|
|
@section The standard ordering
|
|
|
|
For (almost) every Mercury type there exists a standard ordering;
|
|
any two values of the same type can be compared under this ordering
|
|
by using the @code{builtin.compare/3} predicate.
|
|
The ordering is total, meaning that the corresponding binary relations
|
|
are reflexive, transitive and anti-symmetric.
|
|
The one exception is higher-order types,
|
|
which cannot be unified or compared;
|
|
any attempt to do so will raise an exception.
|
|
|
|
The existence of this ordering makes it possible to implement
|
|
generic data structures such as sets and maps,
|
|
without needing to know the specifics of the ordering.
|
|
Furthermore, different platforms often have their own natural orderings
|
|
which are not necessarily consistent with each other.
|
|
As such, the standard ordering for most types is not fully defined.
|
|
|
|
For the primitive integer types,
|
|
the standard ordering is the usual numerical ordering.
|
|
Implementations should reject code containing overflowing integer literals.
|
|
|
|
For the primitive type @code{float},
|
|
the standard ordering approximates the usual numerical ordering.
|
|
If the result of @code{builtin.compare/3} is @code{(<)} or @code{(>)}
|
|
then this relation holds in the numerical ordering,
|
|
but this is not necessarily the case for @code{(=)} due to lack of precision.
|
|
In the standard ordering, ``negative'' and ``positive'' zero values are equal.
|
|
Implementations should replace overflowing literals
|
|
with the infinity of the same sign;
|
|
in the standard ordering positive infinity is greater than all finite values
|
|
and negative infinity is less than all finite values.
|
|
Implementations must throw an exception when comparing
|
|
a ``not a number'' (NaN) value.
|
|
|
|
For the primitive type @code{char},
|
|
the standard ordering is
|
|
the numerical ordering of the Unicode code point values.
|
|
|
|
For the primitive type @code{string},
|
|
the standard ordering is implementation dependent.
|
|
The current implementation performs string comparison using
|
|
the C @code{strcmp()} function,
|
|
the Java @code{String.compareTo()} method, and
|
|
the C# @code{System.String.CompareOrdinal()} method,
|
|
when compiling to C, Java and C# respectively.
|
|
|
|
For tuple types, corresponding arguments are compared,
|
|
with the first argument being the most significant,
|
|
then the second, and so on.
|
|
|
|
For discriminated union types (other than subtypes),
|
|
if both values have the same principal constructor
|
|
then corresponding arguments are compared in order,
|
|
with the first argument being the most significant,
|
|
then the second, and so on.
|
|
If the values have different principal constructors,
|
|
then the value whose principal constructor
|
|
is listed first in the definition of the type
|
|
will compare as less than the other value.
|
|
There is one exception from this rule:
|
|
in types that are subject to a @code{foreign_enum} pragma,
|
|
the outcomes of comparisons are decided
|
|
by user's chosen foreign language representations,
|
|
using the rules of the foreign language.
|
|
|
|
For subtypes, the two values compare as though
|
|
converted to the base type.
|
|
The ordering of constructors in a subtype definition
|
|
does not affect the standard ordering.
|
|
|
|
@node Modes
|
|
@chapter Modes
|
|
|
|
@menu
|
|
* Insts modes and mode definitions::
|
|
* Predicate and function mode declarations::
|
|
* Constrained polymorphic modes::
|
|
* Different clauses for different modes::
|
|
@end menu
|
|
|
|
@node Insts modes and mode definitions
|
|
@section Insts, modes, and mode definitions
|
|
|
|
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 @code{free} and @code{ground}
|
|
as names for instantiatedness trees
|
|
all of whose nodes are free and bound respectively
|
|
(with the exception of solver type values
|
|
which may be semantically ground,
|
|
but be defined in terms of non-ground solver type values;
|
|
see @ref{Solver types} for more detail).
|
|
The shape of these trees is determined
|
|
by the type of the variable to which they apply.
|
|
|
|
A more concise, alternative syntax exists
|
|
for @code{bound} instantiatedness trees:
|
|
|
|
@example
|
|
:- inst maybeskel
|
|
---> no
|
|
; yes(free).
|
|
@end example
|
|
|
|
@noindent
|
|
which is equivalent to writing
|
|
|
|
@example
|
|
:- inst maybeskel == bound(no ; yes(free)).
|
|
@end example
|
|
|
|
You can specify what type (actually what type constructor)
|
|
an inst is intended to be used on
|
|
by adding @code{for}, followed by the name and arity of that type constructor,
|
|
after the name of the inst, like this:
|
|
@example
|
|
:- inst maybeskel for maybe/1
|
|
---> no
|
|
; yes(free).
|
|
@end example
|
|
|
|
@noindent
|
|
This can be useful documentation,
|
|
and the compiler will generate an error message
|
|
when an inst that was declared to be for values of one type constructor
|
|
is applied to values of another type constructor.
|
|
|
|
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
|
|
|
|
Though we do not recommend this,
|
|
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,
|
|
i.e.@: terms that contain both function symbols and free variables,
|
|
such as @samp{f(a, b, X)}.
|
|
In the current implementation,
|
|
partially instantiated data structures are unsupported
|
|
due to a lack of alias tracking in the mode system.
|
|
For more information,
|
|
please see the @file{LIMITATIONS.md} file distributed with Mercury.
|
|
|
|
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 for operation/0
|
|
---> 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) for list/1
|
|
---> []
|
|
; [Inst | listskel(Inst)].
|
|
@end example
|
|
|
|
@noindent
|
|
defines the inst @samp{listskel(Inst)} to be a list skeleton
|
|
whose elements have inst @code{Inst};
|
|
you can then 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.
|
|
|
|
Note that user-defined insts and modes may not have names
|
|
that have meanings in Mercury.
|
|
(Most of these are documented in later sections.)
|
|
|
|
The list of reserved inst names is
|
|
@example
|
|
=<
|
|
any
|
|
bound
|
|
bound_unique
|
|
clobbered
|
|
clobbered_any
|
|
free
|
|
ground
|
|
is
|
|
mostly_clobbered
|
|
mostly_unique
|
|
mostly_unique_any
|
|
not_reached
|
|
unique
|
|
unique_any
|
|
@end example
|
|
|
|
The list of reserved mode names is
|
|
@example
|
|
=
|
|
>>
|
|
any_func
|
|
any_pred
|
|
func
|
|
is
|
|
pred
|
|
@end example
|
|
|
|
@node Predicate and function mode declarations
|
|
@section Predicate and function mode declarations
|
|
|
|
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
|
|
|
|
@noindent
|
|
the (type and) mode declarations
|
|
of the function @samp{length} and predicate @samp{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
|
|
|
|
As for type declarations,
|
|
a predicate or function can be defined
|
|
to have a given higher-order inst (@pxref{Higher-order insts and modes})
|
|
by using @code{`with_inst`} in the mode declaration.
|
|
|
|
For example,
|
|
|
|
@example
|
|
:- inst foldl_pred == (pred(in, in, out) is det).
|
|
:- inst foldl_func == (func(in, in) = out is det).
|
|
|
|
:- mode p(in) `with_inst` foldl_pred.
|
|
:- mode f(in) `with_inst` foldl_func.
|
|
@end example
|
|
|
|
@noindent
|
|
is equivalent to
|
|
|
|
@example
|
|
:- mode p(in, in, in, out) is det.
|
|
:- mode f(in, in, in) = out is det.
|
|
@end example
|
|
|
|
@noindent
|
|
(@samp{is det} is explained in @ref{Determinism}.)
|
|
|
|
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).
|
|
|
|
:- pred p `with_type` foldl_pred(T, U) `with_inst` foldl_pred.
|
|
@end example
|
|
|
|
It is an error for a predicate or function
|
|
whose @samp{pred} and @samp{mode} declarations are so combined
|
|
to have any other separate @samp{mode} declarations.
|
|
|
|
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 @code{in}
|
|
and the result of the function has mode @code{out}.
|
|
(However, there is no requirement that a function have such a mode;
|
|
if there is any explicit mode declaration, it overrides the default.)
|
|
|
|
If a predicate or function type declaration
|
|
occurs in the interface section of a module,
|
|
then all mode declarations for that predicate or function
|
|
must occur in the interface section of the @emph{same} module.
|
|
Likewise, if a predicate or function type declaration
|
|
occurs in the implementation section of a module,
|
|
then all mode declarations for that predicate or function
|
|
must occur in the implementation section of the @emph{same} module.
|
|
Therefore, is an error
|
|
for a predicate or function to have mode declarations
|
|
in both the interface and implementation sections of a module.
|
|
|
|
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 @samp{append}, the mode
|
|
|
|
@example
|
|
:- mode append(in_listskel, in_listskel, out_listskel).
|
|
@end example
|
|
|
|
@noindent
|
|
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 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 conjuncts in each conjunction
|
|
in the clauses 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 Constrained polymorphic modes
|
|
@section Constrained polymorphic modes
|
|
|
|
Mode declarations for predicates and functions may also have inst parameters.
|
|
However, such parameters must be constrained
|
|
to be @emph{compatible} with some other inst.
|
|
In a predicate or function mode declaration,
|
|
an inst of the form @samp{@var{InstParam} =< @var{Inst}},
|
|
where @var{InstParam} is a variable and @var{Inst} is an inst,
|
|
states that
|
|
@var{InstParam} is constrained to be @emph{compatible} with @var{Inst},
|
|
that is,
|
|
@var{InstParam} represents some inst
|
|
that can be used anywhere where @var{Inst} is required.
|
|
If an inst parameter occurs more than once in a declaration,
|
|
it must have the same constraint on each occurrence.
|
|
|
|
For example, in the mode declaration
|
|
@example
|
|
:- mode append(in(list_skel(I =< ground)), in(list_skel(I =< ground)),
|
|
out(list_skel(I =< ground))) is det.
|
|
@end example
|
|
@noindent
|
|
@code{I} is an inst parameter which is constrained to be ground.
|
|
If @samp{append} is called with the first two arguments
|
|
having an inst of, say, @samp{list_skel(bound(f))},
|
|
then after @samp{append} returns,
|
|
all three arguments will have inst @samp{list_skel(bound(f))}.
|
|
If the mode of append had been simply
|
|
@example
|
|
:- mode append(in(list_skel(ground)), in(list_skel(ground)),
|
|
out(list_skel(ground))) is det.
|
|
@end example
|
|
@noindent
|
|
then we would only have been able to infer an inst of @samp{list_skel(ground)}
|
|
for the third argument, not the more specific inst.
|
|
|
|
Note that attempting to call @samp{append}
|
|
when the first two arguments do not have ground insts
|
|
(e.g.@: @samp{list_skel(bound(g(free)))})
|
|
is a mode error because it violates the constraint on the inst parameter.
|
|
|
|
To avoid having to repeat a constraint everywhere that an inst parameter occurs,
|
|
it is possible to list the constraints after the rest of the mode declaration,
|
|
following a @samp{<=}.
|
|
E.g.@: the above example could have been written as
|
|
@example
|
|
:- (mode append(in(list_skel(I)), in(list_skel(I)),
|
|
out(list_skel(I))) is det) <= I =< ground.
|
|
@end example
|
|
|
|
Note that in the current Mercury implementation
|
|
this syntax requires parentheses
|
|
around the @samp{mode(@dots{}) is @var{Det}} part of the declaration.
|
|
|
|
Also, if the constraint on an inst parameter is @samp{ground}
|
|
then it is not necessary to give the constraint in the declaration.
|
|
The example can be further shortened to
|
|
@example
|
|
:- mode append(in(list_skel(I)), in(list_skel(I)), out(list_skel(I)))
|
|
is det.
|
|
@end example
|
|
|
|
Constrained polymorphic modes are particularly useful
|
|
when passing objects with higher-order types to polymorphic predicates,
|
|
since they allow the higher-order mode information to be retained
|
|
(@pxref{Higher-order}).
|
|
|
|
@node Different clauses for different modes
|
|
@section Different clauses for different modes
|
|
|
|
Because the compiler automatically reorders conjunctions to satisfy the modes,
|
|
it is often possible for a single clause to satisfy different modes.
|
|
However, occasionally reordering of conjunctions is not sufficient;
|
|
you may want to write different code for different modes.
|
|
|
|
For example, the usual code for list append
|
|
|
|
@example
|
|
append([], Ys, Ys).
|
|
append([X|Xs], Ys, [X|Zs]) :-
|
|
append(Xs, Ys, Zs).
|
|
@end example
|
|
|
|
@noindent
|
|
works fine in most modes,
|
|
but is not very satisfactory for the @samp{append(out, in, in)} mode of append,
|
|
because although every call in this mode only has at most one solution,
|
|
the compiler's determinism inference will not be able to infer that.
|
|
This means that using the usual code
|
|
for append in this mode will be inefficient,
|
|
and the overly conservative determinism inference
|
|
may cause spurious determinism errors later.
|
|
|
|
For this mode, it is better to use a completely different algorithm:
|
|
|
|
@example
|
|
append(Prefix, Suffix, List) :-
|
|
list.length(List, ListLength),
|
|
list.length(Suffix, SuffixLength),
|
|
PrefixLength = ListLength - SuffixLength,
|
|
list.split_list(PrefixLength, List, Prefix, Suffix).
|
|
@end example
|
|
|
|
@noindent
|
|
However, that code does not work in the other modes of @samp{append}.
|
|
|
|
To handle such cases, you can use mode annotations on clauses,
|
|
which indicate that particular clauses
|
|
should only be used for particular modes.
|
|
To specify that a clause only applies to a given mode,
|
|
each argument @var{Arg} of the clause head
|
|
should be annotated with the corresponding argument mode @var{Mode},
|
|
using the @samp{::} mode qualification operator,
|
|
i.e.@: @samp{@var{Arg} :: @var{Mode}}.
|
|
|
|
For example, if @samp{append} was declared as
|
|
@example
|
|
@group
|
|
:- pred append(list(T), list(T), list(T)).
|
|
:- mode append(in, in, out).
|
|
:- mode append(out, out, in).
|
|
:- mode append(in, out, in).
|
|
:- mode append(out, in, in).
|
|
@end group
|
|
@end example
|
|
|
|
@noindent
|
|
then you could implement it as
|
|
|
|
@example
|
|
@group
|
|
append(L1::in, L2::in, L3::out) :- usual_append(L1, L2, L3).
|
|
append(L1::out, L2::out, L3::in) :- usual_append(L1, L2, L3).
|
|
append(L1::in, L2::out, L3::in) :- usual_append(L1, L2, L3).
|
|
append(L1::out, L2::in, L3::in) :- other_append(L1, L2, L3).
|
|
|
|
usual_append([], Ys, Ys).
|
|
usual_append([X|Xs], Ys, [X|Zs]) :- usual_append(Xs, Ys, Zs).
|
|
|
|
other_append(Prefix, Suffix, List) :-
|
|
list.length(List, ListLength),
|
|
list.length(Suffix, SuffixLength),
|
|
PrefixLength = ListLength - SuffixLength,
|
|
list.split_list(PrefixLength, List, Prefix, Suffix).
|
|
@end group
|
|
@end example
|
|
|
|
This language feature can be used to write ``impure'' code
|
|
that does not have any consistent declarative semantics.
|
|
For example, you can easily use it
|
|
to write something similar to Prolog's (in)famous @samp{var/1} predicate:
|
|
|
|
@example
|
|
:- mode var(in).
|
|
:- mode var(free>>free).
|
|
var(_::in) :- fail.
|
|
var(_::free>>free) :- true.
|
|
@end example
|
|
|
|
@noindent
|
|
As you can see, in this case the two clauses are @emph{not} equivalent.
|
|
|
|
Because of this possibility,
|
|
predicates or functions which are defined
|
|
using different code for different modes
|
|
are by default assumed to be impure;
|
|
the programmer must either
|
|
(1) carefully ensure that the logical meaning of the clauses
|
|
is the same for all modes,
|
|
which can be declared to the compiler
|
|
through a @samp{pragma promise_equivalent_clauses} declaration,
|
|
or a @samp{pragma promise_pure} declaration,
|
|
or (2) declare the predicate or function as impure.
|
|
@xref{Impurity}.
|
|
|
|
In the example with @samp{append} above,
|
|
the two ways of implementing append do have the same declarative semantics,
|
|
so we can safely use the first approach:
|
|
|
|
@example
|
|
:- pragma promise_equivalent_clauses(append/3).
|
|
@end example
|
|
|
|
The pragma
|
|
|
|
@example
|
|
:- pragma promise_pure(append/3).
|
|
@end example
|
|
|
|
would also promise that the clauses are equivalent,
|
|
but on top of that would also promise that the code of each clause is pure.
|
|
Sometimes, if some clauses contain impure code,
|
|
that is a promise that the programmer wants to make,
|
|
but this extra promise is unnecessary in this case.
|
|
|
|
In the example with @samp{var/1} above,
|
|
the two clauses have different semantics,
|
|
so the predicate must be declared as impure:
|
|
|
|
@example
|
|
:- impure pred var(T).
|
|
@end example
|
|
|
|
@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
|
|
(@code{free}, @code{ground}, and @code{bound(@dots{})}),
|
|
Mercury also provides ``unique'' insts
|
|
@code{unique} and @code{unique(@dots{})}
|
|
which are like @code{ground} and @code{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 @code{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 manipulating unique values:
|
|
|
|
@example
|
|
% unique output
|
|
:- mode uo == free >> unique.
|
|
|
|
% unique input
|
|
:- mode ui == unique >> unique.
|
|
|
|
% destructive input
|
|
:- mode di == unique >> dead.
|
|
@end example
|
|
|
|
Mode @code{uo} is used to create a unique value.
|
|
Mode @code{ui} is used to inspect a unique value without losing its uniqueness.
|
|
Mode @code{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 @code{unique}
|
|
if it might be needed on backtracking.
|
|
This means that unique modes are generally only useful
|
|
for code whose determinism is @code{det} or @code{cc_multi}
|
|
(@pxref{Determinism}).
|
|
|
|
Unlike @code{bound} instantiatedness trees,
|
|
there is no alternative syntax for @code{unique} instantiatedness trees.
|
|
|
|
@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 @code{mostly_unique} and @code{mostly_dead}
|
|
are equivalent to @code{unique} and @code{dead},
|
|
except that only references which will be encountered during forward execution
|
|
are counted ---
|
|
it is OK for @code{mostly_unique} or @code{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 @code{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 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.
|
|
|
|
If all possible calls to a particular mode of a predicate or function
|
|
which return to the caller
|
|
(calls which terminate,
|
|
do not throw an exception
|
|
and do not cause a fatal runtime error)
|
|
|
|
@itemize @bullet
|
|
@item
|
|
have exactly one solution,
|
|
then that mode is @dfn{deterministic} (@code{det});
|
|
|
|
@item
|
|
either have no solutions or have one solution,
|
|
then that mode is @dfn{semideterministic} (@code{semidet});
|
|
|
|
@item
|
|
have at least one solution but may have more,
|
|
then that mode is @dfn{multisolution} (@code{multi});
|
|
|
|
@item
|
|
have zero or more solutions,
|
|
then that mode is @dfn{nondeterministic} (@code{nondet});
|
|
|
|
@item
|
|
fail without producing a solution,
|
|
then that mode has a determinism of @code{failure}.
|
|
@end itemize
|
|
|
|
If no possible calls to a particular mode of a predicate or function
|
|
can return to the caller,
|
|
then that mode has a determinism of @code{erroneous}.
|
|
|
|
The determinism annotation @code{erroneous} is used on the library predicates
|
|
@samp{require.error/1} and @samp{exception.throw/1},
|
|
but apart from that,
|
|
determinism annotations @code{erroneous} and @code{failure}
|
|
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 @code{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 @code{det} or @code{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 @code{det} or @code{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};
|
|
aside from assisting in reasoning about the code,
|
|
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 throw an exception (@pxref{Exception handling}),
|
|
contain a trace goal (@pxref{Trace goals}),
|
|
or infinitely loop.
|
|
In some cases these optimizations may not be desirable;
|
|
the strict sequential semantics guarantees that they will not be performed
|
|
(@pxref{Formal semantics}).
|
|
|
|
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 @code{det}.
|
|
If you want to write a partial function,
|
|
i.e.@: one whose determinism is @code{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
|
|
@code{det}, @code{semidet}, @code{erroneous}, or @code{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 categories:
|
|
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
|
|
@group
|
|
(
|
|
L = [], empty(Out)
|
|
;
|
|
L = [H|T], nonempty(H, T, Out)
|
|
)
|
|
@end group
|
|
@end example
|
|
|
|
If @code{L} is input to the disjunction,
|
|
then the disjunction is a switch on @code{L}.
|
|
|
|
If two variables are unified with each other,
|
|
then whatever function symbol one variable is unified with,
|
|
the other variable is considered to be unified with the same function symbol.
|
|
In the following example,
|
|
since @code{K} is unified with @code{L},
|
|
the second disjunct unifies @code{L} as well as @code{K} with cons,
|
|
and thus the disjunction is recognized as a switch.
|
|
@example
|
|
@group
|
|
(
|
|
L = [], empty(Out)
|
|
;
|
|
K = L, K = [H|T], nonempty(H, T, Out)
|
|
)
|
|
@end group
|
|
@end example
|
|
|
|
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 the reachable arms of the switch can succeed at most zero times.
|
|
(A switch arm is not reachable
|
|
if it unifies the switched-on variable with a function symbol
|
|
that is ruled out by that variable's initial instantiation state.)
|
|
|
|
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
|
|
|
|
The unification of the switched-on variable with a function symbol
|
|
may occur inside a nested disjunction in a given disjunct,
|
|
provided that unification is preceded only by other unifications,
|
|
both inside the nested disjunction and before the nested disjunction.
|
|
The following example is a switch on @code{X},
|
|
provided @code{X} is bound beforehand.
|
|
|
|
@example
|
|
@group
|
|
(
|
|
X = f
|
|
p(Out)
|
|
;
|
|
Y = X,
|
|
(
|
|
Y = g,
|
|
Intermediate = 42
|
|
;
|
|
Z = Y,
|
|
Z = h(Arg),
|
|
q(Arg, Intermediate)
|
|
),
|
|
r(Intermediate, Out)
|
|
)
|
|
@end group
|
|
@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
|
|
@group
|
|
:- pred p(T, T).
|
|
:- mode p(in, out) is det.
|
|
|
|
p(A, B) :-
|
|
(
|
|
something_complicated(A, B)
|
|
;
|
|
B = A
|
|
).
|
|
@end group
|
|
@end example
|
|
|
|
@noindent
|
|
@samp{p/2} can have more than one solution
|
|
only if @samp{something_complicated/2} 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) :-
|
|
( if goal_that_should_never_fail(A, B0) then
|
|
B = B0
|
|
else
|
|
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 @code{erroneous} can never succeed,
|
|
which is why it does not require the ``else'' part
|
|
to generate a value for @code{B}.
|
|
The introduction of the new variable @code{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 one of the predicates
|
|
in the standard library module @samp{solutions},
|
|
such as @samp{solutions/2} itself,
|
|
which collects all of the solutions to a goal into a list ---
|
|
@pxref{Higher-order}.
|
|
|
|
If you just want one solution from a predicate and don't care which,
|
|
you should declare the relevant mode of the predicate
|
|
to have determinism @code{cc_nondet} or @code{cc_multi}
|
|
(depending on whether you are guaranteed at least one solution or not).
|
|
This tells the compiler that this mode of this predicate
|
|
may have more than one solution when viewed as a statement in logic,
|
|
but the implementation should stop after generating the first solution.
|
|
In other words, the implementation should @emph{commit} to the first solution.
|
|
|
|
The commit to the first solution means that
|
|
a piece of @code{cc_nondet} or @code{cc_multi} code
|
|
can never be asked to generate a second solution.
|
|
If e.g. a @code{cc_nondet} call is in a conjunction,
|
|
then no later goal in that conjunction (after mode reordering) may fail,
|
|
because that would ask the committed choice goal for a second solution.
|
|
The compiler enforces this rule.
|
|
|
|
In the declarative semantics,
|
|
which solution will be the first is unpredictable,
|
|
but in the operational semantics,
|
|
you @emph{can} predict which solution will be the first,
|
|
since Mercury does depth-first search
|
|
with left-to-right execution of clause bodies,
|
|
though that is not on the source code form of each clause body,
|
|
but on its form @emph{after} mode analysis reordering
|
|
to put the producer of each variable before all its consumers.
|
|
|
|
The @samp{committed choice nondeterminism} of a predicate
|
|
has to be propagated up the call tree,
|
|
making its callers, its callers' callers, and so on,
|
|
also @code{cc_nondet} or @code{cc_multi},
|
|
until either you get to @code{main/2} at the top of the call tree,
|
|
or you get to a location where you don't have to propagate
|
|
the committed choice context upward anymore.
|
|
|
|
While @code{main/2} is usually declared to have determinism @code{det},
|
|
it may also be declared @code{cc_multi}.
|
|
In the latter case,
|
|
while the program's declarative semantics may admit more than one solution,
|
|
the implementation will stop after the first,
|
|
so alternative solutions to @code{main/2}
|
|
(and hence also to @code{cc_nondet} or @code{cc_multi} predicates
|
|
called directly or indirectly from @samp{main/2})
|
|
are implicitly pruned away.
|
|
This is similar to the ``don't care'' nondeterminism
|
|
of committed choice logic programming languages such as GHC.
|
|
|
|
One way to stop propagating committed choice nondeterminism
|
|
is the one mentioned above: if a goal has no non-local output variables
|
|
(i.e.@ none of the goal's outputs are visible from outside the goal),
|
|
then the goal's solutions are indistinguishable from the outside,
|
|
and the implementation will only attempt to satisfy the goal once,
|
|
whether or not the goal is committed choice.
|
|
Therefore if a @code{cc_multi} goal has all its outputs ignored,
|
|
then the compiler considers it to be a @code{det} goal,
|
|
while if a @code{cc_nondet} goal has all its outputs ignored,
|
|
then the compiler considers it to be a @code{semidet} goal.
|
|
|
|
The other way to stop propagating committed choice nondeterminism is applicable
|
|
when you know that all the solutions returned will be equivalent
|
|
in all the ways that your program cares about.
|
|
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 iterate over them,
|
|
the maximum value in the set should be the same.
|
|
|
|
If this condition is satisfied,
|
|
i.e.@ if you know that there will only ever be at most one distinct solution
|
|
under your equality theory of the output variables,
|
|
then you can use a @samp{promise_equivalent_solutions} determinism cast.
|
|
If goal @samp{G} is a @code{cc_multi} goal
|
|
whose outputs are @code{X} and @code{Y}, then
|
|
@code{promise_equivalent_solutions [X, Y] ( G )}
|
|
promises the compiler that all solutions of @code{G} are equivalent,
|
|
so that regardless of which solution of @code{G}
|
|
the implementation happens to commit to,
|
|
the rest of the program will compute
|
|
either identical or (similarly) equivalent results.
|
|
This allows the compiler to consider
|
|
@code{promise_equivalent_solutions [X, Y] ( G )}
|
|
to have determinism @code{det}.
|
|
Likewise, the compiler will consider
|
|
@code{promise_equivalent_solutions [X, Y] ( G )}
|
|
where @code{G} is @code{cc_nondet} to have determinism @code{semidet}.
|
|
|
|
Note that specifying a user-defined equivalence relation
|
|
as the equality predicate for user-defined types
|
|
(@pxref{User-defined equality and comparison})
|
|
means that @samp{promise_equivalent_solutions}
|
|
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_equivalent_solutions} determinism cast
|
|
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 the 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 @code{multi} and the other @code{cc_multi},
|
|
or one being @code{nondet} and the other @code{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 @code{det} or @code{cc_multi} predicates,
|
|
not in @code{multi} predicates.
|
|
Another is for dealing with types that use non-canonical representations
|
|
(@pxref{User-defined equality and comparison}).
|
|
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{:- promise} declaration.
|
|
@c
|
|
@c Here are some examples of @samp{:- promise} declarations.
|
|
@c The following example declares the function @samp{+} to be commutative.
|
|
@c
|
|
@c @example
|
|
@c :- promise all [A, B, R]
|
|
@c (
|
|
@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 :- promise all [A, B, C, ABC]
|
|
@c (
|
|
@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 User-defined equality and comparison
|
|
@chapter User-defined equality and comparison
|
|
|
|
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 representation.
|
|
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
|
|
(not including subtypes):
|
|
|
|
@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 comparison predicate can also be supplied.
|
|
|
|
@example
|
|
:- type set(T)
|
|
---> set(list(T))
|
|
where equality is set_equals, comparison is set_compare.
|
|
|
|
:- pred set_compare(builtin.comparison_result::uo,
|
|
set(T)::in, set(T)::in) is det.
|
|
|
|
set_compare(Result, Set1, Set2) :-
|
|
promise_equivalent_solutions [Result] (
|
|
set_compare_2(Set1, Set2, Result)
|
|
).
|
|
|
|
:- pred set_compare_2(set(T)::in, set(T)::in,
|
|
builtin.comparison_result::uo) is cc_multi.
|
|
|
|
set_compare_2(set(List1), set(List2), Result) :-
|
|
builtin.compare(Result, list.sort(List1), list.sort(List2)).
|
|
@end example
|
|
|
|
If a comparison predicate is supplied
|
|
and the unification predicate is omitted,
|
|
a unification predicate is generated by the compiler
|
|
in terms of the comparison predicate.
|
|
For the @samp{set} example, the generated predicate would be:
|
|
|
|
@example
|
|
set_equals(S1, S2) :-
|
|
set_compare((=), S1, S2).
|
|
@end example
|
|
|
|
If a unification predicate is supplied without a comparison predicate,
|
|
the compiler will generate a comparison predicate
|
|
which throws an exception of type @samp{exception.software_error} when called.
|
|
|
|
A type declaration for a type @samp{foo(T1, @dots{}, TN)}
|
|
may contain a @samp{where equality is @var{equalitypred}} specification
|
|
only if it declares a discriminated union type or a foreign type
|
|
(@pxref{Using foreign types from Mercury})
|
|
and the following conditions are satisfied:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
@var{equalitypred} must be the name of a predicate with signature
|
|
@example
|
|
:- pred @var{equalitypred}(foo(T1, @dots{}, TN)::in,
|
|
foo(T1, @dots{}, TN)::in) is semidet.
|
|
@end example
|
|
|
|
It is 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 of the equality predicate
|
|
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 of the equality predicate
|
|
could be any of @code{det}, @code{failure} or @code{erroneous}).
|
|
|
|
@item
|
|
If the type is a discriminated union
|
|
then its definition cannot be a single zero-arity constructor.
|
|
|
|
@item
|
|
The equality predicate must be ``pure'' (@pxref{Impurity}).
|
|
|
|
@item
|
|
The equality predicate must be defined in the same module as the type.
|
|
|
|
@item
|
|
If the type is exported the equality predicate must also be exported.
|
|
|
|
@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{Formal semantics}),
|
|
i.e.@: the behaviour of the program is undefined.}.
|
|
|
|
@end itemize
|
|
|
|
Types with user-defined equality can only be used in limited ways.
|
|
Because there are 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 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 @code{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{deconstruct})
|
|
that do not have determinism @code{cc_multi} or @code{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}(@var{X}, @var{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}.
|
|
|
|
@end itemize
|
|
|
|
A type declaration for a type @samp{foo(T1, @dots{}, TN)}
|
|
may contain a @samp{where comparison is @var{comparepred}} specification
|
|
only if it declares a discriminated union type or a foreign type
|
|
(@pxref{Using foreign types from Mercury}) and the
|
|
following conditions are satisfied:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
@var{comparepred} must be the name of a predicate with signature
|
|
@example
|
|
:- pred @var{comparepred}(builtin.comparison_result::uo,
|
|
foo(T1, @dots{}, TN)::in, foo(T1, @dots{}, TN)::in) is det.
|
|
@end example
|
|
|
|
As with equality predicates,
|
|
it is legal for the type, mode and determinism to be more permissive.
|
|
|
|
@item
|
|
If the type is a discriminated union
|
|
then its definition cannot be a single zero-arity constructor.
|
|
|
|
@item
|
|
The comparison predicate must also be ``pure'' (@pxref{Impurity}).
|
|
|
|
@item
|
|
The comparison predicate must be defined in the same module as the type.
|
|
|
|
@item
|
|
If the type is exported the comparison predicate must also be exported.
|
|
|
|
@item
|
|
The relation
|
|
@example
|
|
compare_eq(X, Y) :- @var{comparepred}((=), X, Y).
|
|
@end example
|
|
must be an equivalence relation;
|
|
that is, it must be symmetric, reflexive, and transitive.
|
|
The compiler is not required to check this.
|
|
|
|
@item
|
|
The relations
|
|
@example
|
|
compare_leq(X, Y) :- @var{comparepred}(R, X, Y), (R = (=) ; R = (<)).
|
|
compare_geq(X, Y) :- @var{comparepred}(R, X, Y), (R = (=) ; R = (>)).
|
|
@end example
|
|
must be total order relations:
|
|
that is they must be antisymmetric, reflexive and transitive.
|
|
The compiler is not required to check this.
|
|
|
|
@end itemize
|
|
|
|
For each type for which the declaration has a
|
|
@samp{where comparison is @var{comparepred}} specification,
|
|
any calls to the standard library predicate @samp{builtin.compare/3}
|
|
with arguments of that type are evaluated
|
|
as if they were calls to @var{comparepred}.
|
|
|
|
A type declaration may contain a
|
|
@samp{where equality is @var{equalitypred}, comparison is @var{comparepred}}
|
|
specification only if in addition to the conditions above,
|
|
@samp{all [X, Y] (@var{comparepred}((=), X, Y) <=> @var{equalitypred}(X, Y))}.
|
|
The compiler is not required to check this.
|
|
|
|
@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.
|
|
This is because 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::
|
|
* Comparing higher-order terms::
|
|
* Higher-order insts and 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 unifications have the same effect:
|
|
|
|
@example
|
|
X = (pred(List::in, Length::out) is det :- sum(List, Length))
|
|
Y = sum
|
|
@end example
|
|
|
|
In the above example,
|
|
the type of @code{X}, and @code{Y} is @samp{pred(list(int), int)},
|
|
which means a predicate of two arguments
|
|
of types @code{list(int)} and @code{int} respectively.
|
|
|
|
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
|
|
@group
|
|
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 group
|
|
@end example
|
|
|
|
In the above example,
|
|
the type of @code{X}, @code{Y}, and @code{Z} is
|
|
@samp{func(int, list(int)) = list(int)},
|
|
which means a function of two arguments,
|
|
whose types are @code{int} and @code{list(int)},
|
|
with a return type of @code{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 @code{in} for the arguments,
|
|
@code{out} for the function result,
|
|
and the determinism defaults to @code{det}.
|
|
|
|
The Melbourne Mercury implementation currently requires
|
|
that you use an explicit lambda expression to specify which mode you want,
|
|
if the predicate or function has more than one mode
|
|
(but see below for an exception to this rule).
|
|
|
|
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 @code{Sum123} to a higher-order predicate term of type @samp{pred(int)}.
|
|
Similarly, the unification
|
|
|
|
@example
|
|
Double = scalar_product(2)
|
|
@end example
|
|
|
|
@noindent
|
|
binds @code{Double} to a higher-order function term of type
|
|
@samp{func(list(int)) = list(int)}.
|
|
|
|
As a special case, currying of a multi-moded predicate or function is allowed
|
|
provided that the mode of the predicate or function
|
|
can be determined from the insts of the higher-order curried arguments.
|
|
For example, @samp{P = list.foldl(io.write)} is allowed
|
|
because the inst of @samp{io.write} matches
|
|
exactly one mode of @samp{list.foldl}.
|
|
|
|
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(\=(2), [1, 2, 3], List)
|
|
@end example
|
|
|
|
@noindent
|
|
you must write either
|
|
|
|
@example
|
|
list.filter((pred(X::in) is semidet :- X \= 2), [1, 2, 3], List)
|
|
@end example
|
|
|
|
@noindent
|
|
or
|
|
|
|
@example
|
|
list.filter(not_equal(2), [1, 2, 3], 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 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 @code{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 @code{List} to @samp{[2, 4, 6]}.
|
|
|
|
One useful higher-order predicate in the Mercury standard library
|
|
is @samp{solutions/2}, which has the following declaration:
|
|
|
|
@example
|
|
:- pred solutions(pred(T), list(T)).
|
|
:- mode solutions(in(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 without any duplicates.
|
|
@end example
|
|
|
|
@noindent
|
|
where @samp{call(Pred, X)}
|
|
invokes the higher-order predicate term @code{Pred} with argument @code{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 @code{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 is 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{solutions}
|
|
and documented in the Mercury Library Reference Manual.
|
|
|
|
@node Comparing higher-order terms
|
|
@section Comparing higher-order terms
|
|
|
|
In Mercury, it is an error
|
|
to attempt to unify or to compare two higher-order terms.
|
|
This is because the question of whether two higher-order terms are equivalent
|
|
is undecidable in the general case.
|
|
|
|
Note that the compiler will catch only
|
|
@emph{direct} attempts at unifications or comparisons of higher-order terms.
|
|
Indirect attempts,
|
|
using for example polymorphic predicates
|
|
such as @samp{(list.append([], [P], [Q])},
|
|
will result in an error at run-time rather than at compile-time.
|
|
|
|
@node Higher-order insts and modes
|
|
@section Higher-order insts and modes
|
|
|
|
In Mercury, the mode and determinism
|
|
of a higher-order predicate or function term
|
|
are generally part of that term's @emph{inst}, not its @emph{type}.
|
|
This allows a single higher-order predicate to work
|
|
on argument predicates that differ in their modes and in their determinisms,
|
|
which is particularly useful for library predicates
|
|
such as @samp{list.map} and @samp{list.foldl}.
|
|
|
|
Consider @samp{list.foldl}, one of the standard fold predicates on lists.
|
|
The types of its arguments are given by this predicate declaration:
|
|
@example
|
|
:- pred foldl(pred(L, A, A), list(L), A, A).
|
|
@end example
|
|
|
|
The first argument is a higher order value (a predicate in this case),
|
|
whose types are the types bound by the caller
|
|
to the type variables @var{L}, @var{A} and @var{A} respectively,
|
|
where @var{L} is the type of the elements in the list in the second argument,
|
|
and @var{A} is the type of the accumulator
|
|
whose initial and final values are the third and fourth arguments.
|
|
The job of the predicate passed in the first argument
|
|
is to combine each element in the list
|
|
with the current value of the accumulator
|
|
to generate the next value of the accumulator,
|
|
so in most calls to @samp{list.foldl},
|
|
the argument modes and the determinism of that predicate will be
|
|
@example
|
|
pred(in, in, out) is det
|
|
@end example
|
|
|
|
@noindent
|
|
This is a @emph{higher order inst}:
|
|
an inst describing the modes of the arguments and the determinism
|
|
of a higher order value, which in this case is a predicate.
|
|
A @emph{higher order mode} is a mode in which
|
|
the initial and/or final inst is a higher order inst.
|
|
These @emph{can} be written like this:
|
|
|
|
@example
|
|
pred(in, in, out) is det >> pred(in, in, out) is det
|
|
@end example
|
|
|
|
@noindent
|
|
for a predicate being passed to another predicate or function,
|
|
and like this
|
|
|
|
@example
|
|
free >> pred(in, in, out) is det
|
|
@end example
|
|
|
|
@noindent
|
|
for a predicate being returned from another predicate or function.
|
|
In practice, it is far more convenient
|
|
to use the builtin mode constructors @samp{in/1} and @samp{out/1} to write
|
|
|
|
@example
|
|
in(pred(in, in, out) is det)
|
|
out(pred(in, in, out) is det)
|
|
@end example
|
|
|
|
@noindent
|
|
which are each equivalent to the corresponding example just above.
|
|
|
|
You can use higher order insts and modes in mode declarations like this:
|
|
|
|
@example
|
|
:- mode foldl(in(pred(in, in, out) is det), in, in, out) is det.
|
|
@end example
|
|
|
|
@noindent
|
|
The @samp{in()} wrapper around the higher order inst here
|
|
declares the first argument of @samp{list.foldl} to be an input,
|
|
but the higher order inst inside the wrapper goes further,
|
|
by specifying the argument modes and the determinism
|
|
of the predicate that @samp{list.foldl} takes @emph{in this mode}.
|
|
|
|
That last qualification is important,
|
|
because @samp{list.foldl} has several modes,
|
|
each differing in the argument modes, in the determinism, or both.
|
|
The set of mode declarations for @samp{list.foldl} includes
|
|
|
|
@c This list is a good argument for (possibly constrained) mode variables
|
|
@c and determinism variables, which would allow all of the modes above
|
|
@c to declared with just
|
|
@c :- mode foldl(pred(in, InMode, OutMode) is Det, in, InMode, OutMode) is Det.
|
|
@example
|
|
:- mode foldl(in(pred(in, in, out) is det), in, in, out) is det.
|
|
:- mode foldl(in(pred(in, di, uo) is det), in, di, uo) is det.
|
|
:- mode foldl(in(pred(in, in, out) is semidet), in, in, out) is semidet.
|
|
:- mode foldl(in(pred(in, in, out) is cc_multi), in, in, out) is cc_multi.
|
|
:- mode foldl(in(pred(in, di, uo) is cc_multi), in, di, uo) is cc_multi.
|
|
@end example
|
|
|
|
@c These are the modes (as of 25 July 2023) that we are not showing.
|
|
@c :- mode foldl(in(pred(in, di, uo) is semidet), in, di, uo) is semidet.
|
|
@c :- mode foldl(in(pred(in, mdi, muo) is det), in, mdi, muo) is det.
|
|
@c :- mode foldl(in(pred(in, mdi, muo) is semidet), in, mdi, muo) is semidet.
|
|
@c :- mode foldl(in(pred(in, mdi, muo) is nondet), in, mdi, muo) is nondet.
|
|
@c :- mode foldl(in(pred(in, in, out) is multi), in, in, out) is multi.
|
|
@c :- mode foldl(in(pred(in, in, out) is nondet), in, in, out) is nondet.
|
|
|
|
@noindent
|
|
That means you can pass predicates
|
|
with several different argument mode/determinism combinations
|
|
as the first argument.
|
|
In the case of @samp{list.foldl},
|
|
the modes of the accumulator arguments
|
|
and the determinism of the whole predicate will follow
|
|
the argument modes and the determinism of the higher-order argument,
|
|
but one can create predicates (and functions) where this would not be true.
|
|
@c An example of that may be nice, but putting it here
|
|
@c would probably be more confusing than helpful.
|
|
|
|
You can give names to such insts and modes
|
|
using declarations such as
|
|
|
|
@example
|
|
:- inst std_fold_pred == (pred(in, in, out) is det).
|
|
:- mode std_fold_pred_in == in(pred(in, in, out) is det).
|
|
@end example
|
|
|
|
@noindent
|
|
Note that the parentheses around the right hand side of the inst declaration
|
|
are required, due to the relative precedences
|
|
of the @samp{==} and @samp{is} operators.
|
|
|
|
Given these definitions, the declarations
|
|
|
|
@example
|
|
:- mode foldl(in(std_fold_pred), in, in, out) is det.
|
|
:- mode foldl(std_fold_pred_in, in, in, out) is det.
|
|
@end example
|
|
|
|
@noindent
|
|
are both equivalent to
|
|
|
|
@example
|
|
:- mode foldl(in(pred(in, in, out) is det), in, in, out) is det.
|
|
@end example
|
|
|
|
@noindent
|
|
but they may be more convenient to write,
|
|
especially in the presence of more arguments.
|
|
@footnote{If all instances of a given type are expected to use
|
|
a single inst or a single mode,
|
|
there is a convention where programmers will give that inst or mode
|
|
the same name as the type.
|
|
This works because types, insts and modes belong to separate namespaces,
|
|
so the names do not conflict.
|
|
Nonetheless, there is usually no need to define a named mode.
|
|
It is clearer to write a mode using @samp{in()} or @samp{out()}
|
|
around a named inst.}
|
|
|
|
The general form of higher order insts follows one of two patterns,
|
|
one for predicates, and one for functions.
|
|
|
|
The pattern for predicates is
|
|
|
|
@example
|
|
(pred) is @var{Determinism}
|
|
pred(@var{Mode}) is @var{Determinism}
|
|
pred(@var{Mode1}, @var{Mode2}) is @var{Determinism}
|
|
@dots{}
|
|
@end example
|
|
|
|
while the pattern for functions is
|
|
|
|
@example
|
|
(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
|
|
|
|
In the case of zero-argument predicates and functions,
|
|
the parentheses around @samp{pred} and @samp{func}
|
|
are required to tell the compiler that these words
|
|
are not being used as operators in this case.
|
|
And, as explained above, one will usually need parentheses
|
|
around any instances of these patterns in Mercury code.
|
|
|
|
@c ZZZ Note that nontrivial examples for functions
|
|
@c are much harder to find than for predicates, because
|
|
@c - any functions with the default arg modes and determinism need no decl
|
|
@c - we don't want to encourage people to write functions which are not det
|
|
@c - we don't want to encourage people to write functions whose args
|
|
@c have uniqueness requirements
|
|
@c This leaves functions whose arg modes restrict the allowed function symbols
|
|
@c (which would be better expressed using subtypes) and functions whose arg
|
|
@c modes include higher order insts/modes, which would be too complex to
|
|
@c be useful as an example to novices.
|
|
|
|
As a convenience,
|
|
the language allows you to write a higher order @emph{mode}
|
|
using the same syntax as a higher order @emph{inst}.
|
|
If @var{HOInst} has the form of a higher order inst,
|
|
then writing @var{HOInst} where a mode is required
|
|
is the same as writing @samp{in(HOInst)},
|
|
which is in turn equivalent to @samp{HOInst >> HOInst}.
|
|
Therefore,
|
|
you can omit @samp{in()} around the higher order inst of an input argument.
|
|
For example,
|
|
|
|
@example
|
|
:- mode foldl(in(pred(in, in, out) is det), in, in, out) is det.
|
|
@end example
|
|
|
|
@noindent
|
|
can also be written as
|
|
|
|
@example
|
|
:- mode foldl(pred(in, in, out) is det, in, in, out) is det.
|
|
@end example
|
|
|
|
@noindent
|
|
though the former may be easier to understand.
|
|
|
|
As usual,
|
|
if a predicate or function has only one mode,
|
|
the @samp{pred} or @samp{func} declaration
|
|
can be combined with the @samp{mode} declaration.
|
|
Consider the declaration of a function
|
|
that computes the intersection of two maps from keys to values:
|
|
|
|
@example
|
|
:- func intersect(func(V, V) = V, map(K, V), map(K, V)) = map(K, V).
|
|
@end example
|
|
|
|
@noindent
|
|
One could declare the mode of this function
|
|
either using a separate mode declaration, like this:
|
|
|
|
@example
|
|
:- mode intersect(in(func(in, in) = out is det), in, in) = (out) is det.
|
|
@end example
|
|
|
|
@noindent
|
|
or by combining the mode declaration with the function declaration, like this:
|
|
|
|
@example
|
|
:- func intersect((func(V, V) = V)::in(func(in, in) = out is det),
|
|
map(K, V)::in, map(K, V)::in) = (map(K, V)::out) is det.
|
|
@end example
|
|
|
|
@noindent
|
|
In both cases, just as for the predicate examples above,
|
|
the @samp{in()} wrapper around the higher order inst is optional,
|
|
though in the combined declaration the parentheses must stay.
|
|
|
|
Mercury also provides builtin @samp{inst} values for use with solver types.
|
|
These follow the patterns
|
|
|
|
@example
|
|
any_pred is @var{Determinism}
|
|
any_pred(@var{Mode}) is @var{Determinism}
|
|
any_pred(@var{Mode1}, @var{Mode2}) is @var{Determinism}
|
|
@dots{}
|
|
any_func = @var{Mode} is @var{Determinism}
|
|
any_func(@var{Mode1}) = @var{Mode} is @var{Determinism}
|
|
any_func(@var{Mode1}, @var{Mode2}) = @var{Mode} is @var{Determinism}
|
|
@dots{}
|
|
@end example
|
|
|
|
See @ref{Solver types} for more details.
|
|
|
|
@c ZZZ What follows is the remains of the original text of the initial part
|
|
@c of section 8. It should be deleted when the discussion of the commit
|
|
@c that created this commit on 24/25 july 2023 has finished.
|
|
@c
|
|
@c The language contains builtin @samp{inst} values
|
|
@c
|
|
@c @example
|
|
@c (pred) is @var{Determinism}
|
|
@c pred(@var{Mode}) is @var{Determinism}
|
|
@c pred(@var{Mode1}, @var{Mode2}) is @var{Determinism}
|
|
@c @dots{}
|
|
@c (func) = @var{Mode} is @var{Determinism}
|
|
@c func(@var{Mode1}) = @var{Mode} is @var{Determinism}
|
|
@c func(@var{Mode1}, @var{Mode2}) = @var{Mode} is @var{Determinism}
|
|
@c @dots{}
|
|
@c @end example
|
|
@c
|
|
@c These insts represent the instantiation state
|
|
@c of variables bound to higher-order predicate and function terms
|
|
@c with the appropriate mode and determinism.
|
|
@c For example, @samp{pred(out) is det} represents the instantiation state
|
|
@c of being bound to a higher-order predicate term which is @code{det}
|
|
@c and accepts one output argument;
|
|
@c the term @samp{sum([1,2,3])} from the example above
|
|
@c is one such higher-order predicate term
|
|
@c which matches this instantiation state.
|
|
@c
|
|
@c As a convenience, the language also contains
|
|
@c builtin @samp{mode} values of the same name
|
|
@c (and they are what we have been using in the examples up to now).
|
|
@c These modes map from the corresponding @samp{inst} to itself.
|
|
@c It is as if they were defined by
|
|
@c
|
|
@c @example
|
|
@c :- mode (pred is @var{Determinism}) == in(pred is @var{Determinism}).
|
|
@c :- mode (pred(@var{Inst}) is @var{Determinism}) ==
|
|
@c in(pred(@var{Inst}) is @var{Determinism}).
|
|
@c @dots{}
|
|
@c @end example
|
|
@c
|
|
@c @noindent
|
|
@c using the parametric mode @samp{in/1} mentioned in @ref{Modes}
|
|
@c which specified its argument inst
|
|
@c as both the initial and the final instantiation state in the mode.
|
|
@c
|
|
@c @c @node Builtin higher-order insts and modes
|
|
@c @c @subsection Builtin higher-order insts and modes
|
|
@c
|
|
@c If you want to define a predicate
|
|
@c which returns a higher-order predicate term,
|
|
@c you would use a mode such as @samp{free >> pred(@dots{}) is @dots{}},
|
|
@c or @samp{out(pred(@dots{}) is @dots{} )}.
|
|
@c @c XXX The space after the dots{} above works around a bug in texi2html.
|
|
@c For example:
|
|
@c
|
|
@c @example
|
|
@c :- pred foo(pred(int)).
|
|
@c :- mode foo(free >> (pred(out) is det)) is det.
|
|
@c
|
|
@c foo(sum([1,2,3])).
|
|
@c @end example
|
|
@c
|
|
@c In the above mode declaration, the current Mercury implementation
|
|
@c requires parentheses around the higher-order inst.
|
|
@c (This is because the operator @samp{>>} binds more tightly than the operator
|
|
@c @samp{is}.)
|
|
@c
|
|
@c For example, given the definition of @samp{foo} above, the goal
|
|
@c
|
|
@c @example
|
|
@c foo((pred(X::out) is det :- X = 6))
|
|
@c @end example
|
|
@c
|
|
@c @noindent
|
|
@c is illegal.
|
|
@c If you really want to compare higher-order predicates for equivalence,
|
|
@c you must program it yourself;
|
|
@c for example, the above goal could legally be written as
|
|
@c
|
|
@c @example
|
|
@c P = (pred(X::out) is det :- X = 6),
|
|
@c foo(Q),
|
|
@c all [X] (call(P, X) <=> call(Q, X)).
|
|
@c @end example
|
|
|
|
@c Delete first menu item, move menu to just before old second item's heading
|
|
@c * Builtin higher-order insts and modes::
|
|
@menu
|
|
* Default insts for functions::
|
|
* Combined higher-order types and insts::
|
|
@end menu
|
|
|
|
@node Default insts for functions
|
|
@subsection Default insts for functions
|
|
|
|
In order to call a higher-order term,
|
|
the compiler must know its higher-order inst.
|
|
This can cause problems when
|
|
higher-order terms are placed into a polymorphic collection type
|
|
and then extracted,
|
|
since the declared mode for the extraction will typically be @code{out}
|
|
and the higher-order inst information will be lost.
|
|
To partially alleviate this problem,
|
|
and to make higher-order functional programming easier,
|
|
if the term to be called has a function type,
|
|
but no higher-order inst information is explicitly provided,
|
|
we assume that it has the default higher-order function inst
|
|
@samp{func(in, @dots{}, in) = out is det}.
|
|
|
|
As a consequence of this,
|
|
a higher-order function term can @emph{only} be passed
|
|
where a term with no higher-order inst information is expected
|
|
if it can be passed
|
|
where a term with the default higher-order function inst is expected.
|
|
Higher-order predicate terms can always be passed to such a place,
|
|
but there is little value in doing so,
|
|
because there is no default higher-order inst for predicates,
|
|
and therefore it will not be possible to call those terms.
|
|
|
|
@node Combined higher-order types and insts
|
|
@subsection Combined higher-order types and insts
|
|
|
|
A higher-order type may optionally specify an inst in the following manner:
|
|
|
|
@example
|
|
(pred) is @var{Determinism}
|
|
pred(@var{Type}::@var{Mode}) is @var{Determinism}
|
|
pred(@var{Type1}::@var{Mode1}, @var{Type2}::@var{Mode2}) is @var{Determinism}
|
|
@dots{}
|
|
(func) = (@var{Type}::@var{Mode}) is @var{Determinism}
|
|
func(@var{Type1}::@var{Mode1}) = (@var{Type}::@var{Mode}) is @var{Determinism}
|
|
func(@var{Type1}::@var{Mode1}, @var{Type2}::@var{Mode2}) = (@var{Type}::@var{Mode}) is @var{Determinism}
|
|
@dots{}
|
|
@end example
|
|
|
|
When used as argument types of functors in type declarations,
|
|
types of this form have two effects.
|
|
First, for any unification that constructs a term using such an argument,
|
|
there is an additional mode constraint that
|
|
the argument must be approximated by the inst.
|
|
In other words, to be mode correct, a program must not construct any term
|
|
where a functor has an argument that does not have the declared inst,
|
|
if one is present.
|
|
|
|
The second effect is that when a unification deconstructs a ground term
|
|
to extract an argument with such a declared inst,
|
|
the extracted argument may then be used as if it had that inst.
|
|
|
|
For example, given this type declaration:
|
|
|
|
@example
|
|
:- type job
|
|
---> job(pred(int::out, io::di, io::uo) is det).
|
|
@end example
|
|
|
|
the following goal is correct:
|
|
|
|
@example
|
|
:- pred run(job::in, io::di, io::uo) is det.
|
|
run(Job, !IO) :-
|
|
Job = job(Pred),
|
|
Pred(Result, !IO), % Pred has the necessary inst
|
|
write_line(Result, !IO).
|
|
@end example
|
|
|
|
However, the following would be a mode error:
|
|
|
|
@example
|
|
:- pred bad(job::out) is det.
|
|
bad(job(p)). % Error: p does not have required mode
|
|
|
|
:- pred p(int::in, io::di, io::out) is det.
|
|
@dots{}
|
|
@end example
|
|
|
|
As a new feature, combined higher-order types and insts are only permitted
|
|
as direct arguments of functors in discriminated unions.
|
|
So the following examples currently result in errors.
|
|
|
|
@example
|
|
% Error: use on the RHS of equivalence types.
|
|
:- type p == (pred(io::di, io::uo) is det).
|
|
:- type f == (func(int::in) = (int::out) is semidet).
|
|
|
|
% Error: use inside a type constructor.
|
|
:- type jobs
|
|
---> jobs(list(pred(int::out, io::di, io::uo) is det)).
|
|
|
|
% Error: use in a pred/func declaration.
|
|
:- pred p((pred(io::di, io::uo) is det)::in, io::di, io::uo) is det.
|
|
:- func f(func(int::in) = (int::out) is semidet, int) = int.
|
|
@end example
|
|
|
|
Future versions of the language may allow these forms.
|
|
|
|
@node Modules
|
|
@chapter Modules
|
|
|
|
@menu
|
|
* The module system::
|
|
* An example module::
|
|
* Submodules::
|
|
* Module initialisation::
|
|
* Module finalisation::
|
|
* Module-local mutable variables::
|
|
@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 submodules, if any) and cannot be used by other modules.
|
|
The implementation section must contain definitions
|
|
for all abstract data types, abstract instance declarations,
|
|
functions, predicates, and submodules exported by the module,
|
|
as well as for all local types, type class instances, functions,
|
|
predicates, and submodules.
|
|
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
|
|
|
|
In order to constrain which entity a name refers to,
|
|
functor terms representing
|
|
predicates, functions, expressions, constructor fields,
|
|
types, modes, insts, type classes, instances and sub-modules
|
|
can be explicitly module qualified using the @samp{.} operator,
|
|
e.g.@: @samp{module.name} or @samp{module.name(Args)}.
|
|
Operator terms
|
|
(that is, functor terms written using operator syntax)
|
|
may also be module qualified,
|
|
though this requires putting parentheses
|
|
around the operator and its arguments,
|
|
e.g.@: @samp{module.(A + B)}.
|
|
The module name used in a module qualified term
|
|
may itself be module qualified if it is a sub-module,
|
|
e.g.@: @samp{module.submodule.name(Args)}.
|
|
A functor is @dfn{fully qualified}
|
|
if every name that is not a builtin or top-level module
|
|
is module qualified.
|
|
|
|
Currently we also support @samp{__} as an alternative module qualifier,
|
|
so you can write @code{module__name} instead of @code{module.name}.
|
|
|
|
The principal functor of a module qualified term
|
|
combines the name and qualifiers with the arity.
|
|
For example,
|
|
the principal functor of @samp{foo.bar.baz(Xs)} is @samp{foo.bar.baz/1},
|
|
and the principal functor of @samp{quux.(A + B)} is @samp{quux.'+'/2}.
|
|
|
|
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 @w{@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.
|
|
|
|
You may need to module qualify a name if that name has
|
|
several applicable definitions,
|
|
and the context of its occurrence does not resolve this ambiguity.
|
|
Module qualifiers are also useful for readability.
|
|
Uses of entities imported using @code{use_module} declarations
|
|
@emph{must} be fully qualified.
|
|
|
|
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.
|
|
|
|
Exactly one module of the program
|
|
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 over 100 modules,
|
|
including 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 a list of the available modules,
|
|
and for the documentation of each module.
|
|
|
|
@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).
|
|
|
|
% Define 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 Submodules
|
|
@section Submodules
|
|
|
|
As mentioned above, modules may contain submodules.
|
|
There are two kinds of submodules,
|
|
called nested submodules and separate submodules;
|
|
the difference is that nested submodules
|
|
are defined in the same source file as the containing module,
|
|
whereas separate submodules are defined in separate source files.
|
|
Implementations should support separate compilation of separate submodules.
|
|
|
|
A module may not contain more than one submodule with the same name.
|
|
|
|
@menu
|
|
* Nested submodules::
|
|
* Separate submodules::
|
|
* Visibility rules::
|
|
* Implementation bugs and limitations::
|
|
@end menu
|
|
|
|
@node Nested submodules
|
|
@subsection Nested submodules
|
|
|
|
Nested submodules within a module are delimited by
|
|
matching @samp{:- module} and @samp{:- end_module} declarations.
|
|
(Note that @samp{:- end_module} for nested submodules
|
|
are mandatory, not optional,
|
|
even if the nested submodule is the last thing in the source file.
|
|
The module name in a @samp{:- module} or @samp{:- end_module}
|
|
declaration for a nested submodule need not be fully qualified.)
|
|
The sequence of items thus delimited is known as a submodule item sequence.
|
|
|
|
The interface and implementation parts of a nested submodule
|
|
may be specified in two different submodule declarations.
|
|
If a submodule item sequence includes an interface section,
|
|
then it is a declaration of that submodule;
|
|
if it includes an implementation section,
|
|
then it is a definition of that submodule;
|
|
and if includes both, then it is both declaration and definition.
|
|
|
|
It is an error to declare a submodule twice, or to define it twice.
|
|
It is an error to define a submodule without declaring it.
|
|
As mentioned earlier, it is an error
|
|
to define a submodule in the interface section of its parent module.
|
|
|
|
If a submodule is declared but not explicitly defined,
|
|
then there is an implicit definition
|
|
with an empty implementation section for that submodule.
|
|
This empty implementation section will result in an error
|
|
if the interface section of a submodule contains any of the following:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
a declaration for a function or a predicate;
|
|
@item
|
|
an abstract declaration for a type, inst, mode or typeclass,
|
|
i.e.@ a declaration that does not itself serve as a definition
|
|
of that type, inst, mode or typeclass;
|
|
@item
|
|
an abstract declaration of a typeclass instance; or
|
|
@item
|
|
a (doubly, triply, etc) nested submodule
|
|
(which perforce has only an interface section, and no implementation section)
|
|
and which contains any of the above.
|
|
@end itemize
|
|
|
|
@node Separate submodules
|
|
@subsection Separate submodules
|
|
|
|
Separate submodules are declared using
|
|
@samp{:- include_module @var{Modules}} declarations.
|
|
Each @samp{:- include_module} declaration specifies
|
|
a comma-separated list of submodules.
|
|
|
|
@example
|
|
:- include_module @var{Module1}, @var{Module2}, @dots{}, @var{ModuleN}.
|
|
@end example
|
|
|
|
The module names need not be fully qualified.
|
|
|
|
Each of the named submodules 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.
|
|
The Melbourne Mercury implementation requires that
|
|
@itemize
|
|
@item @emph{either} every module must be in a file
|
|
whose name is the fully qualified module name followed by @samp{.m},
|
|
(so a module named e.g.@: @samp{foo.bar.baz},
|
|
must be in a file named @file{foo.bar.baz.m})
|
|
@item @emph{or} that the programmer tell the implementation
|
|
about which files contain which modules
|
|
using a command such as @samp{mmc -f *.m}.
|
|
(Alternatively, you could replace the @samp{*.m} in that command
|
|
with a list of the file names of all the Mercury modules in the program.)
|
|
@end itemize
|
|
|
|
The source file of a separate submodule must contain
|
|
the declaration (interface) and definition (implementation) of the submodule.
|
|
It must start with a @samp{:- module} declaration
|
|
containing the fully qualified module name,
|
|
followed by the interface and (if necessary) implementation sections,
|
|
and it may optionally end with a @samp{:- end_module} declaration.
|
|
(The module name in the @samp{:- end_module} declaration need not be
|
|
fully qualified.)
|
|
|
|
The semantics of separate submodules
|
|
are identical to those of nested submodules.
|
|
The procedure to transform a separate submodule
|
|
into a nested submodule is as follows:
|
|
|
|
@enumerate
|
|
@item
|
|
Replace the @samp{:- include_module @var{submodule}} declaration
|
|
with the interface section of the submodule
|
|
enclosed within @samp{:- module @var{submodule}}
|
|
and @samp{:- end_module @var{submodule}} declarations.
|
|
@item
|
|
Place the implementation section of the submodule
|
|
enclosed within @samp{:- module @var{submodule}}
|
|
and @samp{:- end_module @var{submodule}} declarations
|
|
in the implementation section of the parent module.
|
|
@end enumerate
|
|
|
|
For example
|
|
|
|
@example
|
|
:- module x.
|
|
:- interface.
|
|
:- include_module y.
|
|
:- end_module x.
|
|
@end example
|
|
|
|
@noindent
|
|
is equivalent to
|
|
|
|
@example
|
|
:- module x.
|
|
:- interface.
|
|
:- module y.
|
|
% interface section of module @samp{y}
|
|
:- end_module y.
|
|
:- implementation.
|
|
:- module y.
|
|
% implementation section of module @samp{y}
|
|
:- end_module y.
|
|
:- end_module x.
|
|
@end example
|
|
|
|
@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 submodules,
|
|
including indirect submodules (i.e.@: sub-submodules, 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 submodules, including indirect submodules.
|
|
|
|
Declarations in a child module are not visible in the parent module,
|
|
or in ``sibling'' modules (other children of the same parent),
|
|
or in other unrelated modules
|
|
unless the child is explicitly imported using
|
|
an @samp{:- import_module} or @samp{:- use_module} declaration.
|
|
It is an error to import a module without importing all of its parent modules.
|
|
|
|
Note that a submodule for which
|
|
the @samp{:- module} or @samp{:- include_module} declaration
|
|
occurs only in the implementation section of the parent module
|
|
may only be imported or used by its parent module
|
|
or by submodules of its parent module.
|
|
|
|
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 submodules has a couple of minor limitations.
|
|
|
|
@itemize @bullet
|
|
@item
|
|
The compiler sometimes reports spurious errors
|
|
if you define an equivalence type in a submodule
|
|
and export it as an abstract type.
|
|
@item
|
|
Using @samp{mmake} to do parallel makes (e.g.@: @samp{mmake --jobs 2})
|
|
does not always work correctly if you are using nested submodules.
|
|
(The work-around is to use separate submodules instead of nested submodules,
|
|
i.e.@: to put the submodules in separate source files.)
|
|
@end itemize
|
|
|
|
@node Module initialisation
|
|
@section Module initialisation
|
|
|
|
Modules that interact with foreign libraries or services
|
|
may require special initialisation before use.
|
|
Such modules may include any number of @samp{initialise} directives
|
|
in their implementation sections.
|
|
An @samp{initialise} directive has the following form:
|
|
|
|
@example
|
|
:- initialise @var{initpredname}/@var{arity}.
|
|
@end example
|
|
|
|
where the predicate @var{initpredname} must be declared
|
|
with one of the following signatures:
|
|
|
|
@example
|
|
:- pred @var{initpredname}(io::di, io::uo) is @var{Det}.
|
|
:- impure pred @var{initpredname} is @var{Det}.
|
|
@end example
|
|
|
|
@var{Det} must be either @code{det} or @code{cc_multi}.
|
|
|
|
The effect of the @samp{initialise} declaration
|
|
is to ensure that @samp{@var{initpredname}/@var{arity}} is invoked
|
|
before the program's @samp{main/2} predicate.
|
|
Initialisation predicates within a module are executed
|
|
in the order in which they are specified,
|
|
although no order may be assumed between different modules or submodules.
|
|
Initialisation predicates are only invoked
|
|
after any initialisation required by the Mercury standard library.
|
|
|
|
If @samp{@var{initpredname}/@var{arity}} terminates with an uncaught exception
|
|
then the program will immediately abort execution.
|
|
In this circumstance, those predicates specified by other @samp{initialise}
|
|
directives that have not yet been executed will not be executed,
|
|
@samp{main/2} will not be executed,
|
|
and no predicate specified in a @samp{finalise} directive will be executed.
|
|
|
|
@samp{initialize} is also allowed as a synonym for @samp{initialise}.
|
|
|
|
@node Module finalisation
|
|
@section Module finalisation
|
|
|
|
Modules that require special finalisation at program termination
|
|
may include any number of @samp{finalise} directives
|
|
in their implementation sections.
|
|
|
|
A @samp{finalise} directive has the following form:
|
|
|
|
@example
|
|
:- finalise @var{finalpredname}/@var{arity}.
|
|
@end example
|
|
|
|
where the predicate @samp{finalpredname/arity} must be declared
|
|
with one of the following signatures:
|
|
|
|
@example
|
|
:- pred @var{finalpredname}(io::di, io::uo) is @var{Det}.
|
|
:- impure pred @var{finalpredname} is @var{Det}
|
|
@end example
|
|
|
|
@var{Det} must be either @code{det} or @code{cc_multi}.
|
|
|
|
The effect of the @samp{finalise} declaration
|
|
is to ensure that @samp{@var{finalpredname}/@var{arity}} is invoked
|
|
after the program's @samp{main} predicate.
|
|
Finalisation predicates within a module
|
|
are executed in the order in which they are specified,
|
|
although no order may be assumed between different modules or submodules.
|
|
Any finalisation required by the Mercury standard library
|
|
will always occur after any finalisation predicates have been invoked.
|
|
|
|
If @samp{@var{finalpredname}/@var{arity}}
|
|
terminates with an uncaught exception,
|
|
then the program will immediately abort execution.
|
|
No predicates specified by other @samp{finalise} directives
|
|
that have not yet been executed will be executed.
|
|
If the program's @samp{main/2} predicate terminates with an uncaught exception,
|
|
then no finalisation predicates will be executed.
|
|
|
|
@samp{finalize} is also allowed as a synonym for @samp{finalise}.
|
|
|
|
@node Module-local mutable variables
|
|
@section Module-local mutable variables
|
|
|
|
Certain special cases require a module to have
|
|
one or more mutable (i.e.@: destructively updateable) variables,
|
|
for example to hold the constraint store for a solver type.
|
|
|
|
A mutable variable is declared using the @samp{mutable} directive:
|
|
|
|
@example
|
|
:- mutable(@var{varname}, @var{vartype}, @var{initial_value}, @var{varinst}, [@var{attribute}, @dots{}]).
|
|
@end example
|
|
|
|
This constructs a new mutable variable with access predicates
|
|
that have the following signatures:
|
|
|
|
@example
|
|
:- semipure pred get_@var{varname}(@var{vartype}::out(@var{varinst})) is det.
|
|
:- impure pred set_@var{varname}(@var{vartype}::in(@var{varinst})) is det.
|
|
@end example
|
|
|
|
The initial value of @var{varname} is @var{initial_value},
|
|
which is set before the program's @samp{main/2} predicate is executed.
|
|
|
|
The type @var{vartype} is not allowed
|
|
to contain any type variables or have any type class constraints.
|
|
|
|
The inst @var{varinst} is not allowed to contain any inst variables.
|
|
It is also not allowed to be equivalent to,
|
|
or contain components that are equivalent to,
|
|
the builtin insts @code{free}, @code{unique}, @code{mostly_unique},
|
|
@code{dead} (@code{clobbered})
|
|
or @code{mostly_dead} (@code{mostly_clobbered}).
|
|
|
|
The initial value of a mutable, @var{initial_value},
|
|
may be any Mercury expression with type @var{vartype} and inst @var{varinst}
|
|
subject to the above restrictions.
|
|
It may be impure or semipure.
|
|
|
|
The following @var{attributes} are supported:
|
|
|
|
@table @asis
|
|
|
|
@item @samp{trailed}/@samp{untrailed}
|
|
This attribute specifies whether
|
|
the implementation should generate code
|
|
to undo the effects of @samp{set_@var{varname}/1} on backtracking
|
|
(@samp{trailed}) or not (@samp{untrailed}).
|
|
The default, in case none is specified, is @samp{trailed}.
|
|
|
|
@item @samp{attach_to_io_state}
|
|
This attribute causes the compiler
|
|
to also construct access predicates that have the following signatures:
|
|
|
|
@example
|
|
:- pred get_@var{varname}(@var{vartype}::out(@var{varinst}), io::di, io::uo) is det.
|
|
:- pred set_@var{varname}(@var{vartype}::in(@var{varinst}), io::di, io::uo) is det.
|
|
@end example
|
|
|
|
@item @samp{constant}
|
|
This attribute causes the compiler to construct
|
|
only a @samp{get} access predicate, but not a @samp{set} access predicate.
|
|
Since @var{varname} will always have the initial value given to it,
|
|
the @samp{get} access predicate is pure; its signature will be:
|
|
|
|
@example
|
|
:- pred get_@var{varname}(@var{vartype}::out(@var{varinst})) is det.
|
|
@end example
|
|
|
|
The @samp{constant} attribute cannot be specified together with
|
|
the @samp{attach_to_io_state} attribute
|
|
(since they disagree on this signature).
|
|
It also cannot be specified together with an explicit @samp{trailed} attribute.
|
|
|
|
@end table
|
|
|
|
The Melbourne Mercury compiler also supports the following attributes:
|
|
|
|
@table @asis
|
|
|
|
@item @samp{foreign_name(@var{Lang}, @var{Name})}
|
|
Allow foreign code to access the mutable variable
|
|
in some implementation dependent manner.
|
|
@var{Lang} must be a valid target language for this Mercury implementation.
|
|
@var{Name} must be a valid identifier in that language.
|
|
It is an error to specify
|
|
more than one foreign name attribute for each language.
|
|
|
|
For the C backends,
|
|
this attribute allows foreign code to access the mutable variable
|
|
as an external variable called @var{Name}.
|
|
For the low-level C backend, e.g.@: the asm_fast grades,
|
|
the type of this variable will be @code{MR_Word}.
|
|
For the high-level C backend, e.g.@: the hlc grades,
|
|
the type of this variable depends upon the Mercury type of the mutable.
|
|
For mutables of a Mercury primitive type,
|
|
the corresponding C type is given
|
|
by the mapping in @ref{C data passing conventions}.
|
|
For mutables of any other type,
|
|
the corresponding C type will be @code{MR_Word}.
|
|
|
|
This attribute is not currently implemented for the non-C backends.
|
|
|
|
@item @samp{thread_local}
|
|
This attribute allows a mutable to take on different values in each thread.
|
|
When a child thread is spawned,
|
|
it inherits all the values of thread-local mutables of the parent thread.
|
|
Changing the value of a thread-local mutable
|
|
does not affect its value in any other threads.
|
|
|
|
The @samp{thread_local} attribute cannot be specified
|
|
together with either of the @samp{trailed} or @samp{constant} attributes.
|
|
|
|
@end table
|
|
|
|
It is an error for a @samp{mutable} directive
|
|
to appear in the interface section of a module.
|
|
The usual visibility rules for submodules
|
|
apply to the mutable variable access predicates.
|
|
|
|
For the purposes of determining
|
|
when mutables are assigned their initial values,
|
|
the expression @var{initial_value} behaves
|
|
as though it were a predicate specified in an @samp{initialise} directive.
|
|
|
|
@example
|
|
:- initialise foo/2.
|
|
:- mutable(bar, int, 561, ground, [untrailed]).
|
|
:- initialise baz/2.
|
|
@end example
|
|
|
|
In the above example,
|
|
|
|
@itemize
|
|
@item @samp{foo/2} will be invoked first,
|
|
@item then @samp{bar} will be set to its initial value of 561,
|
|
@item and then @samp{baz/2} will be invoked.
|
|
@end itemize
|
|
|
|
The effect of a mutable initial value expression
|
|
terminating with an uncaught exception
|
|
is also the same as though it were
|
|
a predicate specified in an @samp{initialise} directive.
|
|
|
|
@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 typeclass declarations::
|
|
* Abstract instance declarations::
|
|
* Type class constraints on predicates and functions::
|
|
* Type class constraints on type class declarations::
|
|
* Type class constraints on instance declarations::
|
|
* Functional dependencies::
|
|
@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 each method, all parameters of the typeclass must be determined
|
|
by the type declaration of the method.
|
|
The values of @emph{most} parameter type variables
|
|
are determined by having them occur
|
|
in the declared type of an argument of the method.
|
|
However, if either the typeclass named in the constraint, or its superclasses,
|
|
include any functional dependencies, then
|
|
the value of a variable may also be implied by the values of other variables
|
|
(@pxref{Functional dependencies}).
|
|
|
|
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 mode and determinism of type class methods
|
|
must be explicitly declared or (for functions) defaulted, not inferred.
|
|
In other words, for each predicate declared in a type class,
|
|
there must be at least one mode declaration,
|
|
and each mode declaration in a type class
|
|
must include an explicit determinism annotation.
|
|
Functions with no explicit mode declaration
|
|
get the usual default mode (@pxref{Modes}):
|
|
all arguments have mode @code{in}, the result has mode @code{out},
|
|
and the determinism is @code{det}.
|
|
|
|
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 legal for a @code{typeclass} declaration to declare no methods,
|
|
for example
|
|
|
|
@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 [@var{method_definition}, @var{method_definition}, @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 type variables.
|
|
@c If this restriction is ever lifted, the algorithms for encoding the names of
|
|
@c the data structures describing the instance, in base_typeclass_info.m
|
|
@c and/or rtti.m, would need to be updated as well.
|
|
For example @code{int}, @code{list(T)},
|
|
@code{bintree(K, V)} and @code{bintree(T, T)} are allowed,
|
|
but @code{T} and @code{list(int)} 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 instance declaration for a particular type
|
|
(or sequence of types, in the case of a multi-parameter type class)
|
|
and typeclass.
|
|
These restrictions ensure that there are no overlapping instance declarations,
|
|
i.e.@: for each typeclass there is at most one instance declaration
|
|
that may be applied to any type (or sequence of types).
|
|
|
|
There is no special interaction between subtypes and the typeclass system.
|
|
A subtype is @emph{not} automatically an instance of a typeclass if
|
|
there is an @samp{instance} declaration for its supertype.
|
|
|
|
Each @var{method_definition} entry
|
|
in the @samp{where [@dots{}]} part of an @code{instance} declaration
|
|
defines the implementation of one of the class methods for this instance.
|
|
There are two ways of defining methods.
|
|
|
|
The first way to define a method is by
|
|
giving the name of the predicate or function which implements that method.
|
|
In this case, the @var{method_definition} must have one of the following forms:
|
|
|
|
@example
|
|
pred(@var{method_name}/@var{arity}) is @var{predname}
|
|
func(@var{method_name}/@var{arity}) is @var{funcname}
|
|
@end example
|
|
|
|
@noindent
|
|
The @var{predname} or @var{funcname} must name
|
|
a predicate or function 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{method_name} 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.
|
|
|
|
The second way of defining methods is
|
|
by listing the clauses for the definition inside the instance declaration.
|
|
A @var{method_definition} can be a clause.
|
|
These clauses are just like the clauses
|
|
used to define ordinary predicates or functions (@pxref{Items}),
|
|
and so they can be facts, rules, or DCG rules.
|
|
The only difference is that in instance declarations,
|
|
clauses are separated by commas rather than being terminated by periods,
|
|
and so rules and DCG rules in instance declarations
|
|
must normally be enclosed in parentheses.
|
|
As with ordinary predicates,
|
|
you can have more than one clause for each method.
|
|
The clauses must satisfy
|
|
the declared type, modes, determinism and purity for the method,
|
|
after the types of the arguments in the instance declaration
|
|
have been substituted in place of the parameters in the type class declaration.
|
|
|
|
These two ways are mutually exclusive:
|
|
each method must be defined either by a single naming definition
|
|
(using the @samp{pred(@dots{}) is @var{predname}}
|
|
or @samp{func(@dots{}) is @var{funcname}} form),
|
|
or by a set of one or more clauses, but not both.
|
|
|
|
Here is an example of an instance declaration
|
|
and the different kinds of method definitions that it can contain:
|
|
|
|
@example
|
|
@group
|
|
:- typeclass foo(T) where [
|
|
func method1(T, T) = int,
|
|
func method2(T) = int,
|
|
pred method3(T::in, int::out) is det,
|
|
pred method4(T::in, io.state::di, io.state::uo) is det,
|
|
func method5(bool, T) = T
|
|
].
|
|
|
|
:- instance foo(int) where [
|
|
% method defined by naming the implementation
|
|
func(method1/2) is (+),
|
|
|
|
% method defined by a fact
|
|
method2(X) = X + 1,
|
|
|
|
% method defined by a rule
|
|
(method3(X, Y) :- Y = X + 2),
|
|
|
|
% method defined by a DCG rule
|
|
(method4(X) --> io.print(X), io.nl),
|
|
|
|
% method defined by multiple clauses
|
|
method5(no, _) = 0,
|
|
(method5(yes, X) = Y :- X + Y = 0)
|
|
].
|
|
@end group
|
|
@end example
|
|
|
|
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 is 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 that represents the point using polar coordinates.
|
|
|
|
Since methods may be defined using clauses,
|
|
and the interface sections of modules may @emph{not} include clauses,
|
|
instance declarations that specify method definitions
|
|
may appear only in the implementation section of a module.
|
|
If you want to export the knowledge that a type, or a sequence of types,
|
|
is a member of a given typeclass,
|
|
then put a version of the instance declaration
|
|
that omits all method definitions
|
|
(@pxref{Abstract instance declarations})
|
|
into the interface section of the module
|
|
that contains the full instance declaration in its implementation section.
|
|
|
|
@node Abstract typeclass declarations
|
|
@section Abstract typeclass declarations
|
|
|
|
Abstract typeclass declarations
|
|
are typeclass declarations whose definitions are hidden.
|
|
An abstract typeclass declaration has the same form as a typeclass declaration,
|
|
but without the @samp{where[@dots{}]} part.
|
|
An abstract typeclass declaration defines
|
|
a name for a set of (sequences of) types,
|
|
but does not define what methods must be implemented
|
|
for instances of the type class.
|
|
|
|
Like abstract type declarations,
|
|
abstract typeclass declarations are only useful
|
|
in the interface section of a module.
|
|
Each abstract typeclass declaration must be accompanied
|
|
by a corresponding non-abstract typeclass declaration
|
|
that defines the methods for that type class.
|
|
|
|
Non-abstract instance declarations can only be made
|
|
in scopes where the non-abstract typeclass declaration is visible.
|
|
|
|
@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
|
|
in the implementation section of the same module
|
|
by a corresponding non-abstract instance declaration
|
|
that defines how the type class methods are implemented.
|
|
|
|
Here is 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 has the form:
|
|
|
|
@example
|
|
<= @var{Typeclass}(@var{Type}, @dots{}), @dots{}
|
|
@end example
|
|
|
|
@noindent
|
|
where @var{Typeclass} is the name of a type class and @var{Type} is a type.
|
|
Any variable that appears in @var{Type} must be determined
|
|
by the predicate's or function's type signature.
|
|
A variable is determined by a type signature
|
|
if it appears in the type signature,
|
|
but if functional dependencies are present,
|
|
then it may also be determined from other variables
|
|
(@pxref{Functional dependencies}).
|
|
Each type class constraint in a predicate or function declaration
|
|
must contain at least one variable.
|
|
|
|
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 arguments of a constraint on a type class declaration
|
|
must be either type variables or ground types.
|
|
Each constraint must contain at least one variable argument
|
|
and all variables that appear in the arguments
|
|
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
|
|
@group
|
|
:- 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 group
|
|
@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}.
|
|
|
|
Type class 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
|
|
|
|
Type class constraints may also be placed upon instance declarations.
|
|
The arguments of such constraints
|
|
must be either type variables or ground types.
|
|
Each constraint must contain at least one variable argument
|
|
and all variables that appear in the arguments
|
|
must be type variables that appear in the types in the instance declaration.
|
|
|
|
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([], !IO).
|
|
portray_list([X | Xs], !IO) :-
|
|
portray(X, !IO),
|
|
io.write_char(' ', !IO),
|
|
portray_list(Xs, !IO).
|
|
@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.
|
|
|
|
The abstract version of the above instance declaration would be
|
|
|
|
@example
|
|
:- instance portrayable(list(T)) <= portrayable(T).
|
|
@end example
|
|
|
|
@node Functional dependencies
|
|
@section Functional dependencies
|
|
|
|
Type class constraints may include any number of functional dependencies.
|
|
A @dfn{functional dependency} constraint
|
|
takes the form @code{(@var{Domain} -> @var{Range})}.
|
|
The @var{Domain} and @var{Range} arguments are either single type variables,
|
|
or conjunctions of distinct type variables separated by commas.
|
|
|
|
@example
|
|
:- typeclass @var{Typeclass}(@var{Var}, @dots{})@
|
|
<= ((@var{D} -> @var{R}), @dots{}) @dots{}
|
|
|
|
:- typeclass @var{Typeclass}(@var{Var}, @dots{})@
|
|
<= (@var{D1}, @var{D2}, @dots{} -> @var{R1}, @var{R2}, @dots{}), @dots{}
|
|
@end example
|
|
|
|
Each type variable must appear in the parameter list of the typeclass.
|
|
Abstract typeclass declarations must have
|
|
exactly the same functional dependencies as their concrete forms.
|
|
|
|
Mutually recursive functional dependencies are allowed,
|
|
so the following examples are legal:
|
|
|
|
@example
|
|
:- typeclass foo(A, B) <= ((A -> B), (B -> A)).
|
|
:- typeclass bar(A, B, C, D)@
|
|
<= ((A, B -> C), (B, C -> D), (D -> A, C)).
|
|
@end example
|
|
|
|
A functional dependency on a typeclass places an additional requirement
|
|
on the set of instances which are allowed for that type class.
|
|
The requirement is that
|
|
all types bound to variables in the range of the functional dependency
|
|
must be able to be uniquely determined
|
|
by the types bound to variables in the domain of the functional dependency.
|
|
If more than one functional dependency is present,
|
|
then the requirement for each one must be satisfied.
|
|
|
|
For example, given the typeclass declaration
|
|
|
|
@example
|
|
:- typeclass baz(A, B) <= (A -> B) where @dots{}
|
|
@end example
|
|
|
|
@noindent
|
|
it would be illegal to have both of the instances
|
|
|
|
@example
|
|
:- instance baz(int, int) where @dots{}
|
|
:- instance baz(int, string) where @dots{}
|
|
@end example
|
|
|
|
@noindent
|
|
although either one would be acceptable on its own.
|
|
|
|
The following instance would also be illegal
|
|
|
|
@example
|
|
:- instance baz(string, list(T)) where @dots{}
|
|
@end example
|
|
|
|
@noindent
|
|
since the variable @code{T} may not always be bound to the same type.
|
|
However, the instance
|
|
|
|
@example
|
|
:- instance baz(list(S), list(T)) <= baz(S, T) where @dots{}
|
|
@end example
|
|
|
|
is legal because
|
|
the @samp{baz(S, T)} constraint ensures that
|
|
whatever @code{T} is bound to,
|
|
it is always uniquely determined from the binding of @code{S}.
|
|
|
|
The extra requirements that result from the use of functional dependencies
|
|
allow the bindings of some variables
|
|
to be determined from the bindings of others.
|
|
This in turn relaxes some of the requirements
|
|
of typeclass constraints on predicate and function signatures,
|
|
and on existentially typed data constructors.
|
|
|
|
Without any functional dependencies, all variables in constraints
|
|
must appear in the signature of the predicate or function being declared.
|
|
However, variables which are in the range of a functional dependency
|
|
need not appear in the signature,
|
|
since it is known that their bindings will be determined
|
|
from the bindings of the variables in the domain.
|
|
@c XXX What about a class with two fundeps: A -> B, and B -> A.
|
|
@c Both A and B are in the range of a fundep.
|
|
@c The above text seems to imply that it is ok for *neither* to appear
|
|
@c in the signature.
|
|
@c Should we replace "since it is known that their bindings will be determined"
|
|
@c with "provided that their bindings are determined"?
|
|
|
|
More formally, the constraints on a predicate or function signature
|
|
@emph{induce} a set of functional dependencies
|
|
on the variables appearing in those constraints.
|
|
A functional dependency @samp{(A1, @dots{} -> B1, @dots{})}
|
|
is induced from a constraint
|
|
@samp{@var{Typeclass}(@var{Type1}, @dots{})}
|
|
if and only if the typeclass @samp{@var{Typeclass}}
|
|
has a functional dependency @samp{(D1, @dots{} -> R1, @dots{})},
|
|
and for each typeclass parameter @samp{Di} there exists an @samp{Aj}
|
|
every type variable appearing in the @samp{@var{Typek}}
|
|
corresponding to @samp{Di},
|
|
and each @samp{Bi} appears in the @samp{@var{Typej}}
|
|
bound to the typeclass parameter @samp{Rk} for some @var{k}.
|
|
|
|
For example, with the definition of @code{baz} above,
|
|
the constraint @code{baz(map(X, Y), list(Z))}
|
|
induces the constraint @code{(X, Y -> Z)},
|
|
since @var{X} and @var{Y} appear in the domain argument,
|
|
and @var{Z} appears in the range argument.
|
|
|
|
The set of type variables determined from a signature
|
|
is the @emph{closure} of the set appearing in the signature
|
|
under the functional dependencies induced from the constraints.
|
|
The closure is defined as the smallest set of variables
|
|
which includes all of the variables appearing in the signature,
|
|
and is such that, for each induced functional dependency
|
|
@samp{@var{Domain} -> @var{Range}},
|
|
if the closure includes all of the variables in @var{Domain}
|
|
then it includes all of the variables in @var{Range}.
|
|
|
|
For example, the declaration
|
|
|
|
@example
|
|
:- pred p(X, Y) <= baz(map(X, Y), list(Z)).
|
|
@end example
|
|
|
|
@noindent
|
|
is acceptable since the closure of @{@var{X},
|
|
@var{Y}@} under the induced functional dependency must include @var{Z}.
|
|
Moreover, the typeclass @code{baz/2} would be allowed
|
|
to have a method that only uses the first parameter, @var{A},
|
|
since the second parameter, @var{B}, would always be determined from the first.
|
|
|
|
Note that, since all instances must satisfy the superclass constraints,
|
|
the restrictions on instances obviously transfer from superclass to subclass.
|
|
Again, this allows the requirements of typeclass constraints to be relaxed.
|
|
Thus, the functional dependencies on the ancestors of constraints
|
|
also induce functional dependencies on the variables,
|
|
and the closure that we calculate takes these into account.
|
|
|
|
For example, in this code
|
|
|
|
@example
|
|
:- typeclass quux(P, Q, R) <= baz(R, P) where @dots{}
|
|
|
|
:- pred q(Q, R) <= quux(P, Q, R).
|
|
@end example
|
|
the signature of @code{q/2} is acceptable
|
|
since the superclass constraint on @code{quux/2}
|
|
induces the dependency @samp{R -> P} on the type variables,
|
|
hence @var{P} is in the closure of @{@var{Q}, @var{R}@}.
|
|
|
|
The presence of functional dependencies
|
|
also allows ``improvement'' to occur during type inference.
|
|
This can occur in two ways.
|
|
First, if two constraints of a given class match
|
|
on all of the domain arguments of a functional dependency on that class,
|
|
then it can be inferred that they also match on the range arguments.
|
|
For example,
|
|
given the constraints @w{@code{baz(A, B1)}} and @w{@code{baz(A, B2)}},
|
|
it will be inferred that @code{B1 = B2}.
|
|
|
|
Similarly, if a constraint of a given class
|
|
is subsumed by a known instance of that class in the domain arguments,
|
|
then its range arguments can be unified
|
|
with the corresponding instance range arguments.
|
|
For example, given the instance:
|
|
|
|
@example
|
|
:- instance baz(list(T), string) where @dots{}
|
|
@end example
|
|
|
|
@noindent
|
|
then the constraint @code{baz(list(int), X)}
|
|
can be improved with the inference that @w{@code{X = string}}.
|
|
|
|
@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::
|
|
@end menu
|
|
|
|
@node Existentially typed predicates and functions
|
|
@section Existentially typed predicates and functions
|
|
|
|
@menu
|
|
* Syntax for explicit type quantifiers::
|
|
* Semantics of type quantifiers::
|
|
* Examples of correct code using type quantifiers::
|
|
* Examples of incorrect code using type quantifiers::
|
|
@end menu
|
|
|
|
@node Syntax for explicit type quantifiers
|
|
@subsection Syntax for explicit type quantifiers
|
|
|
|
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 quantifiers
|
|
@subsection Semantics of type quantifiers
|
|
|
|
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 @samp{io.write} which can be useful in this context.)
|
|
|
|
A non-variable type (i.e.@: a type that is not a type variable)
|
|
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.
|
|
|
|
Note that an existentially typed procedure
|
|
is not allowed to have different types
|
|
for its existentially typed arguments in different clauses
|
|
(even mode-specific clauses)
|
|
or in different subgoals of a single clause;
|
|
however, the same effect can be achieved in other ways
|
|
(@pxref{Some idioms using existentially quantified types}).
|
|
|
|
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 @code{in},
|
|
whereas existentially quantified type variables have mode @code{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 @samp{<=},
|
|
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 @samp{=>} instead of @samp{<=};
|
|
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(T2)' are existential constraints,
|
|
% and `c3(T1)' is a universal constraint,
|
|
:- all [T1] some [T2] ((pred p(T1, T2) => (c1(T2), c2(T2))) <= c3(T1)).
|
|
@end example
|
|
|
|
Existential constraints must only constrain type variables
|
|
that are explicitly existentially quantified.
|
|
Likewise, universal constraints must only constrain type variables
|
|
that are universally quantified,
|
|
although in this case the quantification does not have to be explicit
|
|
because universal quantification is the default
|
|
(see @ref{Syntax for explicit type quantifiers}).
|
|
|
|
@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, showable_list) => 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 is an arbitrary example involving multiple type variables
|
|
% and multiple constraints.
|
|
:- typeclass foo(T1, T2) where [ /* @dots{} */ ].
|
|
:- type bar(T)
|
|
---> f1
|
|
; f2(T)
|
|
; some [T1] f3(T1)
|
|
; some [T1, T2] f4(T1, T2, T) => (showable(T1), showable(T2))
|
|
; some [T1, T2] f5(list(T1), T2) => fooable(T1, 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{showable_list}
|
|
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
|
|
|
|
@noindent
|
|
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(showable_list) = list(string).
|
|
process_list(nil) = "".
|
|
process_list(cons(Head, Tail)) = [show(Head) | process_list(Tail)].
|
|
@end example
|
|
|
|
@noindent
|
|
There are some restrictions on the forms that
|
|
existentially typed data constructors can take.
|
|
|
|
The first restriction is that no type variable may be quantified
|
|
both universally, by being listed as an argument of the type constructor,
|
|
and existentially, by being listed in the existential type quantifier
|
|
before the data constructor.
|
|
The type @samp{t12} violates this restriction:
|
|
|
|
@example
|
|
:- type t12(T)
|
|
---> f1(T)
|
|
; some [T] f2(T).
|
|
@end example
|
|
|
|
@noindent
|
|
The reason for the restriction is simple:
|
|
the reference of @samp{T} in the @samp{f2} data constructor
|
|
being simultaneously inside the scope of more than quantification
|
|
can mislead readers who see one of the quantifications,
|
|
and stop looking for the other.
|
|
The simplest way to avoid such confusion
|
|
is to require the programmer to avoid having one quantification shadow another.
|
|
|
|
The second restriction is that
|
|
type variables listed
|
|
in the existential type quantifier before the data constructor
|
|
cannot be repeated.
|
|
Type variables in the argument list of the type constructor
|
|
also cannot be repeated,
|
|
whether or not the data constructors of that type
|
|
have existential types.
|
|
The type @samp{t34} violates both these restrictions:
|
|
|
|
@example
|
|
:- type t34(A, B, A)
|
|
---> f3(A, B)
|
|
; some [C, D, D] f4(C, D).
|
|
@end example
|
|
|
|
The third and final restriction is that
|
|
every existentially quantified type variable
|
|
must occur
|
|
@itemize
|
|
@item either in one of the argument types of the data constructor,
|
|
@item or in one of the type class constraints on the data constructor,
|
|
in the range of a functional dependency.
|
|
@end itemize
|
|
|
|
@noindent
|
|
This means that the type @samp{t5} in
|
|
@example
|
|
:- type t5
|
|
---> some [T1, T2] f5(T1) => xable(T1, T2).
|
|
@end example
|
|
@noindent
|
|
violates this restriction
|
|
@emph{unless} the type class @samp{xable} has a functional dependency
|
|
that determines the type bound to its second argument
|
|
from the type bound to its first.
|
|
|
|
The reason for this restriction is that
|
|
the identity of the type bound to the existential type variable
|
|
must somehow be decided at runtime.
|
|
It can either be given by the type of an argument,
|
|
or determined through a functional dependency
|
|
from the types bound to one or more other existential type variables.
|
|
|
|
@node Some idioms using existentially quantified types
|
|
@section Some idioms using existentially quantified types
|
|
|
|
The standard library module @samp{univ}
|
|
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{univ} 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 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} does not 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
|
|
|
|
The issue can also arise for mode-specific clauses
|
|
(@pxref{Different clauses for different modes}).
|
|
For instance, the following example is illegal:
|
|
|
|
@example
|
|
:- some [T] pred bad_example3(string, T).
|
|
:- mode bad_example3(in(bound("foo")), out) is det.
|
|
:- mode bad_example3(in(bound("bar")), out) is det.
|
|
:- pragma promise_pure(bad_example3/2).
|
|
bad_example3("foo"::in(bound("foo")), 42::out).
|
|
bad_example3("bar"::in(bound("bar")), "blah"::out).
|
|
% type error (cannot unify `int' and `string')
|
|
@end example
|
|
|
|
The solution is similar,
|
|
although in this case an intermediate predicate is required:
|
|
|
|
@example
|
|
:- some [T] pred good_example3(string, T).
|
|
:- mode good_example3(in(bound("foo")), out) is det.
|
|
:- mode good_example3(in(bound("bar")), out) is det.
|
|
good_example3(Name, univ_value(Univ)) :-
|
|
good_example3_univ(Name, Univ).
|
|
|
|
:- pred good_example3_univ(string, univ).
|
|
:- mode good_example3_univ(in(bound("foo")), out) is det.
|
|
:- mode good_example3_univ(in(bound("bar")), out) is det.
|
|
:- pragma promise_pure(good_example3_univ/2).
|
|
good_example3_univ("foo"::in(bound("foo")), univ(42)::out).
|
|
good_example3_univ("bar"::in(bound("bar")), univ("blah")::out).
|
|
@end example
|
|
|
|
@c -----------------------------------------------------------------------
|
|
|
|
@node Type conversions
|
|
@chapter Type conversions
|
|
|
|
(This is a new and experimental feature, subject to change.)
|
|
|
|
A term may be converted from one type @var{FromType}
|
|
to another type @var{ToType}
|
|
using a type conversion expression of the form:
|
|
|
|
@example
|
|
coerce(@var{Term})
|
|
@end example
|
|
|
|
The expression is type-correct iff
|
|
@var{FromType} and @var{ToType} are both discriminated union types,
|
|
and after replacing the principal type constructors with base types
|
|
(@pxref{Subtypes})
|
|
the two types have the same type constructor,
|
|
and the arguments of the common type constructor
|
|
satisfy the type parameter variance restrictions below.
|
|
|
|
Let @var{FromType} expand out to @samp{base(S1, ..., Sn)}
|
|
and @var{ToType} expand out to @samp{base(T1, ..., Tn)},
|
|
where @samp{base(B1, ..., Bn)} is the common base type,
|
|
and @var{Bi} is the i'th type parameter,
|
|
which is bound to @var{Si} in @var{FromType}
|
|
and @var{Ti} in @var{ToType}.
|
|
|
|
For each pair of corresponding type arguments,
|
|
one of the following must be true:
|
|
@itemize
|
|
@item
|
|
@samp{Si = Ti}
|
|
if the two types are the same
|
|
|
|
@item
|
|
@samp{Si < Ti}
|
|
if @var{Si} is a subtype of @var{Ti}
|
|
by the relation below
|
|
|
|
@item
|
|
@samp{Ti < Si}
|
|
if @var{Ti} is a subtype of @var{Si}
|
|
by the relation below
|
|
@end itemize
|
|
|
|
Otherwise, the @code{coerce} expression is not type-correct.
|
|
@c NOTE: we deliberately disallow coercion between arbitrary phantom types.
|
|
|
|
Furthermore,
|
|
@samp{Si = Ti} must be true
|
|
if @var{Bi} occurs in one or more of these locations
|
|
in the @samp{base/n} type definition:
|
|
|
|
@itemize
|
|
@item
|
|
in a higher-order type
|
|
|
|
@item
|
|
in a foreign type
|
|
|
|
@item
|
|
in an abstract type
|
|
|
|
@item
|
|
in a solver type
|
|
|
|
@item
|
|
in a discriminated union type,
|
|
other than a recursive type of the exact form @samp{base(B1, ..., Bn)}
|
|
@end itemize
|
|
|
|
The relation @samp{S < T} is true when @samp{S != T} and either:
|
|
@itemize
|
|
@item
|
|
@samp{S} and @samp{T} are both discriminated union types,
|
|
and @samp{S} is a subtype of @samp{T} by visible subtype definitions;
|
|
or
|
|
|
|
@item
|
|
@samp{S} and @samp{T} are both tuple types of the same arity,
|
|
and for each pair of corresponding argument types @samp{Si} and @samp{Ti},
|
|
@samp{Si < Ti} is true.
|
|
@end itemize
|
|
|
|
@heading Mode checking
|
|
|
|
Type conversion expressions must also be mode-correct.
|
|
Intuitively, conversion from a subtype to its supertype is safe,
|
|
but a conversion from a supertype to one of its subtypes is safe only if
|
|
the inst approximating the term to be converted
|
|
indicates that the result would also be valid in the subtype.
|
|
|
|
Mode checking proceeds by simultaneously traversing
|
|
the inst tree of the @code{coerce} argument,
|
|
the type tree of the @code{coerce} argument,
|
|
and the type tree of the result term,
|
|
and producing the inst tree of the result term
|
|
if the conversion is valid.
|
|
Let
|
|
@itemize
|
|
@item
|
|
@var{InstX} be the current node in the @code{coerce} argument's inst tree,
|
|
@item
|
|
@var{InstY} be the current node in the result inst tree,
|
|
@item
|
|
@var{TypeX} be the current node in the @code{coerce} argument's type tree,
|
|
@item
|
|
@var{TypeY} be the current node in the result type tree,
|
|
@item
|
|
@var{TypeCtorX} be the principal type constructor of @var{TypeX},
|
|
@item
|
|
@var{TypeCtorY} be the principal type constructor of @var{TypeY}.
|
|
@end itemize
|
|
|
|
In the following, @var{X} < @var{Y} means
|
|
@var{X} is a subtype of @var{Y}
|
|
by visible subtype definitions.
|
|
|
|
For each node @var{InstX}:
|
|
@itemize
|
|
@item
|
|
If @var{InstX} is a recursive node in the inst tree
|
|
(i.e. it is its own ancestor),
|
|
then we require @var{TypeX} =< @var{TypeY}.
|
|
Let @var{InstY} = @var{InstX}.
|
|
|
|
@item
|
|
Otherwise, if @var{InstX} is a @code{bound} node:
|
|
|
|
@itemize
|
|
@item
|
|
If @var{TypeX} is an existentially quantified type variable,
|
|
then @var{InstY} = @var{InstX}.
|
|
|
|
@item
|
|
If @var{TypeX} is not an existentially quantified type variable,
|
|
then each of the function symbols listed in @var{InstX}
|
|
must name a constructor in @var{TypeCtorY}.
|
|
Let @var{InstY} be a @code{bound} inst containing those same
|
|
function symbols;
|
|
the insts for the arguments of each function symbol
|
|
are then checked and constructed recursively.
|
|
@end itemize
|
|
|
|
@item
|
|
Otherwise, if @var{InstX} is a @code{ground} node:
|
|
|
|
@itemize
|
|
@item
|
|
If @var{TypeX} = @var{TypeY},
|
|
or if @var{TypeX} is an existentially quantified type variable,
|
|
then let @var{InstY} = @var{InstX}.
|
|
@c This includes higher-order types.
|
|
|
|
@item
|
|
If @var{TypeX} < @var{TypeY}, then
|
|
let @var{InstY} be the @code{bound} node constructed
|
|
using the process below.
|
|
@end itemize
|
|
|
|
@item
|
|
Otherwise,
|
|
the @code{coerce} expression is not mode-correct.
|
|
@end itemize
|
|
|
|
To construct a @samp{bound} node @var{InstY}
|
|
from a @samp{ground} node @var{InstX}:
|
|
|
|
@itemize
|
|
@item
|
|
If @var{TypeX} = @var{TypeY}
|
|
or if @var{TypeX} is a recursive node in the type tree
|
|
(i.e. it is its own ancestor),
|
|
then let @var{InstY} be @code{ground}.
|
|
|
|
@item
|
|
Otherwise, let @var{InstY} be a @code{bound} inst
|
|
containing all of the constructors in @var{TypeCtorX};
|
|
the insts for the arguments of each function symbol
|
|
are constructed recursively.
|
|
@end itemize
|
|
|
|
@heading Examples
|
|
|
|
Assume we have:
|
|
|
|
@example
|
|
:- type fruit
|
|
---> apple
|
|
; lemon
|
|
; orange.
|
|
|
|
:- type citrus =< fruit
|
|
---> lemon
|
|
; orange.
|
|
@end example
|
|
|
|
This function is type and mode-correct:
|
|
|
|
@example
|
|
:- func f1(citrus) = fruit.
|
|
|
|
f1(X) = coerce(X).
|
|
@end example
|
|
|
|
This function is type-correct but not mode-correct
|
|
because some @code{fruit}s are not @code{citrus}:
|
|
|
|
@example
|
|
:- func f2(fruit) = citrus.
|
|
|
|
f2(X) = coerce(X). % incorrect
|
|
@end example
|
|
|
|
This function is mode-correct
|
|
because the initial inst of the input argument
|
|
limits the range of @code{fruit} values
|
|
to those that would also be valid in @code{citrus}:
|
|
|
|
@example
|
|
:- inst citrus for fruit/0
|
|
---> lemon
|
|
; orange.
|
|
|
|
:- func f3(fruit) = citrus.
|
|
:- mode f3(in(citrus)) = out is det.
|
|
|
|
f3(X) = coerce(X).
|
|
@end example
|
|
|
|
Finally,
|
|
this function is type-incorrect because
|
|
in the coerce expression,
|
|
the type parameter @var{T} of @code{wrap/1}
|
|
is bound to @code{fruit} in the input type,
|
|
but @code{citrus} in the result type.
|
|
|
|
@example
|
|
:- type wrap(T)
|
|
---> wrap(T).
|
|
|
|
:- func f4(func(fruit) = int) = (func(citrus) = int).
|
|
|
|
f4(X) = Y :-
|
|
wrap(Y) = coerce(wrap(X)). % incorrect
|
|
@end example
|
|
|
|
@c -----------------------------------------------------------------------
|
|
|
|
@node Exception handling
|
|
@chapter Exception handling
|
|
|
|
Mercury procedures may throw exceptions.
|
|
Exceptions may be caught
|
|
using the predicates defined in the @samp{exception} library module,
|
|
or using try goals.
|
|
|
|
@noindent
|
|
A @samp{try} goal has the following form:
|
|
|
|
@example
|
|
try @var{Params} @var{Goal}
|
|
then @var{ThenGoal}
|
|
else @var{ElseGoal}
|
|
catch @var{Term} -> @var{CatchGoal}
|
|
@dots{}
|
|
catch_any @var{CatchAnyVar} -> @var{CatchAnyGoal}
|
|
@end example
|
|
|
|
@var{Goal}, @var{ThenGoal}, @var{ElseGoal}, @var{CatchGoal},
|
|
@var{CatchAnyGoal} must be valid goals.
|
|
|
|
@var{Goal} must have one of the following determinisms:
|
|
@code{det}, @code{semidet}, @code{cc_multi}, or @w{@code{cc_nondet}}.
|
|
|
|
The non-local variables of @var{Goal}
|
|
must not have an inst equivalent to
|
|
@code{unique}, @w{@code{mostly_unique}} or @code{any},
|
|
unless they have the type @samp{io.state}.
|
|
@c or (later) the store/1.)
|
|
|
|
@var{Params} must be a valid list of zero or more try parameters.
|
|
|
|
The ``then'' part is mandatory.
|
|
The ``else'' part is mandatory if @var{Goal} may fail;
|
|
otherwise it must be omitted.
|
|
There may be zero or more ``catch'' branches.
|
|
The ``catch_any'' part is optional.
|
|
@var{CatchAnyVar} must be a single variable.
|
|
|
|
The try parameter @samp{io} takes a single argument,
|
|
which must be the name of a state variable prefixed by @samp{!};
|
|
for example, @samp{io(!IO)}.
|
|
The state variable must have the type @samp{io.state},
|
|
and be in scope of the try goal.
|
|
The state variable is threaded through @var{Goal},
|
|
so it may perform I/O but cannot fail.
|
|
If no @samp{io} parameter exists, @var{Goal} may not perform I/O and may fail.
|
|
|
|
A try goal has determinism @code{cc_multi}.
|
|
@c Exception: if all of the then/else/catch/catch_any parts only succeed
|
|
@c without binding non-local variables then the determinism is det.
|
|
@c In the implementation we may still infer cc_multi though.
|
|
|
|
On entering a try goal, @var{Goal} is executed.
|
|
If it succeeds without throwing an exception, @var{ThenGoal} is executed.
|
|
Any variables bound by @var{Goal} are visible in @var{ThenGoal} only.
|
|
If @var{Goal} fails, then @var{ElseGoal} is executed.
|
|
|
|
If @var{Goal} throws an exception,
|
|
the exception value is unified with
|
|
each of the @var{Term}s in the ``catch'' branches in turn.
|
|
On the first successful unification,
|
|
the corresponding @var{CatchGoal} is executed
|
|
(and other ``catch'' and ``catch_any'' branches ignored).
|
|
Variables bound during the unification of the @var{Term}
|
|
are in scope of the corresponding @var{CatchGoal}.
|
|
|
|
If the exception value does not unify
|
|
with any of the terms in ``catch'' branches,
|
|
and a ``catch_any'' branch is present,
|
|
the exception is bound to @var{CatchAnyVar}
|
|
and the @var{CatchAnyGoal} executed.
|
|
@var{CatchAnyVar} is visible in the @var{CatchAnyGoal} only,
|
|
and is existentially typed, i.e.@: it has type @samp{some [T] T}.
|
|
|
|
Finally, if the thrown value did not unify with any ``catch'' term,
|
|
and there is no ``catch_any'' branch, the exception is rethrown.
|
|
|
|
@noindent
|
|
The declarative semantics of a try goal is:
|
|
|
|
@example
|
|
@group
|
|
(
|
|
try [] Goal
|
|
then Then
|
|
else Else
|
|
catch CP1 -> CG1
|
|
catch CP2 -> CG2
|
|
@dots{}
|
|
catch_any CAV -> CAG
|
|
)
|
|
<=>
|
|
(
|
|
Goal, Then
|
|
;
|
|
not Goal, Else
|
|
;
|
|
some [Excp]
|
|
( if Excp = CP1 then
|
|
CG1
|
|
else if Excp = CP2 then
|
|
CG2
|
|
else if @dots{}
|
|
@dots{}
|
|
else
|
|
Excp = CAV,
|
|
CAG
|
|
)
|
|
).
|
|
@end group
|
|
@end example
|
|
|
|
If no @samp{else} branch is present, then @samp{Else = fail}.
|
|
If no @samp{catch_any} branch is present, then @samp{CAG = fail}.
|
|
|
|
@noindent
|
|
An example of a try goal that performs I/O is:
|
|
|
|
@example
|
|
:- pred p_carefully(io::di, io::uo) is cc_multi.
|
|
|
|
p_carefully(!IO) :-
|
|
(try [io(!IO)] (
|
|
io.write_string("Calling p\n", !IO),
|
|
p(Output, !IO)
|
|
)
|
|
then
|
|
io.write_string("p returned: ", !IO),
|
|
io.write(Output, !IO),
|
|
io.nl(!IO)
|
|
catch S ->
|
|
io.write_string("p threw a string: ", !IO),
|
|
io.write_string(S, !IO),
|
|
io.nl(!IO)
|
|
catch 42 ->
|
|
io.write_string("p threw 42\n", !IO)
|
|
catch_any Other ->
|
|
io.write_string("p threw something: ", !IO),
|
|
io.write(Other, !IO),
|
|
% Rethrow the value.
|
|
throw(Other)
|
|
).
|
|
@end example
|
|
|
|
@noindent
|
|
One common use for exceptions is to check the input
|
|
and throw an exception if it is invalid.
|
|
It might be tempting to implement this
|
|
with a predicate such as the following:
|
|
|
|
@example
|
|
:- pred check_target(target::in) is det.
|
|
|
|
check_target(Target) :-
|
|
( if ... then
|
|
true
|
|
else
|
|
throw("invalid target")
|
|
).
|
|
@end example
|
|
|
|
@noindent
|
|
This code warrants caution, however.
|
|
Consider the following usage:
|
|
|
|
@example
|
|
shoot(Target, !IO) :-
|
|
check_target(Target),
|
|
unsafe_shoot(Target, !IO).
|
|
@end example
|
|
|
|
@noindent
|
|
Mercury may reorder conjunctions,
|
|
which is (probably) not what the user intended in this case.
|
|
Furthermore,
|
|
Mercury may optimize away the call to @samp{check_target/1} entirely,
|
|
since the mode-determinism assertion for
|
|
a @samp{det} predicate with no outputs
|
|
essentially states that it is equivalent to @samp{true}.
|
|
|
|
The strict sequential semantics can be used
|
|
to guarantee that these changes will not occur
|
|
(@pxref{Formal semantics}).
|
|
However,
|
|
we recommend implementing checks like these in the following way,
|
|
to avoid depending on the choice of operational semantics:
|
|
|
|
@example
|
|
shoot(Target0, !IO) :-
|
|
check_target(Target0, Target),
|
|
unsafe_shoot(Target, !IO).
|
|
|
|
:- pred check_target(target::in, target::out) is det.
|
|
|
|
check_target(Target0, Target) :-
|
|
( if ... then
|
|
Target = Target0
|
|
else
|
|
throw("invalid target")
|
|
).
|
|
@end example
|
|
|
|
@node Formal semantics
|
|
@chapter Formal 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} semantics.
|
|
In this semantics,
|
|
the program is executed top-down using SLDNF resolution
|
|
(or something equivalent),
|
|
starting from @samp{main/2}
|
|
preceded by any module initialisation goals
|
|
(as per @ref{Module initialisation}),
|
|
and followed by any module finalisation goals
|
|
(as per @ref{Module finalisation}).
|
|
Function calls, 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:
|
|
the sub-goals are reordered, not split and interleaved.
|
|
Function application is strict, not lazy.
|
|
Predicate calls are strict in the sense that
|
|
goals will be executed irrespective of any mode-determinism assertions,
|
|
even if they loop,
|
|
are @samp{erroneous},
|
|
or are @samp{det} and contain no outputs.
|
|
@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
|
|
semantics.
|
|
|
|
There is another operational semantics of Mercury programs
|
|
called the @dfn{strict commutative} semantics.
|
|
This semantics is equivalent to the strict sequential 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 differ
|
|
each time a particular goal is entered.
|
|
|
|
As well as providing the strict sequential semantics,
|
|
Mercury implementations may provide
|
|
one or more implementation-defined operational semantics,
|
|
as long as any such implementation-defined operational semantics
|
|
is at least as complete as the strict commutative semantics.
|
|
An implementation-defined operational semantics
|
|
is ``at least as complete'' as the strict commutative semantics
|
|
if and only if the implementation-defined operational 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
|
|
function calls, conjunctions and disjunctions).
|
|
|
|
Thus, to summarize,
|
|
there are in fact a variety of different operational semantics for Mercury.
|
|
One of them, the strict sequential semantics,
|
|
is deterministic---the behaviour is always specified exactly.
|
|
Programs are executed top-down,
|
|
mode analysis does ``minimal'' reordering (in a precisely defined sense),
|
|
function calls, conjunctions and disjunctions
|
|
are executed depth-first left-to-right,
|
|
and function and predicate 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 be non-deterministic)
|
|
as long as they are sound with respect to the declarative semantics,
|
|
and meet a minimum level of completeness.
|
|
|
|
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 strict commutative semantics.
|
|
In some ways this is not 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.
|
|
On the other hand,
|
|
if you do write code which works for all possible executions
|
|
under the strict commutative semantics,
|
|
then you can be guaranteed that it will work correctly
|
|
on every implementation,
|
|
under every possible implementation-defined operational semantics.
|
|
|
|
The Melbourne Mercury implementation offers
|
|
eight different operational semantics,
|
|
which can be selected with different combinations
|
|
of the following options:
|
|
|
|
@table @code
|
|
@item --no-reorder-conj
|
|
Only do minimal reordering of conjunctions.
|
|
@item --no-reorder-disj
|
|
Do not reorder disjunctions.
|
|
@item --no-fully-strict
|
|
Predicate calls are not strict
|
|
(function application is always strict in the current implementation).
|
|
This option allows the compiler to improve completeness
|
|
by optimizing away infinite loops,
|
|
goals with determinism @code{erroneous},
|
|
and goals with determinism @code{det} and no outputs.
|
|
@end table
|
|
|
|
@noindent
|
|
The default semantics is the strict commutative semantics.
|
|
The strict sequential semantics can be selected with the
|
|
@samp{--no-reorder-conj} and @samp{--no-reorder-disj} options.
|
|
|
|
Future implementations of Mercury
|
|
may wish to offer other implementation-defined 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 Foreign language interface
|
|
@chapter Foreign language interface
|
|
|
|
@menu
|
|
* Calling foreign code from Mercury:: How to implement a Mercury predicate
|
|
or function as a call to code
|
|
written in a different
|
|
programming language.
|
|
* Calling Mercury from foreign code:: How to call a Mercury predicate
|
|
or function from a different
|
|
programming language.
|
|
* Data passing conventions:: How Mercury types are passed to
|
|
different languages.
|
|
* Using foreign types from Mercury:: How to use a type defined in
|
|
a different programming language
|
|
in Mercury code.
|
|
* Using foreign enumerations in Mercury code:: How to use an enumeration type
|
|
defined in a foreign language
|
|
in Mercury code.
|
|
* Using Mercury enumerations in foreign code:: How to use an enumeration type
|
|
defined in Mercury in a
|
|
different programming language.
|
|
* Adding foreign declarations:: How to add declarations of
|
|
entities in other programming
|
|
languages.
|
|
* Declaring Mercury exports to other modules::
|
|
How to call Mercury procedures from a
|
|
different programming language in
|
|
another module.
|
|
* Adding foreign definitions:: How to add definitions of
|
|
entities in other programming
|
|
languages.
|
|
* Language specific bindings:: Information specific to each
|
|
foreign language.
|
|
|
|
@end menu
|
|
|
|
This chapter documents the foreign language interface.
|
|
|
|
@node Calling foreign code from Mercury
|
|
@section Calling foreign code from Mercury
|
|
|
|
Mercury procedures can be implemented
|
|
using fragments of foreign language code using @samp{pragma foreign_proc}.
|
|
|
|
@menu
|
|
* pragma foreign_proc:: Defining Mercury procedures using foreign code.
|
|
* Foreign code attributes:: Describing properties of foreign
|
|
functions or code.
|
|
@end menu
|
|
|
|
@node pragma foreign_proc
|
|
@subsection pragma foreign_proc
|
|
|
|
A declaration of the form
|
|
|
|
@example
|
|
:- pragma foreign_proc("@var{Lang}",
|
|
@var{Pred}(@var{Var1}::@var{Mode1}, @var{Var2}::@var{Mode2}, @dots{}),
|
|
@var{Attributes}, @var{Foreign_Code}).
|
|
@end example
|
|
|
|
@noindent
|
|
or
|
|
|
|
@example
|
|
:- pragma foreign_proc("@var{Lang}",
|
|
@var{Func}(@var{Var1}::@var{Mode1}, @var{Var2}::@var{Mode2}, @dots{}) = (@var{Var}::@var{Mode}),
|
|
@var{Attributes}, @var{Foreign_Code}).
|
|
@end example
|
|
|
|
@noindent
|
|
means that any calls to the specified mode of @var{Pred} or @var{Func}
|
|
will result in execution of the foreign code given in @var{Foreign_Code}
|
|
written in language @var{Lang},
|
|
if @var{Lang} is selected as the foreign language code by this implementation.
|
|
See the ``Foreign Language Interface'' chapter of the Mercury User's Guide,
|
|
for more information about how the implementation selects
|
|
the appropriate @samp{foreign_proc} to use.
|
|
|
|
The foreign code fragment may refer to the specified variables
|
|
(@var{Var1}, @var{Var2}, @dots{}, and @var{Var}) directly by name.
|
|
It is an error for a variable to occur more than once in the argument list.
|
|
These variables will have foreign language types
|
|
corresponding to their Mercury types,
|
|
as determined by language and implementation specific rules.
|
|
|
|
All @samp{foreign_proc} implementations are assumed to be impure.
|
|
If they are actually pure or semipure,
|
|
they must be explicitly promised as such by the user
|
|
(either by using foreign language attributes specified below,
|
|
or a @samp{promise_pure} or @samp{promise_semipure} pragma
|
|
as specified in @ref{Impurity}).
|
|
|
|
Additional restrictions on the foreign language interface code
|
|
depend on the foreign language and compilation options.
|
|
For more information, including the list of supported foreign languages
|
|
and the strings used to identify them,
|
|
see the language specific information
|
|
in the ``Foreign Language Interface'' chapter of the Mercury User's Guide.
|
|
|
|
If there is a @code{pragma foreign_proc} declaration
|
|
for any mode of a predicate or function,
|
|
then there must be either a clause or a @code{pragma foreign_proc} declaration
|
|
for every mode of that predicate or function.
|
|
|
|
Here is an example of code using @samp{pragma foreign_proc}.
|
|
The following code defines a Mercury function @samp{sin/1}
|
|
which calls the C function @samp{sin()} of the same name.
|
|
|
|
@example
|
|
@group
|
|
:- func sin(float) = float.
|
|
:- pragma foreign_proc("C",
|
|
sin(X::in) = (Sin::out),
|
|
[promise_pure, may_call_mercury],
|
|
"
|
|
Sin = sin(X);
|
|
").
|
|
@end group
|
|
@end example
|
|
|
|
If the foreign language 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 foreign code @emph{does} invoke Mercury code,
|
|
then the behaviour is undefined --- your program may misbehave or crash.)
|
|
|
|
If there are both Mercury definitions and foreign_proc definitions
|
|
for a procedure and/or foreign_proc definitions for different languages,
|
|
it is implementation-defined which definition is used.
|
|
|
|
For pure and semipure procedures,
|
|
the declarative semantics of the foreign_proc definitions
|
|
must be the same as that of the Mercury code.
|
|
The only thing that is allowed to differ is the efficiency
|
|
(including the possibility of non-termination)
|
|
and the order of solutions.
|
|
|
|
It is an error for a procedure with a @samp{pragma foreign_proc} declaration
|
|
to have a determinism of @code{multi} or @code{nondet}.
|
|
|
|
Since foreign_procs with the determinism @code{multi} or @code{nondet}
|
|
cannot be defined directly,
|
|
procedures with those determinisms
|
|
that require foreign code in their implementation
|
|
must be defined using a combination
|
|
of Mercury clauses and (semi)deterministic foreign_procs.
|
|
The following implementation for the standard library predicate
|
|
@samp{string.append/3} in the mode @samp{append(out, out, in) is multi}
|
|
illustrates this technique:
|
|
|
|
@example
|
|
:- pred append(string, string, string).
|
|
:- mode append(out, out, in) is multi.
|
|
|
|
append(S1, S2, S3) :-
|
|
S3Len = string.length(S3),
|
|
append_2(0, S3Len, S1, S2, S3).
|
|
|
|
:- pred append_2(int::in, int::in, string::out, string::out, string::in) is multi.
|
|
|
|
append_2(NextS1Len, S3Len, S1, S2, S3) :-
|
|
( if NextS1Len = S3Len then
|
|
append_3(NextS1Len, S3Len, S1, S2, S3)
|
|
else
|
|
(
|
|
append_3(NextS1Len, S3Len, S1, S2, S3)
|
|
;
|
|
append_2(NextS1Len + 1, S3Len, S1, S2, S3)
|
|
)
|
|
).
|
|
|
|
:- pred append_3(int::in, int::in, string::out, string::out, string::in) is det.
|
|
|
|
:- pragma foreign_proc("C",
|
|
append_3(S1Len::in, S3Len::in, S1::out, S2::out, S3::in),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
S1 = allocate_string(S1Len); /* Allocate a new string of length S1Len */
|
|
memcpy(S1, S3, S1Len);
|
|
S1[S1Len] = '\\0';
|
|
S2 = allocate_string(S2, S3Len - S1Len);
|
|
strcpy(S2, S3Len + S1Len);
|
|
").
|
|
|
|
@end example
|
|
|
|
@node Foreign code attributes
|
|
@subsection Foreign code attributes
|
|
|
|
As described above,
|
|
@samp{pragma foreign_proc} declarations may include a list of attributes
|
|
describing properties of the given foreign function or 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 foreign language 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 foreign language code @emph{does} invoke Mercury code,
|
|
then the behaviour is undefined.
|
|
|
|
@item @samp{promise_pure}/@samp{promise_semipure}
|
|
This attribute promises that
|
|
the purity of the given predicate or function definition is pure or semipure.
|
|
It is equivalent to a corresponding @samp{pragma promise_pure}
|
|
or @samp{pragma promise_semipure} declaration (@pxref{Impurity}).
|
|
If omitted, the clause specified by the @samp{foreign_proc}
|
|
is assumed to be impure.
|
|
|
|
@item @samp{thread_safe}/@samp{not_thread_safe}/@samp{maybe_thread_safe}
|
|
This attribute declares whether or not it is safe
|
|
for multiple threads to execute this foreign language code concurrently.
|
|
The default, in case none is specified, is @samp{not_thread_safe}.
|
|
If the foreign language 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 foreign language 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 multithreaded version of the 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 foreign language code shares a single mutex.)
|
|
@c XXX this can cause deadlocks if not_thread_safe foreign language code calls
|
|
@c Mercury which calls foreign language code
|
|
If the foreign language code is declared @samp{maybe_thread_safe}
|
|
then whether the code is considered
|
|
@samp{thread_safe} or @samp{not_thread_safe}
|
|
depends upon a compiler flag.
|
|
This attribute is useful when the thread safety of the foreign code itself
|
|
is conditional.
|
|
The Melbourne Mercury compiler uses the @samp{--maybe-thread-safe} option
|
|
to set the value of the @samp{maybe_thread_safe} attribute.
|
|
@end table
|
|
|
|
Additional attributes which are supported by the Melbourne Mercury compiler
|
|
are as follows:
|
|
|
|
@table @asis
|
|
|
|
@item @samp{tabled_for_io}
|
|
This attribute should be attached to foreign procedures that do I/O.
|
|
It tells the debugger to make calls to the foreign procedure idempotent.
|
|
This allows the debugger to safely retry across such calls
|
|
and also allows safe declarative debugging of code containing such calls.
|
|
For more information,
|
|
see the ``I/O tabling'' section of the Mercury User's Guide.
|
|
If the foreign procedure contains gotos or static variables then the
|
|
@samp{pragma no_inline} directive should also be given.
|
|
Note that currently I/O tabling will only be done
|
|
for foreign procedures that take a pair of I/O state arguments.
|
|
Impure foreign procedures that perform I/O will not be made idempotent,
|
|
even if the tabled_for_io attribute is present.
|
|
Note also that the tabled_for_io attribute
|
|
will likely be replaced in a future release with a more general solution.
|
|
|
|
@item @samp{terminates}/@samp{does_not_terminate}
|
|
This attribute specifies
|
|
the termination properties of the given predicate or function definition.
|
|
It is equivalent to the corresponding @samp{pragma terminates}
|
|
or @samp{pragma does_not_terminate} declaration.
|
|
If omitted, the termination property of the procedure is determined
|
|
by the value of the
|
|
@samp{may_call_mercury}/@samp{will_not_call_mercury} attribute.
|
|
See @ref{Termination analysis} for more details.
|
|
|
|
@item @samp{will_not_throw_exception}
|
|
This attribute promises that the given predicate or function
|
|
will not make calls back to Mercury
|
|
that may result in an exception being thrown.
|
|
It is an error to apply this attribute
|
|
to procedures that have determinism @code{erroneous}.
|
|
This attribute is ignored for code
|
|
that is declared as not making calls back to Mercury
|
|
via the @samp{will_not_call_mercury} attribute.
|
|
Note: predicates or functions that have polymorphic arguments
|
|
but do not explicitly throw an exception,
|
|
via a call to @samp{exception.throw/1} or @samp{require.error/1},
|
|
may still throw exceptions because they may be called
|
|
with arguments whose types have user-defined equality or comparison predicates.
|
|
If these user-defined equality or comparison predicates throw exceptions
|
|
then unifications or comparisons involving these types
|
|
may also throw exceptions.
|
|
As such, we recommend that only implementors of the Mercury system
|
|
use this annotation for polymorphic predicates and functions.
|
|
|
|
@c @item @samp{high_level_backend}
|
|
@c The foreign_proc will apply only on the high level backend.
|
|
@c @item @samp{low_level_backend}
|
|
@c The foreign_proc will apply only on the low level backend.
|
|
|
|
@item @samp{will_not_modify_trail/may_modify_trail}
|
|
This attribute declares whether or not
|
|
a foreign procedure modifies the trail (see @ref{Trailing}).
|
|
Specifying that a foreign procedure will not modify the trail
|
|
may allow the compiler to generate more efficient code for that procedure.
|
|
In compilation grades that do not support trailing, this attribute is ignored.
|
|
The default, in case none is specified, is @samp{may_modify_trail}.
|
|
|
|
@item @samp{will_not_call_mm_tabled/may_call_mm_tabled}
|
|
This attribute declares whether or not
|
|
a foreign procedure makes calls back to Mercury procedures
|
|
that are evaluated using minimal model tabling
|
|
(@pxref{Tabled evaluation}).
|
|
Specifying that a foreign procedure will not call
|
|
procedures evaluated using minimal model tabling
|
|
may allow the compiler to generate more efficient code.
|
|
In compilation grades that do not support minimal model tabling,
|
|
this attribute is ignored.
|
|
These attributes may not be used with procedures
|
|
that do not make calls back to Mercury,
|
|
i.e.@: that have the @samp{will_not_call_mercury} attribute.
|
|
The default for foreign procedures that @samp{may_call_mercury},
|
|
in case none is specified, is
|
|
@samp{may_call_mm_tabled}.
|
|
|
|
@item @samp{affects_liveness/does_not_affect_liveness}
|
|
This attribute declares whether or not a foreign procedure
|
|
uses and/or modifies any part of the Mercury virtual machine
|
|
(registers, stack slots)
|
|
through means other than its arguments.
|
|
The @samp{affects_liveness} attribute says that it does;
|
|
The @samp{does_not_affect_liveness} attribute says that it does not.
|
|
In the absence of either attribute,
|
|
the compiler assumes @samp{affects_liveness},
|
|
unless the code of the foreign_proc in question is empty.
|
|
|
|
@item @samp{may_duplicate/may_not_duplicate}
|
|
This attribute tells the compiler
|
|
whether it is allowed to duplicate the foreign code fragment
|
|
through optimizations such as inlining.
|
|
The @samp{may_duplicate} attribute says that it may;
|
|
the @samp{may_not_duplicate} attribute says that it may not.
|
|
In the absence of either attribute,
|
|
the compiler is allowed make its own judgement in the matter,
|
|
based on factors such as the size of the code fragment.
|
|
|
|
@item @samp{may_export_body/may_not_export_body}
|
|
This attribute tells the compiler
|
|
whether it is allowed to duplicate the foreign code fragment
|
|
outside of the target file for the module that
|
|
defines the foreign procedure.
|
|
The @samp{may_export_body} attribute says that it may;
|
|
the @samp{may_not_export_body} attribute says that it may not.
|
|
The default is @samp{may_export_body}.
|
|
|
|
@c @item
|
|
@c @samp{does_not_allocate_memory/allocates_bounded_memory/allocates_unbounded_memory}
|
|
@c This attribute declares whether a foreign procedure
|
|
@c allocates any memory on the Mercury heap,
|
|
@c and if it does, whether the amount allocated
|
|
@c is guaranteed to be smaller than the bound given
|
|
@c by the reserve space of the native garbage collector.
|
|
|
|
@c @item
|
|
@c @samp{registers_roots/does_not_register_roots/does_not_have_roots}
|
|
@c This attribute declares whether a foreign procedure
|
|
@c registers with the native garbage collector
|
|
@c all the root pointers it accesses.
|
|
@c This must always include
|
|
@c all global variables maintained by the foreign procedure.
|
|
@c If the foreign procedure may call Mercury,
|
|
@c it must also include any storage location in which
|
|
@c the foreign procedure stores roots before any call to Mercury
|
|
@c (since a gc may take place during such a call).
|
|
|
|
@c @item @samp{no_sharing/unknown_sharing/sharing(MaybeTypes, SharingList)}
|
|
@c This attribute declares whether or not a foreign procedure creates any
|
|
@c structure sharing @ref{Structure sharing analysis} between its input
|
|
@c and output arguments.
|
|
@c Specifying that a foreign
|
|
@c procedure generates no sharing (attribute @samp{no_sharing}) is a promise
|
|
@c to the compiler that the procedure does not create any sharing
|
|
@c between its arguments. The attribute @samp{unknown_sharing} specifies
|
|
@c that the
|
|
@c procedure may create any possible sharing between the arguments.
|
|
@c Finally, using
|
|
@c @samp{sharing(MaybeTypes, SharingList)} it is possible to specify a list of
|
|
@c sharing arguments, declaring that the foreign procedure creates at most
|
|
@c the specified sharing between the arguments. @samp{MaybeTypes} takes
|
|
@c the values
|
|
@c @samp{no/yes(Types)}, where @samp{Types} corresponds to the types used in
|
|
@c the predicate or function declaration for this foreign procedure.
|
|
@c @samp{SharingList} consists of a list
|
|
@c @samp{[SharingPairA, SharingPairB, ...]}, where each sharing pair
|
|
@c is represented by a pair @samp{cel(Vari, Seli) - cel(Varj, Selj)}.
|
|
@c @samp{Vari, Varj} must be variables that are part of the mode declaration
|
|
@c of the @samp{foreign_proc} definition. @samp{Seli, Selj} select
|
|
@c the subterms of the given arguments that actually share. Each selector
|
|
@c @samp{Seli} is written as a list of types @samp{[Type1, Type2, ...]}
|
|
@c representing a path in the term structure of the given argument. An
|
|
@c empty list designates the complete term to which the argument corresponds.
|
|
@c The types can make use of type variables as long as @samp{MaybeTypes} is
|
|
@c set to @samp{yes(Types)}, and the type variables occur in any of the types
|
|
@c used in @samp{Types}.
|
|
@c
|
|
@c @example
|
|
@c :- pred array.init_2(int::in, T::in, array(T)::array_uo) is det.
|
|
@c
|
|
@c :- pragma foreign_proc("C",
|
|
@c array.init_2(Size::in, Item::in, Array::array_uo),
|
|
@c [will_not_call_mercury, promise_pure, thread_safe, will_not_modify_trail,
|
|
@c sharing(yes(int, T, array(T)), [cel(Item,[]) - cel(Array,[T])])],
|
|
@c "
|
|
@c ML_alloc_array(Array, Size + 1, MR_ALLOC_ID);
|
|
@c ML_init_array(Array, Size, Item);
|
|
@c ").
|
|
@c @end example
|
|
@c
|
|
@c This sharing declaration promises that a call
|
|
@c @code{init_2(Size, Item, Array)}, with types @code{int, T, array(T)}
|
|
@c may create sharing between any
|
|
@c subterms of type @code{T} of the resulting array @code{Array} and the
|
|
@c term @code{Item}. Reformulated: the elements of @code{Array} may refer
|
|
@c to the same memory locations as @code{Item}.
|
|
|
|
@end table
|
|
|
|
@c -----------------------------------------------------------------------
|
|
|
|
@node Calling Mercury from foreign code
|
|
@section Calling Mercury from foreign code
|
|
|
|
Mercury procedures may be exported
|
|
so that they can be called by code written in a foreign language.
|
|
|
|
A declaration of the form:
|
|
|
|
@example
|
|
:- pragma foreign_export("@var{Lang}",
|
|
@var{Pred}(@var{Mode1}, @var{Mode2}, @dots{}), "@var{ForeignName}").
|
|
@end example
|
|
|
|
@noindent
|
|
or
|
|
|
|
@example
|
|
:- pragma foreign_export("@var{Lang}",
|
|
@var{Func}(@var{Mode1}, @var{Mode2}, @dots{}) = @var{Mode},
|
|
"@var{ForeignName}").
|
|
@end example
|
|
|
|
@noindent
|
|
exports a procedure for use by foreign language @var{Lang}.
|
|
For each exported procedure,
|
|
the Mercury implementation will create an interface
|
|
to the named Mercury procedure in the foreign language
|
|
using the name @var{ForeignName}.
|
|
The form of this interface is dependent upon the specified foreign language.
|
|
For further details see the language specific information below.
|
|
|
|
It is an error to export a Mercury procedure
|
|
that has a determinism of @code{multi} or @code{nondet}.
|
|
|
|
@c -----------------------------------------------------------------------
|
|
|
|
@node Data passing conventions
|
|
@section Data passing conventions
|
|
|
|
For each supported foreign language,
|
|
we explain how to map a Mercury type to a type in that foreign language.
|
|
We also map the Mercury parameter passing convention
|
|
to the foreign language's parameter passing convention.
|
|
|
|
@menu
|
|
* C data passing conventions ::
|
|
* C# data passing conventions ::
|
|
* Java data passing conventions ::
|
|
@end menu
|
|
|
|
@node C data passing conventions
|
|
@subsection C data passing conventions
|
|
|
|
The Mercury primitive types are mapped to the following C types:
|
|
|
|
@multitable {Mercury_type} {MR_Unsigned}
|
|
@headitem Mercury type @tab C type
|
|
@item @code{int} @tab @code{MR_Integer}
|
|
@item @code{int8} @tab @code{int8_t}
|
|
@item @code{int16} @tab @code{int16_t}
|
|
@item @code{int32} @tab @code{int32_t}
|
|
@item @code{int64} @tab @code{int64_t}
|
|
@item @code{uint} @tab @code{MR_Unsigned}
|
|
@item @code{uint8} @tab @code{uint8_t}
|
|
@item @code{uint16} @tab @code{uint16_t}
|
|
@item @code{uint32} @tab @code{uint32_t}
|
|
@item @code{uint64} @tab @code{uint64_t}
|
|
@item @code{float} @tab @code{MR_Float}
|
|
@item @code{char} @tab @code{MR_Char}
|
|
@item @code{string} @tab @code{MR_String}
|
|
@end multitable
|
|
|
|
In the current implementation,
|
|
@code{MR_Integer} is a typedef for a signed integral type
|
|
which is the same size as a pointer of type @samp{void *};
|
|
@code{MR_Unsigned} is a typedef for an unsigned integral type
|
|
which is the same size as a pointer of type @samp{void *};
|
|
@code{MR_Float} is a typedef for @code{double}
|
|
(unless the program and the Mercury library
|
|
was compiled with @samp{--single-prec-float},
|
|
in which case it is a typedef for @code{float});
|
|
@code{MR_Char} is a typedef for a signed 32-bit integral type
|
|
and @code{MR_String} is a typedef for @samp{char *}.
|
|
|
|
Mercury variables of primitive types are passed to and from C
|
|
as C variables of the corresponding C type.
|
|
|
|
For the Mercury standard library type @samp{bool.bool},
|
|
there is a corresponding C type, @code{MR_Bool}.
|
|
C code can refer to the boolean data constructors @samp{yes} and @samp{no},
|
|
as @code{MR_YES} and @code{MR_NO} respectively.
|
|
|
|
For the Mercury standard library type @samp{builtin.comparison_result},
|
|
there is a corresponding C type, @code{MR_Comparison_Result}.
|
|
C code can refer to the data constructors of this type,
|
|
@samp{(<)}, @samp{(=)} and @samp{(>)},
|
|
as @code{MR_COMPARE_LESS}, @code{MR_COMPARE_EQUAL}
|
|
and @code{MR_COMPARE_GREATER} respectively.
|
|
|
|
Mercury variables of a type
|
|
for which there is a C @samp{pragma foreign_type} declaration
|
|
(@pxref{Using foreign types from Mercury})
|
|
will be passed as the corresponding C type.
|
|
|
|
Mercury tuple types are passed as @code{MR_Tuple},
|
|
which in the current implementation is a typedef
|
|
for a pointer of type @samp{void *} if @samp{--high-level-code} is enabled,
|
|
and a typedef for @code{MR_Word} otherwise.
|
|
|
|
Mercury variables of any other type are passed as a @code{MR_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 for C}).
|
|
|
|
The implementation provides the macro @code{MR_word_to_float}
|
|
for converting a value of type @code{MR_Word} to one of type @code{MR_Float},
|
|
and the macro @code{MR_float_to_word}
|
|
for converting a value of type @code{MR_Float} to one of type @code{MR_Word}.
|
|
These macros must be used to perform these conversions
|
|
since for some Mercury implementations
|
|
@samp{sizeof(MR_Float)} is greater than @samp{sizeof(MR_Word)}.
|
|
|
|
The following fragment of C code illustrates
|
|
the correct way to extract the head of a Mercury list of floats.
|
|
|
|
@example
|
|
MR_Float f;
|
|
f = MR_word_to_float(MR_list_head(list));
|
|
@end example
|
|
|
|
Omitting the call to @code{MR_word_to_float} in the above example
|
|
would yield incorrect results for implementations
|
|
where @samp{sizeof(MR_Float)} is greater than @samp{sizeof(MR_Word)}.
|
|
|
|
Similarly, the implementation provides
|
|
the macros @code{MR_word_to_int64} and @code{MR_word_to_uint64}
|
|
for converting values of type @code{MR_Word}
|
|
to ones of type @code{int64_t} or @code{uint64_t} respectively,
|
|
and the macros @code{MR_int64_to_word} and @code{MR_uint64_to_word}
|
|
for converting values of type @code{int64_t} or @code{uint64_t} respectively
|
|
to ones of type @code{MR_Word}.
|
|
These macros must be used to perform these conversions
|
|
since for some Mercury implementations
|
|
@samp{sizeof(int64_t)} or @samp{sizeof(uint64_t)}
|
|
are greater than @samp{sizeof(MR_Word)}.
|
|
|
|
@node C# data passing conventions
|
|
@subsection C# data passing conventions
|
|
|
|
The Mercury primitive types are mapped
|
|
to the following Common Language Infrastructure (CLI) and C# types:
|
|
|
|
@multitable {Mercury_type} {System_String} {double}
|
|
@headitem Mercury type @tab CLI type @tab C# type
|
|
@item @code{int} @tab @code{System.Int32} @tab @code{int}
|
|
@item @code{int8} @tab @code{System.Int8} @tab @code{sbyte}
|
|
@item @code{int16} @tab @code{System.Int16} @tab @code{short}
|
|
@item @code{int32} @tab @code{System.Int32} @tab @code{int}
|
|
@item @code{int64} @tab @code{System.Int64} @tab @code{long}
|
|
@item @code{uint} @tab @code{System.UInt32} @tab @code{uint}
|
|
@item @code{uint8} @tab @code{System.UInt8} @tab @code{byte}
|
|
@item @code{uint16} @tab @code{System.UInt16} @tab @code{ushort}
|
|
@item @code{uint32} @tab @code{System.UInt32} @tab @code{uint}
|
|
@item @code{uint64} @tab @code{System.UInt64} @tab @code{ulong}
|
|
@item @code{float} @tab @code{System.Double} @tab @code{double}
|
|
@item @code{char} @tab @code{System.Int32} @tab @code{int}
|
|
@item @code{string} @tab @code{System.String} @tab @code{string}
|
|
@end multitable
|
|
|
|
Note that the Mercury type @code{char} is mapped like @code{int};
|
|
@emph{not} to the CLI type @code{System.Char}
|
|
because that only holds 16-bit numeric values.
|
|
|
|
For the Mercury standard library type @samp{bool.bool},
|
|
there is a corresponding C# type, @code{mr_bool.Bool_0}.
|
|
C# code can refer to the boolean data constructors @samp{yes} and @samp{no},
|
|
as @code{mr_bool.YES} and @code{mr_bool.NO} respectively.
|
|
|
|
For the Mercury standard library type @samp{builtin.comparison_result},
|
|
there is a corresponding C# type, @code{builtin.Comparison_result_0}.
|
|
C# code can refer to the data constructors of this type,
|
|
@samp{(<)}, @samp{(=)} and @samp{(>)},
|
|
as @code{builtin.COMPARE_LESS}, @code{builtin.COMPARE_EQUAL}
|
|
and @code{builtin.COMPARE_GREATER} respectively.
|
|
|
|
Mercury variables of a type
|
|
for which there is a C# @samp{pragma foreign_type} declaration
|
|
(@pxref{Using foreign types from Mercury})
|
|
will be passed as the corresponding C# type.
|
|
Both reference and value types are supported.
|
|
|
|
Mercury tuple types are passed as @samp{object[]}
|
|
where the length of the array is the number of elements in the tuple.
|
|
|
|
Mercury variables whose type is a type variable
|
|
will be passed as @code{System.Object}.
|
|
|
|
Mercury variables whose type is a Mercury discriminated union type
|
|
will be passed as a CLI type
|
|
whose type name is determined from the Mercury type name
|
|
(ignoring any type parameters) followed by an underscore
|
|
and then the type arity, expressed as a decimal integer.
|
|
The first character of the type name will have its case inverted,
|
|
and the name may be mangled to satisfy C# lexical rules.
|
|
|
|
@noindent
|
|
For example, the following Mercury type
|
|
corresponds to the C# class that follows (some implementation details elided):
|
|
|
|
@example
|
|
:- type maybe(T)
|
|
---> yes(yes_field :: T)
|
|
; no.
|
|
|
|
public static class Maybe_1 @{
|
|
public static class Yes_1 : Maybe_1 @{
|
|
public object yes_field;
|
|
public Yes_1(object x) @{ @dots{} @}
|
|
@}
|
|
public static class No_0 : Maybe_1 @{
|
|
public No_0() @{ @dots{} @}
|
|
@}
|
|
@}
|
|
@end example
|
|
|
|
C# code generated by the Mercury compiler
|
|
is placed in the @samp{mercury} namespace.
|
|
Mercury module qualifiers are converted into a C# class name
|
|
by concatenating the components with double underscore separators (@samp{__}).
|
|
For example the Mercury type @samp{foo.bar.baz/1} will be passed
|
|
as the C# type @samp{mercury.foo__bar.Baz_1}.
|
|
|
|
Mercury array types are mapped to @code{System.Array}.
|
|
|
|
Mercury variables whose type is a Mercury equivalence type
|
|
will be passed as the representation
|
|
of the right hand side of the equivalence type.
|
|
|
|
This mapping is subject to change
|
|
and you should try to avoid writing code
|
|
that relies heavily upon a particular representation of Mercury terms.
|
|
|
|
Mercury arguments declared with input modes
|
|
are passed by value to the C# function.
|
|
|
|
Arguments of type @samp{io.state} or @samp{store.store(_)}
|
|
are not passed or returned at all.
|
|
(The reason for this is that these types represent mutable state,
|
|
and in C# modifications to mutable state are done via side effects,
|
|
rather than argument passing.)
|
|
|
|
The handling of multiple output arguments is as follows.
|
|
|
|
If the Mercury procedure is deterministic and has no output arguments,
|
|
then the return type of the C# function is @samp{void};
|
|
if it has one output argument,
|
|
then the return value of the function is that output argument.
|
|
|
|
If the Mercury procedure is deterministic and has two or more output arguments,
|
|
then the return type of the C# function is @samp{void}.
|
|
At the position of each output argument,
|
|
the C# function has an @samp{out} parameter.
|
|
|
|
If the Mercury procedure is semi-deterministic
|
|
then the C# function returns a @samp{bool}.
|
|
A @samp{true} return value denotes success and @samp{false} denotes failure.
|
|
Output arguments are handled in the same way
|
|
as multiple outputs for deterministic procedures,
|
|
using @samp{out} parameters.
|
|
On failure the values of the @samp{val} fields are undefined.
|
|
|
|
Mercury lists can be manipulated by C# code using the following methods,
|
|
which are defined by the Mercury implementation.
|
|
|
|
@example
|
|
bool list.is_empty(List_1 list) // test if a list is empty
|
|
object list.det_head(List_1 list) // get the head of a list
|
|
List_1 list.det_tail(List_1 list) // get the tail of a list
|
|
List_1 list.empty_list() // create an empty list
|
|
List_1 list.cons(object head, List_1 tail)
|
|
// construct a list with
|
|
// the given head and tail
|
|
@end example
|
|
|
|
@node Java data passing conventions
|
|
@subsection Java data passing conventions
|
|
|
|
The Mercury primitive types are mapped to the following Java types:
|
|
@multitable {Mercury_type} {java_lang_String}
|
|
@headitem Mercury type @tab Java type
|
|
@item @code{int} @tab @code{int}
|
|
@item @code{int8} @tab @code{byte}
|
|
@item @code{int16} @tab @code{short}
|
|
@item @code{int32} @tab @code{int}
|
|
@item @code{int64} @tab @code{long}
|
|
@item @code{uint} @tab @code{int}
|
|
@item @code{uint8} @tab @code{byte}
|
|
@item @code{uint16} @tab @code{short}
|
|
@item @code{uint32} @tab @code{int}
|
|
@item @code{uint64} @tab @code{long}
|
|
@item @code{float} @tab @code{double}
|
|
@item @code{char} @tab @code{int}
|
|
@item @code{string} @tab @code{java.lang.String}
|
|
@end multitable
|
|
|
|
Note that since Java lacks unsigned integer types,
|
|
Mercury's unsigned integer types correspond to signed integer types in Java.
|
|
|
|
Also, note that the Mercury type @code{char} is mapped like @code{int};
|
|
@emph{not} to the Java type @code{char}
|
|
because that only holds 16-bit numeric values.
|
|
|
|
For the Mercury standard library type @samp{bool.bool},
|
|
there is a corresponding Java type, @code{bool.Bool_0}.
|
|
Java code can refer to the boolean data constructors @samp{yes} and @samp{no},
|
|
as @code{bool.YES} and @code{bool.NO} respectively.
|
|
|
|
For the Mercury standard library type @samp{builtin.comparison_result},
|
|
there is a corresponding Java type, @code{builtin.Comparison_result_0}.
|
|
Java code can refer to the data constructors of this type,
|
|
@samp{(<)}, @samp{(=)} and @samp{(>)},
|
|
as @code{builtin.COMPARE_LESS}, @code{builtin.COMPARE_EQUAL}
|
|
and @code{builtin.COMPARE_GREATER} respectively.
|
|
|
|
Mercury variables of a type
|
|
for which there is a Java @samp{pragma foreign_type} declaration
|
|
(@pxref{Using foreign types from Mercury})
|
|
will be passed as the corresponding Java type.
|
|
|
|
Mercury tuple types are passed as @code{java.lang.Object[]}
|
|
where the length of the array is the number of elements in the tuple.
|
|
|
|
Mercury variables whose types are universally quantified type variables
|
|
will have generic types.
|
|
Mercury variables whose types are existentially quantified type variables
|
|
will be passed as @code{java.lang.Object}.
|
|
|
|
Mercury variables whose type is a Mercury discriminated union type
|
|
will be passed as a Java type
|
|
whose type name is determined from the Mercury type name
|
|
(ignoring any type parameters) followed by an underscore
|
|
and then the type arity, expressed as a decimal integer.
|
|
The first character of the type name will have its case inverted,
|
|
and the name may be mangled to satisfy Java lexical rules.
|
|
Generics are used in the Java type for any type parameters.
|
|
|
|
@noindent
|
|
For example, the following Mercury type
|
|
corresponds to the Java class that follows
|
|
(some implementation details elided):
|
|
|
|
@example
|
|
:- type maybe(T)
|
|
---> yes(yes_field :: T)
|
|
; no.
|
|
|
|
public static class Maybe_1<T> @{
|
|
public static class Yes_1<T> extends Maybe_1 @{
|
|
public T yes_field;
|
|
public Yes_1(T x) @{ @dots{} @}
|
|
@}
|
|
public static class No_0<T> extends Maybe_1 @{
|
|
public No_0() @{ @dots{} @}
|
|
@}
|
|
@}
|
|
@end example
|
|
|
|
Java code generated by the Mercury compiler
|
|
is placed in the @samp{jmercury} package.
|
|
Mercury module qualifiers are converted into a Java class name
|
|
by concatenating the components with double underscore separators (@samp{__}).
|
|
For example the Mercury type @samp{foo.bar.baz/1}
|
|
will be passed as the Java type @samp{jmercury.foo__bar.Baz_1}.
|
|
|
|
Mercury array types are mapped to Java array types.
|
|
|
|
Mercury variables whose type is a Mercury equivalence type will be passed
|
|
as the representation of the right hand side of the equivalence type.
|
|
|
|
This mapping is subject to change and you should try to avoid writing code
|
|
that relies heavily upon a particular representation of Mercury terms.
|
|
|
|
Mercury arguments declared with input modes
|
|
are passed by value to the corresponding Java function.
|
|
If the Mercury procedure is a function whose result has an input mode,
|
|
then the Mercury function result is appended to the list of input parameters,
|
|
so that the Mercury function result
|
|
becomes the last parameter to the corresponding Java function.
|
|
|
|
Arguments of type @samp{io.state} or @samp{store.store(_)}
|
|
are not passed or returned at all.
|
|
(The reason for this is that these types represent mutable state,
|
|
and in Java modifications to mutable state are done via side effects,
|
|
rather than argument passing.)
|
|
|
|
The handling of multiple output arguments is as follows.
|
|
|
|
If the Mercury procedure is deterministic and has no output arguments,
|
|
then the return type of the Java function is @code{void};
|
|
if it has one output argument,
|
|
then the return value of the function is that output argument.
|
|
|
|
If the Mercury procedure is deterministic and has two or more output arguments,
|
|
then the return type of the Java function is @code{void}.
|
|
At the position of each output argument,
|
|
the Java function takes a value of the type @samp{jmercury.runtime.Ref<T>}
|
|
where @samp{T} is the Java type
|
|
corresponding to the type of the output argument.
|
|
@samp{Ref} is a class with a single field @samp{val},
|
|
which is assigned the output value when the function returns.
|
|
|
|
If the Mercury procedure is semi-deterministic,
|
|
then the Java function returns a @samp{boolean}.
|
|
A @samp{true} return value denotes success and @samp{false} denotes failure.
|
|
Output arguments are handled in the same way
|
|
as multiple outputs for deterministic procedures, using the @samp{Ref} class.
|
|
On failure the values of the @samp{val} fields are undefined.
|
|
|
|
Mercury lists can be manipulated by Java code using the following methods,
|
|
which are defined by the Mercury implementation.
|
|
|
|
@example
|
|
boolean list.is_empty(List_1<E> list) // test if a list is empty
|
|
E list.det_head(List_1<E> list) // get the head of a list
|
|
List_1<E> list.det_tail(List_1<E> list) // get the tail of a list
|
|
List_1<E> list.empty_list() // create an empty list
|
|
<E, F extends E> List_1<E> list.cons(F head, List_1<E> tail)
|
|
// construct a list with
|
|
// the given head and tail
|
|
@end example
|
|
|
|
@c -----------------------------------------------------------------------
|
|
|
|
@node Using foreign types from Mercury
|
|
@section Using foreign types from Mercury
|
|
|
|
Types defined in a foreign language can be accessed in Mercury
|
|
using a declaration of the form
|
|
|
|
@example
|
|
:- pragma foreign_type(@var{Lang}, @var{MercuryTypeName}, @var{ForeignTypeDescriptor}).
|
|
@end example
|
|
|
|
This defines @var{MercuryTypeName}
|
|
as a synonym for type @var{ForeignTypeDescriptor}
|
|
defined in the foreign language @var{Lang}.
|
|
@var{MercuryTypeName} must be the name of
|
|
either an abstract type or a discriminated union type.
|
|
In both cases,
|
|
@var{MercuryTypeName} must be declared with @samp{:- type} as usual.
|
|
The @samp{pragma foreign_type} must not have wider visibility
|
|
than the type declaration
|
|
(if the @samp{pragma foreign_type} declaration is in the interface,
|
|
the @samp{:- type} declaration must be also).
|
|
|
|
If @var{MercuryTypeName} names a discriminated union type,
|
|
that type cannot be the base type of any subtypes,
|
|
nor can it be a subtype itself (@pxref{Subtypes}).
|
|
|
|
@var{ForeignTypeDescriptor} defines
|
|
how the Mercury type is mapped for a particular foreign language.
|
|
Specific syntax is given in the language specific information below.
|
|
|
|
@var{MercuryTypeName} is treated as an abstract type
|
|
at all times in Mercury code.
|
|
However, if @var{MercuryTypeName}
|
|
is one of the parameters of a foreign_proc for @var{Lang},
|
|
and the @samp{pragma foreign_type} declaration is visible to the foreign_proc,
|
|
it will be passed to that foreign_proc
|
|
as specified by @var{ForeignTypeDescriptor}.
|
|
|
|
The same type may have a foreign language definition
|
|
for more than one foreign language.
|
|
The definition used in the generated code
|
|
will be the one for the foreign language
|
|
that is most appropriate for the target language of the compilation
|
|
(see the language specific information below for details).
|
|
All the foreign language definitions must have the same visibility.
|
|
|
|
A type which has one or more foreign language definitions
|
|
may also have a Mercury definition,
|
|
which must define a discriminated union type.
|
|
The constructors for this Mercury type will only be visible in Mercury clauses
|
|
for predicates or functions with @samp{pragma foreign_proc} clauses
|
|
for all of the languages for which there are
|
|
@samp{foreign_type} declarations for the type.
|
|
|
|
You can also associate assertions about the properties of the foreign type
|
|
with the @samp{foreign_type} declaration, using the following syntax:
|
|
|
|
@example
|
|
:- pragma foreign_type(@var{Lang}, @var{MercuryTypeName}, @var{ForeignTypeDescriptor},
|
|
[@var{ForeignTypeAssertion}, @dots{}]).
|
|
@end example
|
|
|
|
Currently, three kinds of assertions are supported.
|
|
|
|
The @samp{can_pass_as_mercury_type} assertion
|
|
states that on the C backends, values of the given type
|
|
can be passed to and from Mercury code without boxing,
|
|
via simple casts, which is faster.
|
|
This requires the type to be either an integer type or a pointer type,
|
|
and requires it to be castable to @samp{MR_Word} and back
|
|
without loss of information
|
|
(which means that its size may not be greater than the size of @samp{MR_Word}).
|
|
|
|
The @samp{word_aligned_pointer} assertion implies
|
|
@samp{can_pass_as_mercury_type} and additionally states that values of the
|
|
given type are pointer values clear in the tag bits.
|
|
It allows the Mercury implementation to avoid boxing values of the given type
|
|
when the type appears as the sole argument of a data constructor.
|
|
|
|
The @samp{stable} assertion is meaningful
|
|
only in the presence of the @samp{can_pass_as_mercury_type}
|
|
or @samp{word_aligned_pointer} assertions.
|
|
It states that either the C type is an integer type,
|
|
or it is a pointer type pointing to memory that will never change.
|
|
Together, these assertions are sufficient to allow
|
|
tabling (@pxref{Tabled evaluation})
|
|
and the @samp{compare_representation} primitive
|
|
to work on values of such types.
|
|
|
|
Violations of any of these assertions are very likely to result
|
|
in the generated executable silently doing the wrong thing,
|
|
giving no clue to where the problem might be.
|
|
Since deciding whether a C type satisfies the conditions of these assertions
|
|
requires knowledge of the internals of the Mercury implementation,
|
|
we do not recommend the use of any of these assertions
|
|
unless you are confident of your expertise in those internals.
|
|
|
|
As with discriminated union types,
|
|
programmers can specify the unification @w{and/or} comparison predicates
|
|
to use for values of the type using the following syntax
|
|
(@pxref{User-defined equality and comparison}):
|
|
|
|
@example
|
|
:- pragma foreign_type(@var{Lang}, @var{MercuryTypeName}, @var{ForeignTypeDescriptor})
|
|
where equality is @var{EqualityPred}, comparison is @var{ComparePred}.
|
|
@end example
|
|
|
|
You can use Mercury foreign language interfacing declarations
|
|
which specify language @var{X} to interface to types
|
|
that are actually written in a different language @var{Y},
|
|
provided that @var{X} and @var{Y} have compatible interface conventions.
|
|
Support for this kind of compatibility
|
|
is described in the language specific information below.
|
|
|
|
@c -----------------------------------------------------------------------
|
|
|
|
@node Using foreign enumerations in Mercury code
|
|
@section Using foreign enumerations in Mercury code
|
|
|
|
While a @samp{pragma foreign_type} declaration
|
|
imports a foreign @emph{type} into Mercury,
|
|
a @samp{pragma foreign_enum} declaration
|
|
imports @emph{the values of the constants of an enumeration type} into Mercury.
|
|
|
|
While languages such as C have special syntax for defining enumeration types,
|
|
in Mercury, an enumeration type is simply an ordinary discriminated union type
|
|
whose function symbols all have arity zero.
|
|
|
|
Given an enumeration type such as
|
|
@example
|
|
:- type unix_file_permissions
|
|
---> user_read
|
|
; user_write
|
|
; user_executable
|
|
; group_read
|
|
; group_write
|
|
; group_executable
|
|
; other_read
|
|
; other_write
|
|
; other_executable.
|
|
@end example
|
|
|
|
the values used to represent each constant
|
|
are usually decided by the Mercury compiler.
|
|
However, the values assigned this way
|
|
may not match the values expected by foreign language code
|
|
that uses values of the enumeration,
|
|
and even if they happen to match,
|
|
programmers probably would not want to @emph{rely} on this coincidence.
|
|
|
|
This is why Mercury supports a mechanism that allows programmers
|
|
to specify the representation of each constant in an enumeration type
|
|
when generating code for a given target language.
|
|
This mechanism is the @samp{pragma foreign_enum} declaration,
|
|
which looks like this:
|
|
|
|
@example
|
|
@group
|
|
:- pragma foreign_enum("C", unix_file_permissions/0,
|
|
[
|
|
user_read - "S_IRUSR",
|
|
user_write - "S_IWUSR",
|
|
user_executable - "S_IXUSR",
|
|
group_read - "S_IRGRP",
|
|
group_write - "S_IWGRP",
|
|
group_executable - "S_IXGRP",
|
|
other_read - "S_IROTH",
|
|
other_write - "S_IWOTH",
|
|
other_executable - "S_IXOTH"
|
|
]).
|
|
@end group
|
|
@end example
|
|
|
|
(Unix systems have a standard header file
|
|
that defines each of @samp{S_IRUSR}, @dots{}, @samp{S_IXOTH}
|
|
as macros that each expand to an integer constant;
|
|
these constants happen @emph{not} to be the ones
|
|
that the Mercury compiler would assign to those constants.)
|
|
|
|
The general form of @samp{pragma foreign_enum} declarations is
|
|
|
|
@example
|
|
:- pragma foreign_enum("@var{Lang}", @var{MercuryType}, @var{CtorValues}).
|
|
@end example
|
|
|
|
where @var{CtorValues} is a list of pairs of the form:
|
|
|
|
@example
|
|
@group
|
|
[
|
|
ctor_0 - "ForeignValue_0",
|
|
ctor_1 - "ForeignValue_1",
|
|
@dots{}
|
|
ctor_N - "ForeignValue_N"
|
|
]
|
|
@end group
|
|
@end example
|
|
|
|
The first element of each pair
|
|
is a constant (function symbol of arity 0) of the type @var{MercuryType},
|
|
and the second is either a numeric or a symbolic name
|
|
for the integer value in the language @var{Lang}
|
|
that the programmer wants to be used to represent that constructor.
|
|
|
|
The mapping defined by this list of pairs must form a bijection,
|
|
i.e.@: the list must map distinct constructors to distinct values,
|
|
and vice versa.
|
|
The Mercury compiler is not required to check this, because it cannot;
|
|
even if two symbolic names (such as C macros) are distinct,
|
|
they may expand to the same integer in the target language.
|
|
|
|
Mercury implementations may impose
|
|
further foreign-language-specific restrictions
|
|
on the form that values used to represent enumeration constructors may take.
|
|
See the language specific information below for details.
|
|
|
|
It is an error for any given @var{MercuryType}
|
|
to be the subject of more than one @samp{pragma foreign_enum} declaration
|
|
for any given foreign language,
|
|
since that would amount to an attempt
|
|
to specify two or more (probably) conflicting representations
|
|
for each of the type's function symbols.
|
|
|
|
@c XXX we need to specify a behaviour when there are multiple supported
|
|
@c foreign languages.
|
|
|
|
A @samp{pragma foreign_enum} declaration must occur in the implementation
|
|
section of the module that defines the type @var{MercuryType}.
|
|
Because of this, the names of the constants
|
|
need not and must not be module qualified.
|
|
|
|
Note that the default comparison for types
|
|
that are the subject of a @samp{pragma foreign_enum} declaration
|
|
will be defined by the foreign values,
|
|
rather than the order of the constructors in the type declaration
|
|
(as would otherwise be the case).
|
|
|
|
@c -----------------------------------------------------------------------
|
|
|
|
@node Using Mercury enumerations in foreign code
|
|
@section Using Mercury enumerations in foreign code
|
|
|
|
A @samp{pragma foreign_enum} declaration
|
|
imports the values of the constants of an enumeration type into Mercury.
|
|
However, sometimes one needs the reverse:
|
|
the ability to @emph{export}
|
|
the values of the constants of an enumeration type
|
|
(whether those values were assigned by @samp{foreign_enum} pragmas or not)
|
|
from Mercury to foreign language code in
|
|
@samp{foreign_proc} and @samp{foreign_code} pragmas.
|
|
This is what @samp{pragma foreign_export_enum} declarations are for.
|
|
|
|
These pragmas have the following general form:
|
|
|
|
@example
|
|
:- pragma foreign_export_enum("@var{Lang}", @var{MercuryType},
|
|
@var{Attributes}, @var{Overrides}).
|
|
@end example
|
|
|
|
When given such a pragma,
|
|
the compiler will define a symbolic name in language @var{Lang}
|
|
for each of the constructors of @var{MercuryType}
|
|
(which must be an enumeration type).
|
|
Each symbolic name allows code in that foreign language
|
|
to create a value corresponding to that of the constructor it represents.
|
|
(The exact mechanism used depends upon the foreign language;
|
|
see the language specific information below for further details.)
|
|
|
|
For each foreign language,
|
|
there is a default mapping between the name of a Mercury constructor
|
|
and its symbolic name in the language @var{Lang}.
|
|
This default mapping is not required to map
|
|
every valid constructor name to a valid name in language @var{Lang};
|
|
where it does not, the programmer must specify a valid symbolic name.
|
|
The programmer may also choose to map a constructor to a symbolic name
|
|
that differs from the one supplied
|
|
by the default mapping for language @var{Lang}.
|
|
@var{Overrides} is a list
|
|
whose elements are pairs of constructor names and strings.
|
|
The latter specify the name that the implementation should use
|
|
as the symbolic name in the foreign language.
|
|
@var{Overrides} has the following form:
|
|
|
|
@example
|
|
[cons_I - "symbol_I", @dots{}, cons_J - "symbol_J"]
|
|
@end example
|
|
|
|
This can be used to provide
|
|
either a valid symbolic name where the default mapping does not,
|
|
or to override a valid symbolic name generated by the default mapping.
|
|
This argument may be omitted if @var{Overrides} is empty.
|
|
|
|
The argument @var{Attributes} is a list of optional attributes.
|
|
If empty,
|
|
it may be omitted from the @samp{pragma foreign_export_enum} declaration
|
|
if the @var{Overrides} argument is also omitted.
|
|
The following attributes must be supported by all Mercury implementations.
|
|
|
|
@table @asis
|
|
|
|
@item @samp{prefix(@var{Prefix})}
|
|
Prefix each symbolic name, regardless of how it was generated,
|
|
with the string @var{Prefix}.
|
|
A @samp{pragma foreign_export_enum} declaration
|
|
may contain at most one @samp{prefix} attribute.
|
|
|
|
@item @samp{uppercase}
|
|
Convert any alphabetic characters in a Mercury constructor name to uppercase
|
|
when generating the symbolic name using the default mapping.
|
|
Symbolic names specified by the programmer using @var{Overrides}
|
|
are not affected by this attribute.
|
|
If the @samp{prefix} attribute is also specified,
|
|
then the prefix is added to the symbolic name
|
|
@emph{after} the conversion to uppercase has been performed,
|
|
i.e.@: the characters in the prefix
|
|
are not affected by the @samp{uppercase} attribute.
|
|
|
|
@end table
|
|
|
|
The implementation does not check
|
|
the validity of a symbolic name in the foreign language
|
|
until after the effects of any attributes have been applied.
|
|
This means that attributes may cause
|
|
an otherwise valid symbolic name to become invalid, or vice versa.
|
|
|
|
A Mercury module may contain @samp{pragma foreign_export_enum} declarations
|
|
that refer to imported types, subject to the usual visibility restrictions.
|
|
|
|
A Mercury module, or program, may contain
|
|
more than one @samp{pragma foreign_export_enum} declaration
|
|
for a given Mercury type for a given language.
|
|
This can be useful when a project is transitioning
|
|
from using one naming scheme for Mercury constants in foreign code
|
|
to another naming scheme.
|
|
|
|
It is an error if the mapping between constructors and symbolic names
|
|
in a @samp{pragma foreign_export_enum} declaration
|
|
does not form a bijection.
|
|
It is also an error
|
|
if two separate @samp{pragma foreign_export_enum} declarations
|
|
for a given foreign language, @emph{whether or not for the same type},
|
|
specify the same symbolic name,
|
|
since in that case, the Mercury compiler would generate
|
|
two conflicting definitions for that symbolic name.
|
|
However, the Mercury implementation is not required to check either condition.
|
|
|
|
A @samp{pragma foreign_export_enum} declaration
|
|
may occur only in the implementation section of a module.
|
|
|
|
@c -----------------------------------------------------------------------
|
|
|
|
@node Adding foreign declarations
|
|
@section Adding foreign declarations
|
|
|
|
Foreign language declarations
|
|
(such as type declarations, header file inclusions or macro definitions)
|
|
can be included in the Mercury source file
|
|
as part of a @samp{foreign_decl} declaration of the form
|
|
|
|
@example
|
|
:- pragma foreign_decl("@var{Lang}", @var{DeclCode}).
|
|
@end example
|
|
|
|
This declaration will have effects equivalent to
|
|
including the specified @var{DeclCode}
|
|
in an automatically generated source file
|
|
of the specified programming language,
|
|
in a place appropriate for declarations,
|
|
and linking that source file with the Mercury program
|
|
(after having compiled it with a compiler
|
|
for the specified programming language, if appropriate).
|
|
|
|
Entities declared in @samp{pragma foreign_decl} declarations
|
|
are visible in @samp{pragma foreign_code}, @samp{pragma foreign_type},
|
|
@samp{pragma foreign_proc}, and @samp{pragma foreign_enum} declarations
|
|
that specify the same foreign language and occur in the same Mercury module.
|
|
|
|
By default, the contents of @samp{pragma foreign_decl} declarations
|
|
are also visible in the same kinds of declarations in other modules
|
|
that import the module containing the @samp{pragma foreign_decl} declaration.
|
|
This is because they may be required to make sense
|
|
of types defined using @samp{pragma foreign_type}
|
|
and/or predicates defined using @samp{pragma foreign_proc}
|
|
in the containing module,
|
|
and these may be visible in other modules,
|
|
especially in the presence of intermodule optimization,
|
|
|
|
If you do not want the contents of a @samp{pragma foreign_decl} declaration
|
|
to be visible in foreign language code in other modules,
|
|
you can use the following variant of the declaration:
|
|
|
|
@example
|
|
:- pragma foreign_decl("@var{Lang}", local, @var{DeclCode}).
|
|
@end example
|
|
|
|
Note: currently only the C backend
|
|
supports this variant of the @samp{pragma foreign_decl} declaration.
|
|
|
|
The Melbourne Mercury implementation additionally supports the forms
|
|
|
|
@example
|
|
:- pragma foreign_decl("@var{Lang}", include_file("@var{Path}")).
|
|
:- pragma foreign_decl("@var{Lang}", local, include_file("@var{Path}")).
|
|
@end example
|
|
|
|
These have the same effects as the standard forms
|
|
except that the contents of the file referenced by @var{Path}
|
|
are included in place of the string literal in the last argument,
|
|
without further interpretation.
|
|
@var{Path} may be an absolute path to a file,
|
|
or a path to a file relative to the directory
|
|
that contains the source file of the module containing the declaration.
|
|
The interpretation of the path is platform-dependent.
|
|
If the filesystem uses a different character set or encoding
|
|
from the Mercury source file (which must be UTF-8),
|
|
the file may not be found.
|
|
|
|
@samp{mmc --make} and @samp{mmake} treat included files
|
|
as dependencies of the module.
|
|
|
|
@c -----------------------------------------------------------------------
|
|
|
|
@node Declaring Mercury exports to other modules
|
|
@section Declaring Mercury exports to other modules
|
|
|
|
The declarations for Mercury predicates or functions
|
|
exported to a foreign language using a @samp{pragma foreign_export} declaration
|
|
are visible to foreign code
|
|
in a @samp{pragma foreign_code} or @samp{pragma foreign_proc} declaration
|
|
of the same module, and also in those of any submodules.
|
|
By default, they are not visible to the foreign code
|
|
in @samp{pragma foreign_code} or @samp{pragma foreign_proc} declarations
|
|
in any other module,
|
|
but this default can be overridden (giving access to all other modules)
|
|
using a declaration of the form:
|
|
|
|
@example
|
|
:- pragma foreign_import_module("@var{Lang}", @var{ImportedModule}).
|
|
@end example
|
|
|
|
@noindent
|
|
where @var{ImportedModule} is the name of the module
|
|
containing the @samp{pragma foreign_export} declarations.
|
|
|
|
If @var{Lang} is @code{"C"}, this is equivalent to
|
|
|
|
@example
|
|
:- pragma foreign_decl("C", "#include ""@var{ImportedModule}.mh""").
|
|
@end example
|
|
|
|
@noindent
|
|
where @file{@var{ImportedModule}.mh} is the automatically generated header file
|
|
containing the C declarations for the predicates and functions exported to C.
|
|
|
|
@samp{pragma foreign_import_module} should be used
|
|
instead of the explicit @code{#include}
|
|
because @samp{pragma foreign_import_module} tells the implementation
|
|
that @file{@var{ImportedModule}.mh} must be built before the object file
|
|
for the module containing the @samp{pragma foreign_import_module} declaration.
|
|
|
|
@c This sentence used to be here:
|
|
@c
|
|
@c A cycle of @samp{pragma foreign_import_module}, where the language is
|
|
@c @samp{"C#"} or @samp{"Java"}, is not permitted.
|
|
@c
|
|
@c but seems to be obsolete now. Julien says (on m-dev, 2019 jun 20):
|
|
@c
|
|
@c That line (minus the bit about the Java) grade was added by Peter Ross
|
|
@c in commit e868b11d. At the time, it was with reference to the old IL
|
|
@c backend, the foreign languages involved were IL, C# and MC++.
|
|
@c
|
|
@c I suspect the restriction on foreign_import_module cycles may have
|
|
@c arisen because C# and MC++ were secondary (i.e.@: non-target) foreign
|
|
@c languages. Compilation of secondary foreign languages is handled by
|
|
@c hoisting the code out to a separate source file and that requires
|
|
@c the foreign_import_module graph to be acyclic.
|
|
@c
|
|
@c None of that line is applicable to C# and Java when they are the target
|
|
@c language.
|
|
|
|
Note that the Melbourne Mercury implementation often behaves
|
|
as if @samp{pragma foreign_import_module} declarations
|
|
were implicitly added to modules.
|
|
However, programmers should @emph{not} should not depend on this behaviour;
|
|
they should always write explicit
|
|
@samp{pragma foreign_import_module} declarations wherever they are needed.
|
|
|
|
@c -----------------------------------------------------------------------
|
|
|
|
@node Adding foreign definitions
|
|
@section Adding foreign definitions
|
|
|
|
Definitions of foreign language entities
|
|
(such as functions or global variables)
|
|
may be included using a declaration of the form
|
|
|
|
@example
|
|
:- pragma foreign_code("@var{Lang}", @var{Code}).
|
|
@end example
|
|
|
|
This declaration will have effects equivalent to
|
|
including the specified @var{Code} in an automatically generated source file
|
|
of the specified programming language,
|
|
in a place appropriate for definitions,
|
|
and linking that source file with the Mercury program
|
|
(after having compiled it with a compiler
|
|
for the specified programming language, if appropriate).
|
|
|
|
Entities declared in @samp{pragma foreign_code} declarations
|
|
are visible in @samp{pragma foreign_proc} declarations
|
|
that specify the same foreign language and occur in the same Mercury module.
|
|
|
|
The Melbourne Mercury implementation additionally supports the form
|
|
|
|
@example
|
|
:- pragma foreign_code("@var{Lang}", include_file("@var{Path}")).
|
|
@end example
|
|
|
|
This has the same effect as the standard form
|
|
except that the contents of the file referenced by @var{Path}
|
|
are included in place of the string literal in the last argument,
|
|
without further interpretation.
|
|
@var{Path} may be an absolute path to a file,
|
|
or a path to a file relative to the directory
|
|
that contains the source file of the module containing the declaration.
|
|
The interpretation of the path is platform-dependent.
|
|
If the filesystem uses a different character set or encoding
|
|
from the Mercury source file (which must be UTF-8),
|
|
the file may not be found.
|
|
|
|
@samp{mmc --make} and @samp{mmake} treat included files
|
|
as dependencies of the module.
|
|
|
|
@c -----------------------------------------------------------------------
|
|
|
|
@node Language specific bindings
|
|
@section Language specific bindings
|
|
|
|
@c Please keep this menu in alphabetical order
|
|
|
|
@menu
|
|
* Interfacing with C :: How to write code to interface with C
|
|
* Interfacing with C# :: How to write code to interface with C#
|
|
* Interfacing with Java :: How to write code to interface with Java
|
|
@end menu
|
|
|
|
All Mercury implementations should support interfacing with C.
|
|
The set of other languages supported is implementation-defined.
|
|
A suitable compiler or assembler for the foreign language
|
|
must be available on the system.
|
|
|
|
The Melbourne Mercury implementation supports
|
|
interfacing with the following languages:
|
|
|
|
@table @asis
|
|
|
|
@c Please keep this table in alphabetical order
|
|
|
|
@item @samp{C}
|
|
Use the string @code{"C"} to set the foreign language to C.
|
|
|
|
@item @samp{C#}
|
|
Use the string @code{"C#"} to set the foreign language to C#.
|
|
|
|
@item @samp{Java}
|
|
Use the string @code{"Java"} to set the foreign language to Java.
|
|
|
|
@end table
|
|
|
|
@c -----------------------------------------------------------------------
|
|
|
|
@node Interfacing with C
|
|
@subsection Interfacing with C
|
|
|
|
@menu
|
|
* Using pragma foreign_type for C :: Declaring C types in Mercury
|
|
* Using pragma foreign_enum for C :: Assigning Mercury enumerations
|
|
values in C
|
|
* Using pragma foreign_export_enum for C :: Using Mercury enumerations in C
|
|
* Using pragma foreign_proc for C :: Calling C code from Mercury
|
|
* Using pragma foreign_export for C :: Calling Mercury code from C
|
|
* Using pragma foreign_decl for C :: Including C declarations in Mercury
|
|
* Using pragma foreign_code for C :: Including C code in Mercury
|
|
* Memory management for C :: Caveats about passing dynamically
|
|
allocated memory to or from C.
|
|
* Linking with C object files :: Linking with C object files and
|
|
libraries.
|
|
|
|
@end menu
|
|
|
|
@node Using pragma foreign_type for C
|
|
@subsubsection Using pragma foreign_type for C
|
|
|
|
A C @samp{pragma foreign_type} declaration has the form:
|
|
|
|
@example
|
|
:- pragma foreign_type("C", @var{MercuryTypeName}, "@var{CForeignType}").
|
|
@end example
|
|
|
|
For example,
|
|
|
|
@example
|
|
:- pragma foreign_type("C", long_double, "long double").
|
|
@end example
|
|
|
|
The @var{CForeignType} can be any C type name
|
|
that obeys the following restrictions.
|
|
Function types, array types, and incomplete types are not allowed.
|
|
The type name must be such that when declaring a variable in C of that type,
|
|
no part of the type name is required after the variable name.
|
|
(This rule prohibits, for example,
|
|
function pointer types such as @samp{void (*)(void)};
|
|
however, it would be OK to use a typedef name
|
|
which was defined as a function pointer type.)
|
|
|
|
C preprocessor directives (such as @samp{#if})
|
|
may not be used in @var{CForeignType}.
|
|
(You can however use a typedef name that refers to a type
|
|
defined in a @samp{pragma foreign_decl} declaration,
|
|
and the @samp{pragma foreign_decl} declaration
|
|
may contain C preprocessor directives.)
|
|
|
|
@c @strong{With @samp{--gc accurate}, foreign_types which are C pointer types
|
|
@c must not point to the Mercury heap.}
|
|
|
|
If the @var{MercuryTypeName} is the type of a parameter of a procedure
|
|
defined using @samp{pragma foreign_proc},
|
|
it will be passed to the foreign_proc's foreign language code
|
|
as @var{CForeignType}.
|
|
|
|
Furthermore, any Mercury procedure exported with @samp{pragma foreign_export}
|
|
will use @var{CForeignType} as the type
|
|
for any parameters whose Mercury type is @var{MercuryTypeName}.
|
|
|
|
The builtin Mercury type @code{c_pointer} may 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_c_structure::di,
|
|
complicated_c_structure::uo) is det.
|
|
|
|
:- implementation.
|
|
|
|
% Our C structure is implemented as a c_pointer.
|
|
:- type complicated_c_structure
|
|
---> complicated_c_structure(c_pointer).
|
|
|
|
:- pragma foreign_decl("C",
|
|
extern struct foo *init_struct(void);
|
|
extern struct foo *perform_calculation(int, struct foo *);
|
|
");
|
|
|
|
:- pragma foreign_proc("C",
|
|
initialise_complicated_structure(Structure::uo),
|
|
[will_not_call_mercury, may_call_mercury],
|
|
"
|
|
Structure = init_struct();
|
|
").
|
|
|
|
:- pragma foreign_proc("C",
|
|
do_calculation(Value::in, Structure0::di, Structure::uo),
|
|
[will_not_call_mercury, may_call_mercury],
|
|
"
|
|
Structure = perform_calculation(Value, Structure0);
|
|
").
|
|
@end example
|
|
|
|
We strongly recommend the use of @samp{pragma foreign_type}
|
|
instead of @code{c_pointer}
|
|
as the use of @samp{pragma foreign_type} results in more type-safe code.
|
|
|
|
@node Using pragma foreign_enum for C
|
|
@subsubsection Using pragma foreign_enum for C
|
|
|
|
Foreign enumeration values in C must be constants of type @code{MR_Integer}.
|
|
A foreign enumeration value may be specified by one of the following:
|
|
@itemize
|
|
@item An integer literal.
|
|
@item An enumeration constant.
|
|
@item A preprocessor macro that expands to either an integer literal or
|
|
an enumeration constant.
|
|
@end itemize
|
|
|
|
@node Using pragma foreign_export_enum for C
|
|
@subsubsection Using pragma foreign_export_enum for C
|
|
|
|
For C the symbolic names generated by a @samp{pragma foreign_export_enum}
|
|
must form valid C identifiers.
|
|
These identifiers are used as the names of preprocessor macros.
|
|
The body of each of these macros expands to a value
|
|
that is identical to that of the constructor
|
|
to which the symbolic name corresponds
|
|
in the mapping established
|
|
by the @w{@samp{pragma foreign_export_enum}} declaration.
|
|
|
|
As noted in the @ref{C data passing conventions},
|
|
the type of these values is @code{MR_Word}.
|
|
|
|
The default mapping
|
|
used by @samp{pragma foreign_export_enum} declarations for C
|
|
is to use the Mercury constructor name as the base of the symbolic name.
|
|
For example, the symbolic name for the Mercury constructor @samp{foo}
|
|
would be @code{foo}.
|
|
|
|
@c It would be useful if there were some documented way of mapping
|
|
@c these things into [0, N - 1], e.g.@: for array lookups.
|
|
|
|
@node Using pragma foreign_proc for C
|
|
@subsubsection Using pragma foreign_proc for C
|
|
|
|
The input and output variables
|
|
will have C types corresponding to their Mercury types,
|
|
as determined by the rules specified in @ref{C data passing conventions}.
|
|
|
|
The C code fragment may declare local variables,
|
|
up to a total size of 10kB for the procedure.
|
|
@c The relevant parameter is LOCALS_SIZE, defined in runtime/mercury_engine.c.
|
|
If a procedure requires more than this for its local variables,
|
|
the code can be moved into a separate function
|
|
(defined in a @samp{pragma foreign_code} declaration, for example).
|
|
|
|
The C code fragment should not declare any labels or static variables
|
|
unless there is also a @samp{pragma no_inline} declaration
|
|
or a @samp{may_not_duplicate} foreign code attribute 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.
|
|
|
|
C code in a @code{pragma foreign_proc} declaration
|
|
for any procedure whose determinism indicates that it can fail
|
|
must assign a truth value to the macro @code{SUCCESS_INDICATOR}.
|
|
For example:
|
|
|
|
@example
|
|
:- pred string.contains_char(string, character).
|
|
:- mode string.contains_char(in, in) is semidet.
|
|
|
|
:- pragma foreign_proc("C",
|
|
string.contains_char(Str::in, Ch::in),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
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 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.
|
|
If the procedure fails,
|
|
the C code need only set @code{SUCCESS_INDICATOR} to false (zero).
|
|
|
|
The behaviour of a procedure
|
|
defined using a @samp{pragma foreign_proc} declaration
|
|
whose body contains a @code{return} statement is undefined.
|
|
|
|
@node Using pragma foreign_export for C
|
|
@subsubsection Using pragma foreign_export for C
|
|
|
|
A @samp{pragma foreign_export} declaration for C has the form:
|
|
|
|
@example
|
|
:- pragma foreign_export("C", @var{MercuryMode}, "@var{C_Name}").
|
|
@end example
|
|
|
|
For example,
|
|
|
|
@example
|
|
:- pragma foreign_export("C", foo(in, in, out), "FOO").
|
|
@end example
|
|
|
|
For each Mercury module
|
|
containing @samp{pragma foreign_export} declarations for C,
|
|
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 foreign_export} declarations.
|
|
Each such C function is the C interface to the specified Mercury procedure.
|
|
|
|
The type signature of the C interface to a Mercury procedure
|
|
is determined as follows.
|
|
Mercury types are converted to C types
|
|
according to the rules in @ref{C data passing conventions}.
|
|
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.
|
|
@c XXX We need to update this for dummy unit types.
|
|
Arguments of type @samp{io.state} or @samp{store.store(_)}
|
|
are not passed at all.
|
|
(The reason for this is that 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 distinct 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{type_desc}.
|
|
|
|
To use the C declarations produced see @ref{Using pragma foreign_decl for C}.
|
|
|
|
Throwing an exception across the C interface is not supported.
|
|
That is, if a Mercury procedure that is exported to C using
|
|
@samp{pragma foreign_export} throws an exception
|
|
which is not caught within that procedure,
|
|
then you will get undefined behaviour.
|
|
|
|
@node Using pragma foreign_decl for C
|
|
@subsubsection Using pragma foreign_decl for C
|
|
|
|
Any macros, function prototypes, or other C declarations
|
|
that are used in @samp{foreign_code}, @samp{foreign_type}
|
|
or @samp{foreign_proc} pragmas
|
|
must be included using a @samp{foreign_decl} declaration of the form
|
|
|
|
@example
|
|
:- pragma foreign_decl("C", @var{HeaderCode}).
|
|
@end example
|
|
|
|
@noindent
|
|
@var{HeaderCode} can be a C @samp{#include} line, for example
|
|
|
|
@example
|
|
:- pragma foreign_decl("C", "#include <math.h>")
|
|
@end example
|
|
|
|
@noindent
|
|
or
|
|
|
|
@example
|
|
:- pragma foreign_decl("C", "#include ""tcl.h""").
|
|
@end example
|
|
|
|
@noindent
|
|
or it may contain any C declarations, for example
|
|
|
|
@example
|
|
:- pragma foreign_decl("C", "
|
|
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.
|
|
|
|
If a Mercury predicate or function exported
|
|
using a @samp{pragma foreign_export} declaration
|
|
is to be used within a @samp{:- pragma foreign_code}
|
|
or @samp{:- pragma foreign_proc} declaration
|
|
the header file for the module containing
|
|
the @samp{pragma foreign_export} declaration
|
|
should be included using a @samp{pragma foreign_import_module} declaration,
|
|
for example
|
|
|
|
@example
|
|
:- pragma foreign_import_module("C", exporting_module).
|
|
@end example
|
|
|
|
@node Using pragma foreign_code for C
|
|
@subsubsection Using pragma foreign_code for C
|
|
|
|
Definitions of C functions or global variables
|
|
may be included using a declaration of the form
|
|
|
|
@example
|
|
:- pragma foreign_code("C", @var{Code}).
|
|
@end example
|
|
|
|
For example,
|
|
|
|
@example
|
|
:- pragma foreign_code("C", "
|
|
int bar = 42;
|
|
void foo(void) @{@}
|
|
").
|
|
@end example
|
|
|
|
Such code is copied verbatim into the generated C file.
|
|
|
|
@node Memory management for C
|
|
@subsubsection Memory management for C
|
|
|
|
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.
|
|
The latter is suitable only for programs
|
|
with very short running times (less than a second),
|
|
which makes the former the standard method for almost all Mercury programs.
|
|
|
|
Conservative garbage collection makes inter-language calls simplest.
|
|
Mercury uses the Boehm-Demers-Weiser conservative garbage collector,
|
|
which we also call simply Boehm gc.
|
|
This has its own set of functions for allocating memory blocks,
|
|
such as @samp{MR_GC_NEW},
|
|
which are documented in @file{runtime/mercury_memory.h}.
|
|
Memory blocks allocated by these functions,
|
|
either in C code generated by the Mercury compiler
|
|
or in C code hand written by programmers,
|
|
are automatically reclaimed when they are no longer referred to
|
|
either from the stack, from global variables,
|
|
or from other memory blocks allocated by Boehm gc functions.
|
|
Note that these are the @emph{only} places
|
|
where Boehm gc looks for pointers to the blocks it has allocated.
|
|
If the only pointers to such a block occur in other parts of memory,
|
|
such as in memory blocks allocated by @samp{malloc},
|
|
the Boehm collector won't see them, and may collect the block prematurely.
|
|
Programmers can avoid this either
|
|
by not storing pointers to Boehm-allocated memory in malloc-allocated blocks,
|
|
or by storing them e.g.@: on the stack as well.
|
|
|
|
Boehm gc recognizes pointers to the blocks it has allocated
|
|
only if they point either to the start to the block,
|
|
or to a byte in the first word of the block;
|
|
pointers into the middle of a block beyond the first word
|
|
won't keep the block alive.
|
|
|
|
Pointers to Boehm-allocated memory blocks
|
|
can be passed freely between Mercury and C code
|
|
provided these restrictions are observed.
|
|
|
|
Note that the Boehm collector cannot and does not recover
|
|
memory allocated by other methods, such as @samp{malloc}.
|
|
|
|
When using no garbage collection,
|
|
heap storage is reclaimed only on backtracking.
|
|
This requires programmers to 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.
|
|
They must also avoid the use of the macros
|
|
@code{MR_list_empty()} and @code{MR_list_cons()}.
|
|
(The reason for this is that they may access Mercury's @samp{MR_hp} register,
|
|
which might not be valid in C code.
|
|
Using them in the bodies of procedures
|
|
defined using @samp{pragma foreign_proc} 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 foreign_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 Linking with C object files
|
|
@subsubsection 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 Melbourne Mercury implementation.
|
|
|
|
To link an existing object file or archive of object files
|
|
into your Mercury code,
|
|
use the command line option @samp{--link-object}.
|
|
For example, the following will link the object file @samp{my_function.o}
|
|
from the current directory when compiling the program @samp{prog}:
|
|
|
|
@example
|
|
mmc --link-object my_functions.o prog
|
|
@end example
|
|
|
|
The command line option @samp{--library} (or @samp{-l} for short)
|
|
can be used to link an existing library into your Mercury code.
|
|
For example, the following will link the library file @file{libfancy_library.a},
|
|
or perhaps the shared version @file{libfancy_library.so},
|
|
from the directory @file{/usr/local/contrib/lib},
|
|
when compiling the program @samp{prog}:
|
|
|
|
@example
|
|
mmc -R/usr/local/contrib/lib -L/usr/local/contrib/lib -lfancy_library prog
|
|
@end example
|
|
|
|
As illustrated by the example,
|
|
the command line options @samp{-R}, @samp{-L} and @samp{-l},
|
|
have the same meaning as they do with the Unix linker.
|
|
|
|
For more information,
|
|
see the ``Libraries'' chapter of the Mercury User's Guide.
|
|
|
|
@c ----------------------------------------------------------------------------
|
|
|
|
@node Interfacing with C#
|
|
@subsection Interfacing with C#
|
|
|
|
@menu
|
|
* Using pragma foreign_type for C# :: Declaring C# types in Mercury
|
|
* Using pragma foreign_enum for C# :: Assigning Mercury enumerations
|
|
values in C#
|
|
* Using pragma foreign_export_enum for C# :: Using Mercury enumerations in C#
|
|
* Using pragma foreign_proc for C# :: Calling C# code from Mercury
|
|
* Using pragma foreign_export for C# :: Calling Mercury code from C#
|
|
* Using pragma foreign_decl for C# :: Including C# declarations in Mercury
|
|
* Using pragma foreign_code for C# :: Including C# code in Mercury
|
|
@end menu
|
|
|
|
@node Using pragma foreign_type for C#
|
|
@subsubsection Using pragma foreign_type for C#
|
|
|
|
A C# @samp{pragma foreign_type} declaration has the form:
|
|
|
|
@example
|
|
:- pragma foreign_type("C#", @var{MercuryTypeName}, "@var{C#-Type}").
|
|
@end example
|
|
|
|
The @var{C#-Type} can be any accessible C# type.
|
|
|
|
The effect of this declaration is that
|
|
Mercury values of type @var{MercuryTypeName}
|
|
will be passed to and from C# foreign_procs as having type @var{C#-Type}.
|
|
|
|
Furthermore, any Mercury procedure exported with @samp{pragma foreign_export}
|
|
will use @var{C#-Type} as the type
|
|
for any parameters whose Mercury type is @var{MercuryTypeName}.
|
|
|
|
@node Using pragma foreign_enum for C#
|
|
@subsubsection Using pragma foreign_enum for C#
|
|
|
|
Foreign enumeration values in C# must be a constant value expression
|
|
which is a valid initializer
|
|
within an enumeration of underlying type @code{int}.
|
|
|
|
@node Using pragma foreign_export_enum for C#
|
|
@subsubsection Using pragma foreign_export_enum for C#
|
|
|
|
For C# the symbolic names generated by a @samp{pragma foreign_export_enum}
|
|
must form valid C# identifiers.
|
|
These identifiers are used as the names of static class members.
|
|
|
|
The default mapping
|
|
used by @samp{pragma foreign_export_enum} declarations for C#
|
|
is to use the Mercury constructor name as the base of the symbolic name.
|
|
For example, the symbolic name for the Mercury constructor @samp{foo}
|
|
would be @code{foo}.
|
|
|
|
@node Using pragma foreign_proc for C#
|
|
@subsubsection Using pragma foreign_proc for C#
|
|
|
|
The C# code from C# @samp{pragma foreign_proc} declarations
|
|
will be placed in the bodies of static member functions
|
|
of an automatically generated C# class.
|
|
Since such C# code will become part of a static member function,
|
|
it must not refer to the @code{this} keyword.
|
|
It may however refer to static member variables or static member functions
|
|
declared with @samp{pragma foreign_code}.
|
|
|
|
The input and output variables for a C# @samp{pragma foreign_proc}
|
|
will have C# types corresponding to their Mercury types.
|
|
The exact rules for mapping Mercury types to C# types
|
|
are described in @ref{C# data passing conventions}.
|
|
|
|
C# code in a @code{pragma foreign_proc} declaration
|
|
for any procedure whose determinism indicates that it can fail
|
|
must assign a value of type @code{bool}
|
|
to the variable @code{SUCCESS_INDICATOR}.
|
|
For example:
|
|
|
|
@example
|
|
:- pred string.contains_char(string, character).
|
|
:- mode string.contains_char(in, in) is semidet.
|
|
|
|
:- pragma foreign_proc("C#",
|
|
string.contains_char(Str::in, Ch::in),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
SUCCESS_INDICATOR = (Str.IndexOf(Ch) != -1);
|
|
").
|
|
@end example
|
|
|
|
@noindent
|
|
C# code for procedures whose determinism indicates 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.
|
|
If the procedure fails,
|
|
the C# code need only set @code{SUCCESS_INDICATOR} to false.
|
|
|
|
@node Using pragma foreign_export for C#
|
|
@subsubsection Using pragma foreign_export for C#
|
|
|
|
A @samp{pragma foreign_export} declaration for C# has the form:
|
|
|
|
@example
|
|
:- pragma foreign_export("C#", @var{MercuryMode}, "@var{C#_Name}").
|
|
@end example
|
|
|
|
For example,
|
|
|
|
@example
|
|
:- pragma foreign_export("C#", foo(in, in, out), "FOO").
|
|
@end example
|
|
|
|
The type signature of the C# interface to a Mercury procedure
|
|
is as described in @ref{C# data passing conventions}.
|
|
|
|
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 distinct 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{type_desc}.
|
|
|
|
@node Using pragma foreign_decl for C#
|
|
@subsubsection Using pragma foreign_decl for C#
|
|
|
|
@samp{pragma foreign_decl} declarations for C#
|
|
can be used to provide any top-level C# declarations
|
|
(e.g.@: @samp{using} declarations or auxiliary class definitions)
|
|
which are needed by C# code in @samp{pragma foreign_proc} declarations
|
|
in that module.
|
|
|
|
For example:
|
|
|
|
@example
|
|
:- pragma foreign_decl("C#", "
|
|
using System;
|
|
").
|
|
:- pred hello(io.state::di, io.state::uo) is det.
|
|
:- pragma foreign_proc("C#",
|
|
hello(_IO0::di, _IO::uo),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
// here we can refer directly to Console rather than System.Console
|
|
Console.WriteLine(""hello world"");
|
|
").
|
|
@end example
|
|
|
|
@node Using pragma foreign_code for C#
|
|
@subsubsection Using pragma foreign_code for C#
|
|
|
|
The C# code from @samp{pragma foreign_proc} declarations for C#
|
|
will be placed in the bodies of static member functions
|
|
of an automatically generated C# class.
|
|
@samp{pragma foreign_code} can be used to define
|
|
additional members of this automatically generated class,
|
|
which can then be referenced by @samp{pragma foreign_proc} declarations
|
|
for C# from that module.
|
|
|
|
For example:
|
|
|
|
@example
|
|
:- pragma foreign_code("C#", "
|
|
static int counter = 0;
|
|
").
|
|
|
|
:- impure pred incr_counter is det.
|
|
:- pragma foreign_proc("C#",
|
|
incr_counter,
|
|
[will_not_call_mercury], "
|
|
counter++;
|
|
").
|
|
|
|
:- semipure func get_counter = int.
|
|
:- pragma foreign_proc("C#",
|
|
get_counter = (Result::out),
|
|
[will_not_call_mercury, promise_semipure],
|
|
"
|
|
Result = counter;
|
|
").
|
|
@end example
|
|
|
|
@c ----------------------------------------------------------------------------
|
|
|
|
@node Interfacing with Java
|
|
@subsection Interfacing with Java
|
|
|
|
@menu
|
|
* Using pragma foreign_type for Java :: Declaring Java types in Mercury
|
|
* Using pragma foreign_enum for Java :: Assigning Mercury enumerations
|
|
values in Java
|
|
* Using pragma foreign_export_enum for Java :: Using Mercury enumerations in
|
|
Java
|
|
* Using pragma foreign_proc for Java :: Calling Java code from Mercury
|
|
* Using pragma foreign_export for Java :: Calling Mercury from Java code
|
|
* Using pragma foreign_decl for Java :: Including Java declarations in Mercury
|
|
* Using pragma foreign_code for Java :: Including Java code in Mercury
|
|
@end menu
|
|
|
|
@node Using pragma foreign_type for Java
|
|
@subsubsection Using pragma foreign_type for Java
|
|
|
|
A Java @samp{pragma foreign_type} declaration has the form:
|
|
|
|
@example
|
|
:- pragma foreign_type("Java", @var{MercuryTypeName}, "@var{JavaType}").
|
|
@end example
|
|
|
|
The @var{JavaType} can be any accessible Java type.
|
|
|
|
The effect of this declaration is that
|
|
Mercury values of type @var{MercuryTypeName}
|
|
will be passed to and from Java foreign_procs as having type @var{JavaType}.
|
|
|
|
Furthermore, any Mercury procedure exported with @samp{pragma foreign_export}
|
|
will use @var{JavaType} as the type
|
|
for any parameters whose Mercury type is @var{MercuryTypeName}.
|
|
|
|
@node Using pragma foreign_enum for Java
|
|
@subsubsection Using pragma foreign_enum for Java
|
|
|
|
@samp{pragma foreign_enum} is currently not supported for Java.
|
|
|
|
@node Using pragma foreign_export_enum for Java
|
|
@subsubsection Using pragma foreign_export_enum for Java
|
|
|
|
For Java the symbolic names generated by a @samp{pragma foreign_export_enum}
|
|
must form valid Java identifiers.
|
|
These identifiers are used as the names of static class members
|
|
which are assigned instances of the enumeration class.
|
|
|
|
The @code{equals} method should be used
|
|
for equality testing of enumeration values in Java code.
|
|
|
|
The default mapping
|
|
used by @samp{pragma foreign_export_enum} declarations for Java
|
|
is to use the Mercury constructor name as the base of the symbolic name.
|
|
For example, the symbolic name for the Mercury constructor @samp{foo}
|
|
would be @code{foo}.
|
|
|
|
@node Using pragma foreign_proc for Java
|
|
@subsubsection Using pragma foreign_proc for Java
|
|
|
|
The Java code from Java @samp{pragma foreign_proc} declarations
|
|
will be placed in the bodies of static member functions
|
|
of an automatically generated Java class.
|
|
Since such Java code will become part of a static member function,
|
|
it must not refer to the @code{this} keyword.
|
|
It may however refer to static member variables or static member functions
|
|
declared with @samp{pragma foreign_code}.
|
|
|
|
The input and output variables for a Java @samp{pragma foreign_proc}
|
|
will have Java types corresponding to their Mercury types.
|
|
The exact rules for mapping Mercury types to Java types
|
|
are described in @ref{Java data passing conventions}.
|
|
|
|
The Java code in a @code{pragma foreign_proc} declaration
|
|
for a procedure whose determinism indicates that it can fail
|
|
must assign a value of type @code{boolean}
|
|
to the variable @code{SUCCESS_INDICATOR}.
|
|
For example:
|
|
|
|
@example
|
|
:- pred string.contains_char(string, character).
|
|
:- mode string.contains_char(in, in) is semidet.
|
|
|
|
:- pragma foreign_proc("Java",
|
|
string.contains_char(Str::in, Ch::in),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
SUCCESS_INDICATOR = (Str.IndexOf(Ch) != -1);
|
|
").
|
|
@end example
|
|
|
|
@noindent
|
|
Java code for procedures whose determinism indicates that they cannot fail
|
|
should not refer to the @code{SUCCESS_INDICATOR} variable.
|
|
|
|
Arguments whose mode is input
|
|
will have their values set by the Mercury implementation
|
|
on entry to the Java code.
|
|
With our current implementation,
|
|
the Java code must set the values of all output variables,
|
|
even if the procedure fails
|
|
(i.e.@: sets the @code{SUCCESS_INDICATOR} variable to @code{false}).
|
|
@c If the procedure
|
|
@c succeeds, the Java code must set the values of all output arguments
|
|
@c If the procedure fails, the Java code need only
|
|
@c set the @code{SUCCESS_INDICATOR} variable to false.
|
|
|
|
@node Using pragma foreign_export for Java
|
|
@subsubsection Using pragma foreign_export for Java
|
|
|
|
A @samp{pragma foreign_export} declaration for Java has the form:
|
|
|
|
@example
|
|
:- pragma foreign_export("Java", @var{MercuryMode}, "@var{Java_Name}").
|
|
@end example
|
|
|
|
For example,
|
|
|
|
@example
|
|
:- pragma foreign_export("Java", foo(in, in, out), "FOO").
|
|
@end example
|
|
|
|
The type signature of the Java interface to a Mercury procedure
|
|
is as described in @ref{Java data passing conventions}.
|
|
|
|
Calling polymorphically typed Mercury procedures from Java
|
|
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 Java interface function
|
|
for each distinct 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{type_desc}.
|
|
|
|
@node Using pragma foreign_decl for Java
|
|
@subsubsection Using pragma foreign_decl for Java
|
|
|
|
@samp{pragma foreign_decl} declarations for Java
|
|
can be used to provide any top-level Java declarations
|
|
(e.g.@: @samp{import} declarations or auxiliary class definitions)
|
|
which are needed by Java code in @samp{pragma foreign_proc} declarations
|
|
in that module.
|
|
|
|
For example:
|
|
|
|
@example
|
|
:- pragma foreign_decl("Java", "
|
|
import javax.swing.*;
|
|
import java.awt.*;
|
|
|
|
class MyApplet extends JApplet @{
|
|
public void init() @{
|
|
JLabel label = new JLabel(""Hello, world"");
|
|
label.setHorizontalAlignment(JLabel.CENTER);
|
|
getContentPane().add(label);
|
|
@}
|
|
@}
|
|
").
|
|
:- pred hello(io.state::di, io.state::uo) is det.
|
|
:- pragma foreign_proc("Java",
|
|
hello(_IO0::di, _IO::uo),
|
|
[will_not_call_mercury],
|
|
"
|
|
MyApplet app = new MyApplet();
|
|
// @dots{}
|
|
").
|
|
@end example
|
|
|
|
@node Using pragma foreign_code for Java
|
|
@subsubsection Using pragma foreign_code for Java
|
|
|
|
The Java code from @samp{pragma foreign_proc} declarations for Java
|
|
will be placed in the bodies of static member functions
|
|
of an automatically generated Java class.
|
|
@samp{pragma foreign_code} can be used to define additional members
|
|
of this automatically generated class,
|
|
which can then be referenced by @samp{pragma foreign_proc} declarations
|
|
for Java from that module.
|
|
|
|
For example:
|
|
|
|
@example
|
|
:- pragma foreign_code("Java", "
|
|
static int counter = 0;
|
|
").
|
|
|
|
:- impure pred incr_counter is det.
|
|
:- pragma foreign_proc("Java",
|
|
incr_counter,
|
|
[will_not_call_mercury],
|
|
"
|
|
counter++;
|
|
").
|
|
|
|
:- semipure func get_counter = int.
|
|
:- pragma foreign_proc("Java",
|
|
get_counter = (Result::out),
|
|
[will_not_call_mercury, promise_semipure],
|
|
"
|
|
Result = counter;
|
|
").
|
|
@end example
|
|
|
|
@c ----------------------------------------------------------------------------
|
|
|
|
@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 foreign language 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 or function to be so declared,
|
|
and by requiring every call to an impure predicate or function
|
|
to be flagged as such.
|
|
Predicates or functions that are implemented
|
|
in terms of impure predicates or functions
|
|
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,
|
|
or for implementing interfaces to foreign language libraries
|
|
using the foreign language interface.
|
|
Any other 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.
|
|
* Purity ordering:: How purity levels are ordered
|
|
* Impurity semantics:: What impure code means.
|
|
* Declaring impurity:: Declaring predicates impure.
|
|
* Impure goals:: Marking a goal as impure.
|
|
* Promising purity:: Promising that a predicate is pure.
|
|
* Impurity example:: A simple example using impurity.
|
|
* Higher-order impurity:: Using impurity with higher-order code.
|
|
@end menu
|
|
|
|
@node Purity levels
|
|
@section Choosing the right level of purity
|
|
|
|
Mercury distinguishes three ``levels'' of purity:
|
|
|
|
@table @dfn
|
|
@item pure
|
|
For pure procedures,
|
|
the set of solutions depends only on the values of the input arguments.
|
|
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 change the value of any data structure
|
|
that will not be undone on backtracking
|
|
(unless the data structure would be unreachable on backtracking).
|
|
Note that equality axioms are important
|
|
when considering the value of data structures.
|
|
The declarative semantics of pure predicates
|
|
is never affected by the invocation of other predicates.
|
|
It not is possible for the invocation of pure predicates
|
|
to affect the operational behaviour of non-pure predicates and vice versa.
|
|
|
|
By default, Mercury predicates and functions are pure.
|
|
Without using the foreign language interface,
|
|
writing mode-specific clauses
|
|
or calling other impure predicates and functions,
|
|
it is impossible to write impure code in Mercury.
|
|
|
|
@item semipure
|
|
Semipure predicates are just like pure predicates,
|
|
except that their declarative semantics 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 perform I/O or modify hidden state,
|
|
even if these side effects alter the operational semantics of other code.
|
|
However, impure predicates may not change
|
|
the declarative semantics of pure code.
|
|
They must be type-, mode-, determinism- and uniqueness correct.
|
|
|
|
@end table
|
|
|
|
@node Purity ordering
|
|
@section Purity ordering
|
|
|
|
The three levels of purity (which we will simply call the purity)
|
|
have a total ordering defined upon them: @code{pure > semipure > impure}.
|
|
|
|
@node Impurity semantics
|
|
@section Impurity 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 Mercury draws this distinction 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 implementations must respect.
|
|
|
|
The operational semantics
|
|
of a Mercury predicate which invokes @emph{impure} code
|
|
is a modified form of the @emph{strict sequential} semantics
|
|
(@pxref{Formal 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 the compiler desires
|
|
(within the bounds of the semantics the user has specified for the program)
|
|
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
|
|
the 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 implementations must respect
|
|
this contextual nature of the semantics of semipure goals;
|
|
within a single context,
|
|
an implementation may treat a semipure goal as if it were pure.
|
|
|
|
@node Declaring impurity
|
|
@section Declaring impure functions and predicates
|
|
|
|
Every Mercury predicate or function
|
|
has exactly two purity values associated with it.
|
|
One is the @emph{declared} purity of the predicate or function,
|
|
which is given by the programmer.
|
|
The other value is the @emph{inferred} purity,
|
|
which is calculated from the purity of goals
|
|
in the body of the predicate or function.
|
|
|
|
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.
|
|
Similarly, a function is declared impure or semipure
|
|
by preceding the word @code{func} in its @code{func} declaration
|
|
with @code{impure} or @code{semipure}.
|
|
That is, the declarations
|
|
|
|
@example
|
|
:- impure pred @var{Pred}(@var{Arguments}@dots{}).
|
|
:- semipure pred @var{Pred}(@var{Arguments}@dots{}).
|
|
:- impure func @var{Func}(@var{Arguments}@dots{}) = @var{Result}.
|
|
:- semipure func @var{Func}(@var{Arguments}@dots{}) = @var{Result}.
|
|
@end example
|
|
|
|
@noindent
|
|
declare the predicate @var{Pred} and the function @var{Func}
|
|
to be impure and semipure, respectively.
|
|
|
|
Type class methods may also be declared as @code{impure} or @code{semipure}
|
|
by preceding the word @code{pred} or @code{func}
|
|
with the appropriate purity level.
|
|
An instance of the type class must provide method implementations
|
|
that are at least as pure as the method declaration.
|
|
|
|
@node Impure goals
|
|
@section Marking a goal as impure
|
|
|
|
If predicate @code{p/N} is declared to be @code{impure} (@code{semipure})
|
|
then all calls to @code{p/N} must be annotated
|
|
with @code{impure} (@code{semipure}):
|
|
|
|
@example
|
|
impure p(X1, X2, @dots{}, XN)
|
|
@end example
|
|
|
|
If function @code{f/N} is declared to be @code{impure} (@code{semipure})
|
|
then all applications of @code{f/N}
|
|
must be obtained by unification with a variable
|
|
and the unification goal as a whole be annotated with @code{impure}
|
|
|
|
@example
|
|
impure X = f(X1, X2, @dots{}, XN)
|
|
@end example
|
|
|
|
Any call or unification goal containing a non-local variable
|
|
with inst @code{any} that appears in a negated context
|
|
(i.e., in a negation or in the condition of an if-then-else goal)
|
|
must be given an @code{impure} annotation
|
|
because it may violate referential transparency.
|
|
|
|
Compound goals should not have purity annotations.
|
|
|
|
The compiler will report an error
|
|
if a required purity annotation is omitted from a call or unification goal
|
|
or if a @code{semipure} annotation is used
|
|
where an @code{impure} annotation is required.
|
|
The compiler will report a warning
|
|
if a semipure goal is annotated with @code{impure}
|
|
or a pure goal is annotated with @code{semipure}.
|
|
|
|
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
|
|
|
|
Predicates that are implemented in terms of impure or semipure predicates
|
|
are assumed to have the least of the purity of the goals in their body.
|
|
The declared purity of a predicate
|
|
must not be more pure than the inferred purity;
|
|
if it is, the compiler must generate an error.
|
|
If the declared purity is less pure than the inferred purity,
|
|
the compiler should issue a warning
|
|
(this is similar to the above case for goals).
|
|
Because the inferred purity of the predicate
|
|
is calculated from the declared purity of the calls it executes,
|
|
the lowest purity bound is propagated up
|
|
from callee to caller through the program.
|
|
|
|
In some cases,
|
|
the impurity of a predicate's body is an implementation detail
|
|
which should not be exposed to callers.
|
|
These predicates are pure or semipure
|
|
even though they call impure or semipure predicates.
|
|
The only way for the programmer to stop the propagation of impurity
|
|
is to explicitly promise that the predicate or function is pure or semipure.
|
|
|
|
Of course, the Mercury compiler cannot verify
|
|
that the predicate's purity matches the promise,
|
|
so it is the programmer's responsibility to ensure this.
|
|
If a predicate is promised pure or semipure and is not,
|
|
the behaviour of the program is undefined.
|
|
|
|
The programmer may promise that a predicate or function is pure or semipure
|
|
using the @code{promise_pure} and @code{promise_semipure} pragmas:
|
|
|
|
@example
|
|
:- pragma promise_pure(@var{Name}/@var{Arity}).
|
|
:- pragma promise_semipure(@var{Name}/@var{Arity}).
|
|
@end example
|
|
|
|
Programmers should be very careful
|
|
about mixing code that is promised pure
|
|
with impure predicates or functions that may manipulate the same hidden state
|
|
(for example, the impure predicates
|
|
used to implement a predicate that is promised pure);
|
|
the @samp{promise_pure} declaration is supposed to promise that
|
|
impure code cannot change the declarative semantics of pure code.
|
|
The module system can be used to minimize the possibility
|
|
of making errors with such code,
|
|
by keeping impure predicates or functions
|
|
behind the interface where code is promised pure.
|
|
|
|
Note that the @samp{promise_pure}, @samp{promise_semipure},
|
|
and @samp{promise_impure} scopes described in @ref{Goals}
|
|
may be used to promise purity at the finer level of goals within clauses.
|
|
|
|
@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 foreign_decl("C", "#include <limits.h>").
|
|
:- pragma foreign_decl("C", "extern MR_Integer max;").
|
|
|
|
:- pragma foreign_code("C", "MR_Integer max;").
|
|
|
|
:- impure pred init_max is det.
|
|
:- pragma foreign_proc("C",
|
|
init_max,
|
|
[will_not_call_mercury],
|
|
"
|
|
max = INT_MIN;
|
|
").
|
|
|
|
:- impure pred set_max(int::in) is det.
|
|
:- pragma foreign_proc("C",
|
|
set_max(X::in),
|
|
[will_not_call_mercury],
|
|
"
|
|
if (X > max) max = X;
|
|
").
|
|
|
|
:- semipure func get_max = (int::out) is det.
|
|
:- pragma foreign_proc("C",
|
|
get_max = (X::out),
|
|
[promise_semipure, 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 Max = get_max
|
|
).
|
|
@end example
|
|
|
|
@node Higher-order impurity
|
|
@section Using impurity with higher-order code
|
|
|
|
Higher-order code can manipulate impure or semipure predicates and functions,
|
|
provided that explicit purity annotations are used in three places:
|
|
on the higher-order types, on lambda expressions, and on higher-order calls.
|
|
(There are no purity annotations on higher-order insts and modes, however.)
|
|
|
|
@menu
|
|
* Purity annotations on higher-order types::
|
|
* Purity annotations on lambda expressions::
|
|
* Purity annotations on higher-order calls::
|
|
@end menu
|
|
|
|
@node Purity annotations on higher-order types
|
|
@subsection Purity annotations on higher-order types
|
|
|
|
Ordinary higher-order types,
|
|
such as @samp{pred(T1, T2)} and @samp{func(T1, T2) = T},
|
|
represent only pure predicates or pure functions.
|
|
But for each ordinary higher-order type @var{Foo},
|
|
there are two corresponding types
|
|
@samp{semipure @var{Foo}} and @samp{impure @var{Foo}}.
|
|
These types can be used for higher-order code
|
|
that needs to manipulate impure or semipure procedures.
|
|
For example the type @samp{impure func(int) = int}
|
|
represents impure functions from @code{int} to @code{int}.
|
|
|
|
There are no implicit conversions and no subtyping relationship
|
|
between ordinary higher-order types
|
|
and the corresponding impure or semipure higher-order types.
|
|
However, a value of an ordinary higher-order type
|
|
can be explicitly ``converted''
|
|
to a value of an impure (or semipure) higher-order type
|
|
by wrapping it in an impure (or semipure) lambda expression
|
|
that just calls the pure higher-order term.
|
|
|
|
@node Purity annotations on lambda expressions
|
|
@subsection Purity annotations on lambda expressions
|
|
|
|
Purity annotations are required on lambda expressions
|
|
that call semipure or impure code.
|
|
Lambda expressions can be declared as @samp{semipure} or @samp{impure}
|
|
by including such an annotation
|
|
before the @samp{pred} or @samp{func} identifier in the lambda expression.
|
|
Such lambda expressions have
|
|
the corresponding @samp{semipure} or @samp{impure} higher-order type.
|
|
For example, the expression
|
|
|
|
@example
|
|
(impure func(X) = Y :- semipure get_max(Y), impure set_max(X))
|
|
@end example
|
|
|
|
@noindent
|
|
is an example of an impure function lambda expression
|
|
with type @samp{(impure func(int) = int)},
|
|
and the expression
|
|
|
|
@example
|
|
(impure pred(X::in, Y::out) is det :-
|
|
semipure get_max(Y),
|
|
impure set_max(X))
|
|
@end example
|
|
is an example of an impure predicate lambda expression
|
|
with type @samp{impure pred(int, int)}.
|
|
|
|
@node Purity annotations on higher-order calls
|
|
@subsection Purity annotations on higher-order calls
|
|
|
|
Any calls to impure or semipure higher-order terms
|
|
must be explicitly annotated as such.
|
|
For impure or semipure higher-order predicates, the annotation is indicated
|
|
by putting @samp{impure} or @samp{semipure} before the call.
|
|
For example:
|
|
|
|
@example
|
|
:- func foo(impure pred(int)) = int.
|
|
:- mode foo(in(pred(out) is det)) = out is det.
|
|
|
|
foo(ImpurePred) = X1 + X2 :-
|
|
% Using higher-order syntax.
|
|
impure ImpurePred(X1),
|
|
% Using the call/N syntax.
|
|
impure call(ImpurePred, X2).
|
|
@end example
|
|
|
|
For calling impure or semipure higher-order functions,
|
|
the notation is different than what you might expect.
|
|
In addition to using an @samp{impure} or @samp{semipure} operator
|
|
on the unification which invokes the higher-order function application,
|
|
you must also use @samp{impure_apply} or @samp{semipure_apply}
|
|
rather than using @samp{apply} or higher-order syntax.
|
|
@c XXX it would be nicer to change the implementation to support
|
|
@c nice syntax, rather than documenting this hack
|
|
For example:
|
|
|
|
@example
|
|
:- func map(impure func(T1) = T2, list(T1)) = list(T2).
|
|
|
|
map(_ImpureFunc, []) = [].
|
|
map(ImpureFunc, [X|Xs]) = [Y|Ys] :-
|
|
impure Y = impure_apply(ImpureFunc, X),
|
|
impure Ys = map(ImpureFunc, Ys).
|
|
@end example
|
|
|
|
@node Solver types
|
|
@chapter Solver types
|
|
|
|
@menu
|
|
* The any inst::
|
|
* Abstract solver type declarations::
|
|
* Solver type definitions::
|
|
* Implementing solver types::
|
|
* Solver types and negated contexts::
|
|
@end menu
|
|
|
|
Solver types are an experimental addition to the language
|
|
supporting the implementation of constraint solvers.
|
|
A program may place constraints on and between variables of a solver type,
|
|
limiting the values those variables may take on before they are actually bound.
|
|
For example, if @code{X} and @code{Y} are variables
|
|
belonging to a constrained integer solver type,
|
|
we might place constraints upon them such that
|
|
@w{@code{X > 3 + Y}} and @w{@code{Y =< 7}}.
|
|
A later attempt to unify @code{Y} with @code{10} will fail
|
|
(it would violate the second constraint);
|
|
similarly an attempt to unify @code{X} with @code{5} and @code{Y} with @code{4}
|
|
would fail (it would violate the first constraint).
|
|
|
|
@node The any inst
|
|
@section The @samp{any} inst
|
|
|
|
Variables with solver types can have one of three possible insts:
|
|
@code{free}, @code{ground} or @code{any}.
|
|
A variable with a solver type with inst @code{any}
|
|
may not (yet) be semantically ground, in the following sense:
|
|
if a variable is semantically ground,
|
|
then the set of values it unifies with form an equivalence class;
|
|
if a variable is non-ground,
|
|
then the set of values it unifies with do not form an equivalence class.
|
|
|
|
More formally, @code{X} is ground
|
|
if for values @code{Y} and @code{Z} that unify with @code{X},
|
|
it is the case that @code{Y} and @code{Z} also unify with each other.
|
|
@code{X} is non-ground
|
|
if there are values @code{Y} and @code{Z} that unify with @code{X},
|
|
but which do not unify with each other.
|
|
|
|
A non-solver type value will have inst @code{any}
|
|
if it is constructed using one or more inst @code{any} values.
|
|
|
|
The builtin modes @code{ia} and @code{oa}
|
|
are equivalent to @code{in(any)} and @code{out(any)} respectively.
|
|
|
|
@node Abstract solver type declarations
|
|
@section Abstract solver type declarations
|
|
|
|
The type declarations
|
|
|
|
@example
|
|
:- solver type t1.
|
|
:- solver type t2(T1, T2).
|
|
@end example
|
|
|
|
@noindent
|
|
declare types @code{t1/0} and @code{t2/2} to be abstract solver types.
|
|
Abstract solver type declarations are
|
|
identical to ordinary abstract type declarations
|
|
except for the @code{solver} keyword.
|
|
|
|
@node Solver type definitions
|
|
@section Solver type definitions
|
|
|
|
A solver type definition takes the following form:
|
|
|
|
@example
|
|
@group
|
|
:- solver type @var{solver_type}
|
|
where representation is @var{representation_type},
|
|
ground is @var{ground_inst},
|
|
any is @var{any_inst},
|
|
constraint_store is @var{mutable_decls},
|
|
equality is @var{equality_pred},
|
|
comparison is @var{comparison_pred}.
|
|
@end group
|
|
@end example
|
|
|
|
The @code{representation} attribute is mandatory.
|
|
The @var{ground_inst} and @var{any_inst} attributes are optional
|
|
and default to @code{ground}.
|
|
The @code{constraint_store} attribute is mandatory:
|
|
@var{mutable_decls} must be either a single mutable declaration
|
|
(@pxref{Module-local mutable variables}),
|
|
or a comma separated list of mutable declarations in brackets.
|
|
The @code{equality} and @code{comparison} attributes are optional,
|
|
although a solver type without equality would not be very useful.
|
|
The attributes that are not omitted must appear in the order shown above.
|
|
|
|
The @var{representation_type}
|
|
is the type used to implement the @var{solver_type}.
|
|
A two-tier scheme of this kind is necessary for a number of reasons,
|
|
including
|
|
@itemize @bullet
|
|
@item
|
|
a semantic gap is necessary to accommodate the fact that
|
|
non-ground @var{solver_type} values
|
|
may be represented by ground @var{representation_type} values
|
|
(in the context of the corresponding constraint solver state);
|
|
@item
|
|
this approach greatly simplifies
|
|
the definition of equality and comparison predicates for the @var{solver_type}.
|
|
@end itemize
|
|
|
|
@c XXX The following paragraph describes the old support for automatic
|
|
@c initialisation of solver types. We no longer officially support
|
|
@c automatic initialisation as part of the language but the compiler
|
|
@c still contains the code necessary to implement it.
|
|
@c
|
|
@c The @code{initialisation_pred} is the name of a predicate defined in the
|
|
@c same module as the solver type, with the following signature:
|
|
@c
|
|
@c @example
|
|
@c :- pred initialisation_pred(solver_type::out(any)) is det.
|
|
@c @end example
|
|
@c
|
|
@c Calls to this predicate are inserted automatically by the compiler when a
|
|
@c @code{free} @code{solver_type} variable has to be given inst @code{any}.
|
|
@c (The initialisation predicate is responsible for registering the new,
|
|
@c unbound variable with the corresponding constraint solver state.)
|
|
|
|
The @var{ground_inst} is the inst associated with
|
|
@var{representation_type} values denoting @code{ground}
|
|
@var{solver_type} values.
|
|
|
|
The @var{any_inst} is the inst associated with @var{representation_type} values
|
|
denoting @code{any} @code{solver_type} values.
|
|
|
|
The compiler constructs four impure functions
|
|
for converting between @var{solver_type} values
|
|
and @var{representation_type} values
|
|
(@var{name} is the function symbol used to name @var{solver_type}
|
|
and @var{arity} is the number of type parameters it takes):
|
|
|
|
@example
|
|
:- impure func 'representation of ground @var{name}/@var{arity}'(@var{solver_type}) =
|
|
@var{representation_type}.
|
|
:- mode 'representation of ground @var{name}/@var{arity}'(in) =
|
|
out(@var{ground_inst}) is det.
|
|
|
|
:- impure func 'representation of any @var{name}/@var{arity}'(@var{solver_type}) =
|
|
@var{representation_type}.
|
|
:- mode 'representation of any @var{name}/@var{arity}'(in(any)) =
|
|
out(@var{any_inst}) is det.
|
|
|
|
:- impure func 'representation to ground @var{name}/@var{arity}'(@var{representation_type}) =
|
|
@var{solver_type}.
|
|
:- mode 'representation to ground @var{name}/@var{arity}'(in(@var{ground_inst})) =
|
|
out is det.
|
|
|
|
:- impure func 'representation to any @var{name}/@var{arity}'(@var{representation_type}) =
|
|
@var{solver_type}.
|
|
:- mode 'representation to any @var{name}/@var{arity}'(in(@var{any_inst})) =
|
|
out(any) is det.
|
|
@end example
|
|
|
|
These functions are impure because of the semantic gap issue mentioned above.
|
|
|
|
Solver types may be exported from their defining module,
|
|
but only in an abstract form.
|
|
This requires the full definition
|
|
to appear in the implementation section of the module,
|
|
and an abstract declaration like the following in its interface:
|
|
|
|
@example
|
|
:- solver type @var{solver_type}.
|
|
@end example
|
|
|
|
If a solver type is exported,
|
|
then its representation type,
|
|
and, if specified, its equality and/or comparison predicates
|
|
must also exported from the same module.
|
|
|
|
If a solver type has no equality predicate specified,
|
|
then the compiler will generate an equality predicate
|
|
that throws an exception of type @samp{exception.software_error/0} when called.
|
|
|
|
Likewise, if a solver type has no equality comparison specified,
|
|
then the compiler will generate a comparison predicate
|
|
that throws an exception of type @samp{exception.software_error/0} when called.
|
|
|
|
If provided,
|
|
any mutable declarations given for the @code{constraint_store} attribute
|
|
are equivalent to separate mutable declarations;
|
|
their association with the solver type is for the purposes of documentation.
|
|
That is,
|
|
|
|
@example
|
|
:- solver type t
|
|
where @dots{},
|
|
constraint_store is [ mutable(a, int, 42, ground, []),
|
|
mutable(b, string, "Hi", ground, [])
|
|
],
|
|
@dots{}
|
|
@end example
|
|
|
|
@noindent
|
|
is equivalent to
|
|
|
|
@example
|
|
:- solver type t
|
|
where @dots{}
|
|
:- mutable(a, int, 42, ground, []).
|
|
:- mutable(b, string, "Hi", ground, []).
|
|
@end example
|
|
|
|
@node Implementing solver types
|
|
@section Implementing solver types
|
|
|
|
A solver type is an abstraction,
|
|
implemented using a combination of a private representation type
|
|
and a constraint store.
|
|
|
|
The constraint store is an (impure) piece of state
|
|
used to keep track of the extant constraints on variables of the solver type.
|
|
This will typically be implemented using foreign code.
|
|
|
|
It is important that changes to the constraint store
|
|
are properly trailed (see @ref{Trailing})
|
|
so that changes can be undone on backtracking.
|
|
|
|
The solver type implementation should provide functions and predicates
|
|
@itemize @bullet
|
|
@item
|
|
to construct and deconstruct solver type values,
|
|
@item
|
|
to place constraints on solver type variables,
|
|
@item
|
|
to convert @code{any} solver type variables to @code{ground} if possible
|
|
(this is obviously an impure operation --- see @ref{Impurity}),
|
|
@item
|
|
to convert solver type values to non-solver type values
|
|
(again, this is impure
|
|
and requires the argument solver type values be sufficiently ground),
|
|
@item
|
|
to ask questions about the extant constraints on solver type variables
|
|
without constraining them further
|
|
(this too is impure because the set of constraints on a variable
|
|
may change during execution of the program).
|
|
@end itemize
|
|
|
|
@node Solver types and negated contexts
|
|
@section Solver types and negated contexts
|
|
|
|
Mercury's negation and if-then-else goals
|
|
(and hence also inequalities and universal quantifications)
|
|
are implemented using @emph{negation as failure},
|
|
meaning that the failure to find a proof of one statement
|
|
is regarded as a proof of its negation.
|
|
Negation as failure is sound
|
|
provided that no non-local variable becomes further bound
|
|
during the execution of a goal which may be negated.
|
|
This includes negated goals themselves,
|
|
as well as the conditions of if-then-elses,
|
|
which are negated iff they fail without producing any solution,
|
|
and the bodies of pred or func expressions,
|
|
which may be called or applied in one of the other contexts,
|
|
or indeed in another pred or func expression.
|
|
|
|
Mercury checks that any solver variables that are used in the above contexts
|
|
are used in such a way that negation as failure remains sound.
|
|
In the case of negation and if-then-else goals,
|
|
if any non-local solver type variable or higher-order variable
|
|
with inst @code{any} is used in a negated context,
|
|
the goal must be placed inside
|
|
a @code{promise_pure}, @code{promise_semipure}, or @code{promise_impure} scope.
|
|
The first two promises assert that (among other things)
|
|
no solver variable becomes further bound in the negated context.
|
|
The third promise makes the weaker assertion that the goal satisfies
|
|
the requirements of all impure goals
|
|
(namely, that it does not interfere with the semantics of other pure goals).
|
|
|
|
In the case of pred and func expressions, Mercury allows three possibilities.
|
|
The higher-order value may be considered @code{ground},
|
|
which means that all non-local variables used in the body of the expression
|
|
(including those with other higher-order values) must themselves be ground.
|
|
Higher-order values that are ground
|
|
can be safely called or applied in any context, including negated contexts,
|
|
since none of their (ground) non-local variables
|
|
can become further bound by doing so.
|
|
Alternatively, the higher-order value
|
|
may be considered to have inst @code{any},
|
|
which allows non-local variables used in the body of the expression
|
|
to have inst @code{any}.
|
|
Calling or applying these values
|
|
@emph{may} further bind non-local variables,
|
|
so if this occurs in a negated context
|
|
then, as in the case of solver variables,
|
|
a promise will be required around the negation or if-then-else.
|
|
|
|
Pred and func expressions with inst @code{any}
|
|
are written using @code{any_pred} and @code{any_func}
|
|
in place of @code{pred} and @code{func}, respectively.
|
|
|
|
The third possibility is that
|
|
the higher-order value can be given an impure type
|
|
(@pxref{Higher-order impurity}).
|
|
|
|
@node Trace goals
|
|
@chapter Trace goals
|
|
|
|
Sometimes, programmers find themselves
|
|
needing to perform some side-effects in the middle of declarative code.
|
|
One example is an operation that takes so long that
|
|
users may think the program has gone into an infinite loop:
|
|
periodically printing a progress message can give them reassurance.
|
|
Another example is a program that is
|
|
too long-running for its behaviour to be analyzed via debuggers
|
|
and too complex for analysis via profilers;
|
|
a programmable logging facility generating data
|
|
for analysis by a specially-written program may be the best option.
|
|
However, inserting arbitrary side effects into declarative code
|
|
is against the spirit of Mercury.
|
|
Trace goals exist to provide a mechanism
|
|
to code these side effects in a disciplined fashion.
|
|
|
|
The format of trace goals is @code{trace @var{Params} @var{Goal}}.
|
|
@var{Goal} must be a valid goal;
|
|
@var{Params} must be a valid list of one or more trace parameters.
|
|
The following example shows all four of the available kinds of parameters:
|
|
@samp{compile_time}, @samp{run_time}, @samp{io} and @samp{state}.
|
|
(In practice, it is far more typical to have just one parameter, @samp{io}.)
|
|
|
|
@example
|
|
:- mutable(logging_level, int, 0, ground, []).
|
|
|
|
:- pred time_consuming_task(data::in, result::out) is det.
|
|
|
|
time_consuming_task(In, Out) :-
|
|
trace [
|
|
compile_time(flag("do_logging") or grade(debug)),
|
|
run_time(env("VERBOSE")),
|
|
io(!IO),
|
|
state(logging_level, !LoggingLevel)
|
|
] (
|
|
io.write_string("Time_consuming_task start\n", !IO),
|
|
( if !.LoggingLevel > 1 then
|
|
io.write_string("Input is ", !IO),
|
|
io.write(In, !IO),
|
|
io.nl(!IO)
|
|
else
|
|
true
|
|
)
|
|
),
|
|
@dots{}
|
|
% perform the actual task
|
|
@end example
|
|
|
|
The @samp{compile_time} parameter says under what circumstances
|
|
the trace goal should be included in the executable program.
|
|
In the example, at least one of two conditions has to be true:
|
|
either this module has to be compiled
|
|
with the option @samp{--trace-flag=do_logging},
|
|
or it has to be compiled in a debugging grade.
|
|
|
|
In general, the single argument of the @samp{compile_time} function symbol
|
|
is a boolean expression of primitive compile-time conditions.
|
|
Valid boolean operators in these expressions
|
|
are @samp{and}, @samp{or} and @samp{not}.
|
|
There are three kinds of primitive compile-time conditions.
|
|
The first has the form @samp{flag(@var{FlagName})},
|
|
where @var{FlagName} is an arbitrary name picked by the programmer;
|
|
this condition is true
|
|
if the module is compiled with the option @samp{--trace-flag=@var{FlagName}}.
|
|
The second has the form @samp{tracelevel(shallow)}, or @samp{tracelevel(deep)};
|
|
this condition is true (irrespective of grade)
|
|
if the module is compiled with at least the specified trace level.
|
|
The third has the form @samp{grade(GradeTest)}.
|
|
The supported @samp{GradeTests}s and their meanings are as follows.
|
|
|
|
@table @asis
|
|
@item @samp{debug}
|
|
True if the module is compiled with execution tracing enabled.
|
|
@item @samp{ssdebug}
|
|
True if the module is compiled with source-to-source debugging enabled.
|
|
@item @samp{prof}
|
|
True if the module is compiled with non-deep profiling enabled.
|
|
@item @samp{profdeep}
|
|
True if the module is compiled with deep profiling enabled.
|
|
@item @samp{par}
|
|
True if the module is compiled with parallel execution enabled.
|
|
@item @samp{trail}
|
|
True if the module is compiled with trailing enabled.
|
|
@c The next one is commented because the rbmm grades are not yet publicly
|
|
@c documented.
|
|
@c @item @samp{rbmm}
|
|
@c True if the module is compiled with region based memory management enabled.
|
|
@item @samp{llds}
|
|
True if the module is compiled with @samp{--highlevel-code} disabled.
|
|
@item @samp{mlds}
|
|
True if the module is compiled with @samp{--highlevel-code} enabled.
|
|
@item @samp{c}
|
|
True if the target language of the compilation is C.
|
|
@item @samp{csharp}
|
|
True if the target language of the compilation is C#.
|
|
@item @samp{java}
|
|
True if the target language of the compilation is Java.
|
|
@end table
|
|
@c (We may support the specification of other kinds of grades in the future.)
|
|
|
|
The @samp{run_time} parameter says under what circumstances the trace goal,
|
|
if included in the executable program, should actually be executed.
|
|
In this case, the environment variable @samp{VERBOSE} has be to set
|
|
when the program starts execution.
|
|
(It does not matter what value it is set to.)
|
|
|
|
In general, the single argument of the @samp{run_time} function symbol
|
|
is a boolean expression of primitive run-time conditions.
|
|
Valid boolean operators in these expressions
|
|
are @samp{and}, @samp{or} and @samp{not}.
|
|
There is just one primitive run-time condition.
|
|
It has the form @samp{env(@var{EnvVarName})},
|
|
this condition is true
|
|
if the environment variable @var{EnvVarName} exists
|
|
when the program starts execution.
|
|
|
|
The @samp{compile_time} and @samp{run_time} parameters
|
|
may not appear in the parameter list more than once;
|
|
programmers who want more than one condition
|
|
have to specify how (with what boolean operators)
|
|
their values should be combined.
|
|
However, it is ok for them not to appear in the parameter list at all.
|
|
If there is no @samp{compile_time} parameter,
|
|
the trace goal is always compiled into the executable;
|
|
if there is no @samp{run_time} parameter,
|
|
the trace goal is always executed (if it is compiled into the executable).
|
|
|
|
Since the trace goal may end up
|
|
either not compiled into the executable or just not executed,
|
|
it cannot bind any variables that occur in the surrounding code.
|
|
(If it were allowed to bind such variables,
|
|
then those variables would stay unbound
|
|
if either the compile time or the run time condition were false.)
|
|
This greatly restricts what trace goals can do.
|
|
|
|
The usual reason for including a trace goal
|
|
in a procedure body is to perform some I/O,
|
|
which requires access to the I/O state.
|
|
The @samp{io} parameter supplies this access.
|
|
Its argument must be the name of a state variable prefixed by @samp{!};
|
|
by convention, it is usually @samp{!IO}.
|
|
The language implementation supplies
|
|
the initial unique value of the I/O state
|
|
as the value of @samp{!.IO} at the start of the trace goal;
|
|
it requires the trace goal to give back
|
|
the final unique value of the I/O state
|
|
as the value of @samp{!.IO} current at the end of the trace goal.
|
|
|
|
Note that trace goals that wish to do I/O
|
|
must include this parameter in their parameter list
|
|
@emph{even if} the surrounding code already has access to an I/O state.
|
|
This is because otherwise,
|
|
doing any I/O inside the trace goal
|
|
would destroy the value of the current I/O state,
|
|
changing the instantiation state of the variable holding it,
|
|
and trace goals are not allowed to do that.
|
|
|
|
The @samp{io} parameter may appear in the parameter list at most once,
|
|
since it does not make sense to have
|
|
two copies of the I/O state available to the trace goal.
|
|
|
|
Besides doing I/O, trace goals may read and possibly write
|
|
the values of mutable variables.
|
|
Each mutable the trace goal wants access to should be listed
|
|
in its own @samp{state} parameter
|
|
(which may therefore appear in the parameter list more than once).
|
|
Each @samp{state} parameter has two arguments:
|
|
the first gives the name of the mutable,
|
|
while the second must be the name of a state variable prefixed by @samp{!},
|
|
e.g.@: @samp{!LoggingLevel}.
|
|
The language implementation supplies
|
|
the initial value of the mutable
|
|
as the value of (in this case) @samp{!.LoggingLevel}
|
|
at the start of the trace goal;
|
|
at the end of the trace goal,
|
|
it puts the value of @samp{!.LoggingLevel} current then
|
|
back into the mutable.
|
|
|
|
The intention here is that trace goals
|
|
should be able to access mutables that give them information
|
|
about the parameters within which they should operate.
|
|
The ability of trace goals to actually @emph{update} the values of mutables
|
|
is intended to allow the implementation of trace goals
|
|
whose actions depend on the actions executed by previous trace goals.
|
|
For example, a trace goal could test
|
|
whether the current input value is the same as the previous input value,
|
|
and if it is, then it can say so instead of printing the value out again.
|
|
Another possibility is a progress message
|
|
which is printed not for every item processed, but for every 1000th item,
|
|
reassuring users without overwhelming them with a deluge of output.
|
|
|
|
This kind of code is the @emph{only} intended use of this ability.
|
|
Any program in which the value of a mutable set by a trace goal
|
|
is inspected by code that is not itself within a trace goal
|
|
is explicitly violating the intended uses of trace goals.
|
|
Only the difficulty of implementing the required global program analysis
|
|
prevents the language design from outlawing such programs in the first place.
|
|
|
|
The compiler will not delete trace goals
|
|
from the bodies of the procedures containing them,
|
|
even though they are @samp{det} and have no outputs.
|
|
In their effect on program optimizations,
|
|
trace goals function as a kind of impure code,
|
|
but one with an implicit promise_pure around the clause in which they occur.
|
|
@c zs: I think saying the following is more likely to confuse than enlighten:
|
|
@c The trace goal scope itself acts
|
|
@c as a promise_pure scope for any impure code inside it.
|
|
Note that trace goals inside a procedure
|
|
do not prevent calls to that procedure from being optimized away.
|
|
For example,
|
|
if a predicate definition contains a single trace goal
|
|
in order to factor out the details of that goal,
|
|
calls to it may be optimized away.
|
|
This will render them ineffective;
|
|
the strict sequential semantics can be used
|
|
to inhibit such optimizations (@pxref{Formal semantics}).
|
|
|
|
@node Pragmas
|
|
@chapter Pragmas
|
|
|
|
The pragma declarations described below
|
|
are a standard part of the Mercury language,
|
|
as are the pragmas for controlling the foreign language interface
|
|
(@pxref{Foreign language 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.
|
|
* No determinism warnings:: Pragmas can be used to suppress warnings
|
|
about too loose determinism declarations.
|
|
* No dead predicate warnings:: Pragmas can be used to suppress warnings
|
|
about unused predicates.
|
|
* Format calls :: Pragmas for requesting extra checking of calls
|
|
to formatting predicates and functions.
|
|
* Source file name:: The @samp{source_file} pragma and
|
|
@samp{#@var{line}} directives provide support
|
|
for preprocessors and other tools that
|
|
generate Mercury code.
|
|
* Old pragma syntax:: Old and obsolete syntax for some pragmas.
|
|
@end menu
|
|
|
|
@node Inlining
|
|
@section Inlining
|
|
|
|
Declarations of these forms
|
|
|
|
@example
|
|
:- pragma inline(pred(@var{Name}/@var{Arity})).
|
|
:- pragma inline(func(@var{Name}/@var{Arity})).
|
|
@end example
|
|
|
|
@noindent
|
|
are a hint to the compiler that
|
|
all calls to the predicate or function
|
|
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.
|
|
|
|
Declarations of these forms
|
|
|
|
@example
|
|
:- pragma no_inline(pred(@var{Name}/@var{Arity})).
|
|
:- pragma no_inline(func(@var{Name}/@var{Arity})).
|
|
@end example
|
|
|
|
@noindent
|
|
tell the compiler not to inline the named predicate or function.
|
|
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 builtin 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(pred(@var{Name}/@var{Arity}), @var{Subst}).
|
|
:- pragma type_spec(func(@var{Name}/@var{Arity}), @var{Subst}).
|
|
@end example
|
|
|
|
@noindent
|
|
suggests to the compiler that it should create a specialized version
|
|
of the predicate or function with name @var{Name} and arity @var{Arity}
|
|
with the type substitution given by @var{Subst} applied to the argument types.
|
|
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 conjunction must have parentheses around it
|
|
if it contains two or more bindings.)
|
|
|
|
For example, the declarations
|
|
|
|
@example
|
|
:- pred map.lookup(map(K, V), K, V).
|
|
:- pragma type_spec(pred(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.
|
|
|
|
The pragma also has a form that suggests specialization
|
|
of only one mode of the predicate or function, instead of all of them:
|
|
|
|
@example
|
|
:- pragma type_spec(@var{Name}(@var{m1}, ... @var{mn}), @var{Subst}).
|
|
:- pragma type_spec(@var{Name}(@var{m1}, ... @var{mn}) = @var{mr}, @var{Subst}).
|
|
@end example
|
|
|
|
where @var{m1} etc are the modes of the arguments.
|
|
If the @samp{= @var{mr}} part is present,
|
|
it gives the mode of the function result;
|
|
if it is absent, this indicates that @var{Name} is a predicate.
|
|
|
|
@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 builtin types such as @code{int}, @code{float} and @code{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 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.
|
|
However, for the Java back-end,
|
|
user-requested type specializations are ignored.
|
|
|
|
@node Obsolescence
|
|
@section Obsolescence
|
|
|
|
Declarations of the forms
|
|
|
|
@example
|
|
:- pragma obsolete(pred(@var{Name}/@var{Arity})).
|
|
:- pragma obsolete(func(@var{Name}/@var{Arity})).
|
|
:- pragma obsolete(pred(@var{Name}/@var{Arity}),
|
|
[@var{ReplName1}/@var{ReplArity1}, ..., @var{ReplNameN}/@var{ReplArityN}]).
|
|
:- pragma obsolete(func(@var{Name}/@var{Arity}),
|
|
[@var{ReplName1}/@var{ReplArity1}, ..., @var{ReplNameN}/@var{ReplArityN}]).
|
|
@end example
|
|
|
|
@noindent
|
|
declare that the predicate or function
|
|
with name @var{Name} and arity @var{Arity} is ``obsolete'':
|
|
they instruct the compiler to issue a warning
|
|
whenever the named predicate or function is used.
|
|
The forms with a second argument tell the compiler
|
|
to suggest the use of one of the listed possible replacements.
|
|
|
|
Declarations of the forms
|
|
|
|
@example
|
|
:- pragma obsolete_proc(@var{PredName}(@var{ArgMode1}, ..., @var{ArgModeN})).
|
|
:- pragma obsolete_proc(@var{PredName}(@var{ArgMode1}, ..., @var{ArgModeN}),
|
|
[@var{ReplName1}/@var{ReplArity1}, ..., @var{ReplNameN}/@var{ReplArityN}]).
|
|
:- pragma obsolete_proc(@var{FuncName}(@var{ArgMode1}, ..., @var{ArgModeN}) = @var{RetMode}).
|
|
:- pragma obsolete_proc(@var{FuncName}(@var{ArgMode1}, ..., @var{ArgModeN}) = @var{RetMode},
|
|
[@var{ReplName1}/@var{ReplArity1}, ..., @var{ReplNameN}/@var{ReplArityN}]).
|
|
@end example
|
|
|
|
@noindent
|
|
similarly declare that the predicate named @var{PredName} with arity @var{N},
|
|
or the function named @var{FuncName} with arity @var{N},
|
|
is obsolete when called in the specified mode.
|
|
These forms also allow the specification
|
|
of an optional list of possible replacements.
|
|
|
|
These 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 or procedure,
|
|
they should leave its old version in the library,
|
|
but mark it as obsolete using one of these declarations,
|
|
and, if possible, use the suggested replacements to steer users
|
|
to their replacements (either partial or total) in 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
|
|
believes that users have had sufficient warning,
|
|
they can remove the old version entirely.
|
|
|
|
@node No determinism warnings
|
|
@section No determinism warnings
|
|
|
|
Declarations of the forms
|
|
|
|
@example
|
|
:- pragma no_determinism_warning(pred(@var{Name}/@var{Arity})).
|
|
:- pragma no_determinism_warning(func(@var{Name}/@var{Arity})).
|
|
@end example
|
|
|
|
@noindent
|
|
tell the compiler not to generate any warnings
|
|
about the determinism declarations of procedures of the predicate or function
|
|
with name @var{Name} and arity @var{Arity} not being as tight as they could be.
|
|
|
|
@samp{pragma no_determinism_warning} declarations are intended for use
|
|
in situations in which the code of a predicate has one determinism,
|
|
but the declared determinism of the procedure must be looser
|
|
due to some outside requirement.
|
|
One such situation is when a set of procedures are all possible values
|
|
of the same higher-order variable,
|
|
which requires them to have the same argument types, modes, and determinisms.
|
|
If (say) most of the procedures are @code{det}
|
|
but some are @code{erroneous} (that is, they always throws an exception),
|
|
the procedures that are declared @code{det}
|
|
but whose bodies have determinism @code{erroneous}
|
|
will get a warning saying their determinism declaration could be tighter,
|
|
unless the programmer specifies this pragma for them.
|
|
|
|
@node No dead predicate warnings
|
|
@section No dead predicate warnings
|
|
|
|
Declarations of the forms
|
|
|
|
@example
|
|
:- pragma consider_used(pred(@var{Name}/@var{Arity})).
|
|
:- pragma consider_used(func(@var{Name}/@var{Arity})).
|
|
@end example
|
|
|
|
@noindent
|
|
tells the compiler to consider the predicate or function
|
|
with name @var{Name} and arity @var{Arity} to be used,
|
|
and not generate any dead procedure/predicate/function warnings
|
|
either for the named predicate or function,
|
|
@emph{or} for the other predicates and functions that it calls,
|
|
either directly or indirectly.
|
|
|
|
@samp{pragma consider_used} declarations are intended for use in situations
|
|
in which the code that was intended to call such a predicate or function
|
|
is not yet written.
|
|
|
|
@node Format calls
|
|
@section Format calls
|
|
|
|
The @samp{format_call} pragma asks the compiler
|
|
to perform the same checks on calls to the named predicate or function
|
|
as it performs for calls to the following
|
|
formatting predicates and function in the Mercury standard library.
|
|
|
|
The Mercury standard library has a function and a predicate
|
|
to format a given sequence of values according to a format string,
|
|
like this:
|
|
|
|
@example
|
|
string.format("Count = %d, Total = %5.2f, Average = %5.2f\n",
|
|
[i(Count), f(Total), f(Total/float(Count))], FormatStr)
|
|
|
|
FormatStr = string.format("Count = %d, Total = %5.2f, Average = %5.2f\n",
|
|
[i(Count), f(Total), f(Total/float(Count))])
|
|
@end example
|
|
|
|
@noindent
|
|
and predicates that immediately output the resulting formatted string,
|
|
like this:
|
|
|
|
@example
|
|
io.format(
|
|
"Count = %d, Total = %5.2f, Average = %5.2f\n",
|
|
[i(Count), f(Total), f(Total/float(Count))], !IO)
|
|
|
|
io.format(OutputStream,
|
|
"Count = %d, Total = %5.2f, Average = %5.2f\n",
|
|
[i(Count), f(Total), f(Total/float(Count))], !IO)
|
|
|
|
stream.string_writer.format(StringWriterStream,
|
|
"Count = %d, Total = %5.2f, Average = %5.2f\n",
|
|
[i(Count), f(Total), f(Total/float(Count))], !StringWriterState)
|
|
@end example
|
|
|
|
@noindent
|
|
These four predicates and one function
|
|
all take a format string argument, and a values_to_format argument.
|
|
The format string argument in all the examples above is
|
|
@example
|
|
"Count = %d, Total = %5.2f, Average = 5.2%f\n"
|
|
@end example
|
|
@noindent
|
|
while the values_to_format argument is
|
|
@example
|
|
[i(Count), f(Total), f(Total/float(Count))]
|
|
@end example
|
|
|
|
In this example, @code{%d} means that the corresponding value
|
|
should be output as a signed integer, using as many characters as needed,
|
|
and @code{%5.2f} means that the corresponding value
|
|
should be formatted as a floating point number,
|
|
using five characters, of which two are after the decimal point.
|
|
|
|
Mercury does not allow
|
|
values of different types to be stored in the same list,
|
|
so the elements of that list are actually values of the @code{poly_type} type,
|
|
whose definition in the @code{string} module of the standard library is
|
|
@example
|
|
:- type poly_type
|
|
---> f(float)
|
|
; i(int)
|
|
; i8(int8)
|
|
; i16(int16)
|
|
; i32(int32)
|
|
; i64(int64)
|
|
; u(uint)
|
|
; u8(uint8)
|
|
; u16(uint16)
|
|
; u32(uint32)
|
|
; u64(uint64)
|
|
; s(string)
|
|
; c(char).
|
|
@end example
|
|
@noindent
|
|
As you can see, each function symbol in this type
|
|
wraps up a value of a builtin type,
|
|
and thus converts it to the same @code{poly_type} type.
|
|
|
|
With one exception,
|
|
every occurrence of a percent sign in the format string
|
|
is intended to start a @emph{conversion specifier},
|
|
which specifies how the corresponding entry in the value list
|
|
should be converted to a string.
|
|
(The exception is that the double percent sign @code{%%}
|
|
simply says that the output should be a single percent sign;
|
|
the doubling up escapes
|
|
the special conversion-introduction role of the character.)
|
|
Each conversion specifier consists of a percent sign,
|
|
zero or more non-alphabetic characters such as @samp{5},
|
|
and an alphabetic @emph{conversion character} such as @code{d} or @code{f}.
|
|
|
|
The format string and the values list must match.
|
|
There should be exactly one element in the value list
|
|
for each conversion specifier,
|
|
and the Nth value in the value list must satisfy
|
|
the requirements of the Nth conversion specifier in the format string.
|
|
|
|
For example, the call
|
|
@example
|
|
string.format("Count = %d, Total = %5.2f, Average = %5.2f\n",
|
|
[i(Count), f(Total/float(Count))], FormatStr)
|
|
@end example
|
|
@noindent
|
|
would not work, because the format string contains three conversion specifiers,
|
|
but the value list contains only two values.
|
|
|
|
The call
|
|
@example
|
|
string.format("Count = %f, Total = %d, Average = %5.2f\n",
|
|
[i(Count), f(Total), f(Total/float(Count))], FormatStr)
|
|
@end example
|
|
@noindent
|
|
would not work either,
|
|
because the first specifier's conversion character, @code{f},
|
|
requires the corresponding value to have the form @code{f(Float)},
|
|
but the corresponding value is @code{i(Count)}.
|
|
The conversion character in the second specifier, @code{d},
|
|
accepts any signed integer as the value,
|
|
so the second value could be any of @code{i(Int)}, @code{i8(Int8)},
|
|
@code{i16(Int16)}, @code{i32(Int32)}, or @code{i64(Int64)},
|
|
but not @code{f(Float)}.
|
|
|
|
For the full set of the rules, please see the documentation
|
|
of @code{string.format} in the Mercury Library Reference Manual;
|
|
the same rules apply to @code{io.format}
|
|
and @code{stream.string_writer.format)} as well.
|
|
|
|
the Mercury compiler checks calls
|
|
to the formatting predicates and function in the Mercury standard library,
|
|
specifically
|
|
|
|
@table @asis
|
|
@item predicate @code{io.format/4}
|
|
@item predicate @code{io.format/5}
|
|
@item predicate @code{stream.string_writer.format/5}
|
|
@item function @code{string.format/2}
|
|
@item predicate @code{string.format/3}
|
|
@end table
|
|
|
|
for inconsistencies between the format string and the value list,
|
|
generating a report for each such inconsistency.
|
|
This improves both program reliability
|
|
(because programmers get the problem brought to their attention
|
|
even if the bad call is never executed)
|
|
and programmer productivity
|
|
(because programmers don't have to write test cases
|
|
just to force the execution of all calls to these predicates).
|
|
However, the compiler can perform this check
|
|
only if the predicate or function
|
|
containing the call to the formatting predicate or function
|
|
also constructs the format string and the value list.
|
|
Most calls to formatting predicates satisfy this condition, but not all.
|
|
|
|
The main exceptions are predicates intended for logging,
|
|
whose general logic follows this general pattern:
|
|
|
|
@example
|
|
maybe_log_message(LogInfo, FormatString, Values, !IO) :-
|
|
log_info_should_log(LogInfo, ShouldLog),
|
|
(
|
|
ShouldLog = no
|
|
;
|
|
ShouldLog = yes,
|
|
io.format(FormatString, Values, !IO),
|
|
io.flush_output(!IO)
|
|
).
|
|
@end example
|
|
|
|
In this case, the compiler cannot check
|
|
the call to @code{io.format} in this predicate,
|
|
because the format string and the values list both come from the caller.
|
|
If some caller supplies format string and values list arguments
|
|
that are inconsistent with one another,
|
|
the call to @code{io.format} will throw an exception.
|
|
|
|
The purpose of the @samp{format_call} pragma is to remedy this.
|
|
The pragma
|
|
@example
|
|
:- pragma format_call(pred(maybe_log_message/5),
|
|
format_string_values(2, 3)).
|
|
@end example
|
|
@noindent
|
|
tells the compiler that calls to this predicate
|
|
should be checked the same way
|
|
as calls to the four formatting predicates and one formatting function
|
|
listed the above,
|
|
with the format string in the second argument,
|
|
and the values in list in the third.
|
|
This way, while @code{maybe_log_message} cannot ensure
|
|
that @code{FormatString} and @code{Values} will match,
|
|
its @emph{callers} can do so.
|
|
|
|
In general, this pragma may take these four forms.
|
|
|
|
@example
|
|
:- pragma format_call(pred(@var{Name}/@var{Arity}),
|
|
format_string_values(@var{FormatStringArgNum}, @var{ValuesArgNum})).
|
|
:- pragma format_call(func(@var{Name}/@var{Arity}),
|
|
format_string_values(@var{FormatStringArgNum}, @var{ValuesArgNum})).
|
|
:- pragma format_call(pred(@var{Name}/@var{Arity}),
|
|
[format_string_values(@var{FS1}, @var{V1}), ...).
|
|
:- pragma format_call(func(@var{Name}/@var{Arity}),
|
|
[format_string_values(@var{FS1}, @var{V1}), ...).
|
|
@end example
|
|
|
|
The first form is the one in the example above,
|
|
while the second is the function version.
|
|
The third and fourth forms differ from the first and second respectively
|
|
by having the second argument being not a single
|
|
@code{format_string_values(@var{FormatStringArgNum}, @var{ValuesArgNum})} term,
|
|
but a list of two or more such terms.
|
|
(One such term is also allowed,
|
|
but in that case, there is no need for the list.)
|
|
This latter capability is intended for use in situations
|
|
where predicate or function concerned
|
|
contains several (possibly conditionally executed) calls
|
|
to formatting predicates or functions
|
|
whose format strings and values come from the caller,
|
|
like this:
|
|
|
|
@example
|
|
:- maybe_quad_log_message(LogInfo,
|
|
FmtA, ValuesA1, ValuesA2,
|
|
FmtB, ValuesB1, ValuesB2, !IO) :-
|
|
...
|
|
io.format(FmtA, ValuesA1, !IO),
|
|
...
|
|
io.format(FmtA, ValuesA2, !IO),
|
|
...
|
|
io.format(FmtB, ValuesB1, !IO),
|
|
...
|
|
io.format(FmtB, ValuesB2, !IO),
|
|
...
|
|
@end example
|
|
|
|
In such cases, programmers can include a @code{format_string_values} entry
|
|
describing the argument numbers that act as the sources
|
|
for each such call, like this:
|
|
|
|
@example
|
|
:- pragma format_call(pred(maybe_quad_log_message/5),
|
|
[format_string_values(2, 3), format_string_values(2, 4),
|
|
format_string_values(5, 6), format_string_values(5, 7)]).
|
|
@end example
|
|
|
|
This will ask the compiler to check the compatibility
|
|
of all four listed argument pairs at all call sites.
|
|
|
|
@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 an 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 Old pragma syntax
|
|
@section Old pragma syntax
|
|
|
|
Many of the pragmas above specify the identity of a predicate or a function
|
|
as the entity to which the pragma applies.
|
|
Their documentation shows these pragmas to have this syntax:
|
|
@example
|
|
:- pragma @var{pragma_name}(pred(@var{Name}/@var{Arity})).
|
|
:- pragma @var{pragma_name}(func(@var{Name}/@var{Arity})).
|
|
@end example
|
|
|
|
New code should use this syntax.
|
|
However, old versions of the Mercury compiler
|
|
supported only a simpler version of this syntax, like this:
|
|
@example
|
|
:- pragma @var{pragma_name}(@var{Name}/@var{Arity}).
|
|
@end example
|
|
|
|
Since this syntax does not specify
|
|
whether the pragma is supposed to apply to a predicate or to a function,
|
|
it is ambiguous in the event that the program contains
|
|
both a predicate and a function with the given name and arity.
|
|
|
|
For backwards compatibility, the Mercury compiler still supports this syntax,
|
|
but it will now generate a warning when the program contains
|
|
both a predicate and a function with the given name and arity.
|
|
It can also be asked to generate a warning for all pragmas
|
|
that should specify whether they apply to a predicate or to a function
|
|
but do not do so.
|
|
|
|
A later version of Mercury will deprecate this syntax,
|
|
and a still later version will stop supporting it.
|
|
|
|
@c which each apply their hint to both a predicate @var{Name}/@var{Arity}
|
|
@c and a function @var{Name}/@var{Arity} if both exist.
|
|
|
|
@node Implementation-dependent extensions
|
|
@chapter Implementation-dependent extensions
|
|
|
|
The Melbourne Mercury implementation supports
|
|
the following extensions to the Mercury language:
|
|
|
|
@menu
|
|
* Fact tables:: Support for very large tables of facts.
|
|
@c XXX STM
|
|
@c The documentation of STM is commented out because its support is
|
|
@c not yet complete. All such lines are preceded by XXX STM.
|
|
@c * Software Transactional Memory::
|
|
@c Support for synchronisation of threads without
|
|
@c explicit locking.
|
|
* 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.
|
|
@c * Tail recursion check:: Require that a predicate is tail recursive.
|
|
* Feature sets:: Support for checking that optional features of
|
|
the implementation are supported at compile
|
|
time.
|
|
* Trailing:: Undoing side-effects on backtracking.
|
|
|
|
@end menu
|
|
|
|
@node Fact tables
|
|
@section Fact tables
|
|
|
|
Large tables of facts can be compiled using a different algorithm
|
|
that is more efficient and can produce more efficient code.
|
|
|
|
Declarations of the forms
|
|
|
|
@example
|
|
:- pragma fact_table(pred(@var{Name}/@var{Arity}), @var{FileName}).
|
|
:- pragma fact_table(func(@var{Name}/@var{Arity}), @var{FileName}).
|
|
@end example
|
|
|
|
@noindent
|
|
tell 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 @file{@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 @file{@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 in the current implementation,
|
|
predicates or functions defined as fact tables
|
|
can only have arguments of types @code{string}, @code{int} or @code{float}.
|
|
|
|
Another limitation is that the @samp{--high-level-code} back-end
|
|
does not support @samp{pragma fact_table}
|
|
for procedures with determinism @code{nondet} or @code{multi}.
|
|
|
|
@c XXX STM
|
|
@c @node Software Transactional Memory
|
|
@c @section Software Transactional Memory
|
|
@c
|
|
@c (Note: Software Transactional Memory is still in development and many
|
|
@c aspects c documented here might change without notice.
|
|
@c Please use with caution.)
|
|
@c
|
|
@c Software Transactional Memory or STM
|
|
@c is an method of synchronising access to shared data
|
|
@c between concurrently running threads.
|
|
@c It is an alternative to the use of explicit locking.
|
|
@c
|
|
@c The way to synchronise threads using Software Transactional Memory
|
|
@c is through the use of the @samp{atomic} scope.
|
|
@c The syntax of an atomic scope is @code{atomic @var{Params} @var{Goal}}.
|
|
@c @var{Goal} must be a valid goal;
|
|
@c @var{Params} must be a list of atomic parameters
|
|
@c which must include the @samp{outer} and @samp{inner} parameters.
|
|
@c The following example shows the use of the atomic scope:
|
|
@c
|
|
@c @example
|
|
@c :- pred add_2_atomically(stm_var(int)::in, io::di, io::uo) is cc_multi.
|
|
@c
|
|
@c add_2_atomically(TVar, IO0, IO) :-
|
|
@c atomic [ outer(IO0, IO1), inner(STM0, STM) ] (
|
|
@c read_stm_var(TVar, X, STM0, STM1),
|
|
@c Y = X + 2,
|
|
@c write_stm_var(TVar, Y, STM1, STM)
|
|
@c ),
|
|
@c io.write_string("Value of Y is ", IO1, IO2),
|
|
@c io.write(Y, IO2, IO3),
|
|
@c io.nl(IO3, IO).
|
|
@c @end example
|
|
@c
|
|
@c
|
|
@c The @samp{outer} parameter takes a pair of variables of type @samp{io.io}.
|
|
@c As the atomic scope can be seen as an operation which changes the I/O state,
|
|
@c the modes of these variables must be @code{di} and @code{uo} respectively.
|
|
@c
|
|
@c The @samp{inner} parameter takes a pair of variables of type @samp{stm}.
|
|
@c When the atomic scope is executed,
|
|
@c these variables supply and consume the @samp{stm} state
|
|
@c which can be used by the Software Transactional Memory primitives.
|
|
@c Calling these primitives requires threading the @samp{stm} state
|
|
@c in a way similar to I/O operations and,
|
|
@c as such, the modes of these variables must also be @code{di} and @code{uo}.
|
|
@c
|
|
@c The code within the atomic scope is restricted
|
|
@c in the same way as code which takes the I/O state.
|
|
@c The code within the atomic scope
|
|
@c must be either @code{det} or @code{cc_multi}.
|
|
@c Due to the way Software Transactional Memory provides synchronous behaviour,
|
|
@c it is likely that the goal will be executed more than once.
|
|
@c As it is unknown how many times (if any) the inner goal will be repeated,
|
|
@c only pure code or code which makes use of the @samp{stm} state
|
|
@c should be placed inside an atomic scope.
|
|
@c (Trace goals are permitted but should not be used for any action
|
|
@c that depends on the number of times the goal is executed).
|
|
@c
|
|
@c Using the atomic scope requires the program to explicitly import the modules
|
|
@c @samp{stm_builtin}, @samp{exception} and @samp{univ}.
|
|
@c This restriction will soon be dropped,
|
|
@c as the compiler itself will do the required imports.
|
|
@c
|
|
@c In STM systems, data shared between threads
|
|
@c is stored in @samp{Transaction Variables}.
|
|
@c This is the only form of shared data
|
|
@c which the atomic scope will synchronise.
|
|
@c @samp{Transaction Variables} can be operated on
|
|
@c using the following predicates:
|
|
@c
|
|
@c @example
|
|
@c :- pred new_stm_var(T::in, stm_var(T)::out, io::di, io::uo) is det.
|
|
@c
|
|
@c :- pred read_stm_var(stm_var(T)::in, T::out, stm::di, stm::uo) is det.
|
|
@c
|
|
@c :- pred write_stm_var(stm_var(T)::in, T::in, stm::di, stm::uo) is det.
|
|
@c @end example
|
|
@c
|
|
@c The @samp{new_stm_var} creates a new transaction variable
|
|
@c whose the type and initial value are given by the first argument,
|
|
@c and returns a reference to it.
|
|
@c Only one copy of the transaction variable exists in memory,
|
|
@c but references to it can be duplicated.
|
|
@c Unifications and tests of references
|
|
@c affect only the references themselves,
|
|
@c and do not affect the underlying transaction variables.
|
|
@c
|
|
@c To get or set the value of the actual transaction variable,
|
|
@c programs must call
|
|
@c the builtins @samp{read_stm_var} and @samp{write_stm_var}.
|
|
@c These calls take a reference to a transaction variable
|
|
@c and either set or return the value of the transaction variable.
|
|
@c @footnote{In actual fact, write_stm_var does not update the variable.
|
|
@c The update is instead written to a log,
|
|
@c and the real transaction variable is changed
|
|
@c only when the atomic goal has completed
|
|
@c and the whole log has been validated.}
|
|
@c As the calls to @samp{read_stm_var} and @samp{write_stm_var}
|
|
@c take a pair of @samp{stm} states,
|
|
@c they can only appear within an atomic scope.
|
|
|
|
@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;
|
|
this table is sometimes called the memo table
|
|
(since it ``remembers'' previous answers).
|
|
At each procedure call, the implementation will search the memo table
|
|
to check whether the answer(s) have already been computed,
|
|
and if so, the answers will be returned directly from the memo table
|
|
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 also check at runtime for the situation
|
|
where a procedure calls itself recursively with the same arguments,
|
|
which would normally result in an 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 a ``minimal model'' semantics.
|
|
(Specifically, the minimal model computed by our implementation
|
|
is the perfect model.)
|
|
|
|
When targeting the generation of C code,
|
|
the current Mercury implementation supports
|
|
three different pragmas for tabling, to cover these three cases:
|
|
@samp{loop_check}, @samp{memo}, and @samp{minimal_model}.
|
|
(None of these are supported
|
|
when targeting the generation of C# or Java code.)
|
|
|
|
@itemize @bullet
|
|
@item
|
|
The @samp{loop_check} pragma asks only for loop checking.
|
|
With this pragma, the memo table will map each distinct set of input arguments
|
|
only to a single boolean saying whether
|
|
a call with those arguments is currently active or not;
|
|
the pragma's only effect is to cause the predicate to throw an exception
|
|
if this boolean says that the current call has the same arguments
|
|
as one of its ancestors, which indicates an infinite recursive loop.
|
|
|
|
Note that loop checking for nondet and multi predicates assumes that
|
|
calls to these predicates generate all their solutions and then fail.
|
|
If a caller asks them only for some solutions
|
|
and then cuts away all later solutions
|
|
(e.g.@: via a quantification
|
|
that only asks whether a solution satisfying a particular test exists),
|
|
then the cut-away call never gets a chance
|
|
to record the fact that it is not longer active.
|
|
The next call to that predicate with the same arguments
|
|
will therefore think that the previous call is still active,
|
|
and will consider this call to be an infinite loop.
|
|
@item
|
|
The @samp{memo} pragma asks for both loop checking and memoization.
|
|
With this pragma, the memo table will map each distinct set of input arguments
|
|
either to the set of results computed previously for those arguments,
|
|
or to an indication that the call is still active
|
|
and thus those results are still being computed.
|
|
This predicate will thus look for infinite recursive loops
|
|
(and throw an exception if and when it finds one)
|
|
but it will also record all its solutions in the memo table,
|
|
and will avoid recomputing solutions
|
|
that are already available in the memo table.
|
|
@item
|
|
The @samp{minimal_model} pragma asks
|
|
for the computation of a ``minimal model'' semantics.
|
|
These differ from the @samp{memo} pragma in that
|
|
the detection of what appears to be an infinite recursive loop is not fatal.
|
|
The implementation will consider
|
|
the apparently infinitely recursive calls to fail
|
|
if the call concerned has no way of computing
|
|
any solutions it has not already computed and recorded,
|
|
and if it does have such a way,
|
|
then it switches the execution to explore those ways
|
|
before coming back to the apparently infinitely recursive call.
|
|
|
|
Minimal model evaluation is applicable
|
|
only to procedures that can succeed more than once,
|
|
and only in grades that explicitly support it.
|
|
@end itemize
|
|
|
|
The syntax for each of these declarations is
|
|
|
|
@example
|
|
:- pragma memo(pred(@var{Name}/@var{Arity})).
|
|
:- pragma memo(pred(@var{Name}/@var{Arity}), [@var{list of tabling attributes}]).
|
|
:- pragma loop_check(pred(@var{Name}/@var{Arity})).
|
|
:- pragma loop_check(pred(@var{Name}/@var{Arity}), [@var{list of tabling attributes}]).
|
|
:- pragma minimal_model(pred(@var{Name}/@var{Arity})).
|
|
:- pragma minimal_model(pred(@var{Name}/@var{Arity}), [@var{list of tabling attributes}]).
|
|
@end example
|
|
|
|
@noindent
|
|
and the corresponding versions in which
|
|
@samp{pred} is replaced with @samp{func}.
|
|
The @samp{pred(@var{Name}/@var{Arity})} or @samp{func(@var{Name}/@var{Arity})}
|
|
part specifies the predicate or function to which the declaration applies.
|
|
At most one of these declarations may be specified
|
|
for any given predicate or function.
|
|
|
|
Pragmas using the above syntax specify
|
|
a declaration that applies to all the modes of a predicate or function.
|
|
Programmers can request the application of tabling
|
|
to only one particular mode of a predicate or function,
|
|
via declarations such as these:
|
|
|
|
@example
|
|
:- pragma memo(@var{Name}(in, in, out)).
|
|
:- pragma memo(@var{Name}(in, in, out), [@var{list of tabling attributes}]).
|
|
:- pragma loop_check(@var{Name}(in, out)).
|
|
:- pragma loop_check(@var{Name}(in, out), [@var{list of tabling attributes}]).
|
|
:- pragma minimal_model(@var{Name}(in, in, out, out)).
|
|
:- pragma minimal_model(@var{Name}(in, in, out, out), [@var{list of tabling attributes}]).
|
|
@end example
|
|
|
|
All the above example pragmas are for predicates.
|
|
For functions, the first argument of the pragma would include
|
|
the mode of the function result as well, like this:
|
|
|
|
@example
|
|
:- pragma memo(@var{Name}(in, in) = out, [@var{list of tabling attributes}]).
|
|
@end example
|
|
|
|
Because all variants of tabling record the values of input arguments,
|
|
and all except @samp{loop_check} also record the values of output arguments,
|
|
you cannot apply any of these pragmas to procedures
|
|
whose arguments' modes include any unique component.
|
|
|
|
Tabled evaluation of a predicate or function
|
|
that has an argument whose type is a foreign type
|
|
will result in a run-time error,
|
|
unless the foreign type is one for which
|
|
the @samp{can_pass_as_mercury_type} and @samp{stable} assertions
|
|
have been made (@pxref{Using foreign types from Mercury}).
|
|
|
|
The optional list of attributes allows programmers
|
|
to control some aspects of the management of the memo table(s)
|
|
of the procedure(s) affected by the pragma.
|
|
|
|
The @samp{allow_reset} attribute asks the compiler
|
|
to define a predicate that, when called, resets the memo table.
|
|
The name of this predicate will be ``table_reset_for'',
|
|
followed by the name of the tabled predicate, followed by its arity,
|
|
and (if the predicate has more than one mode) by the mode number
|
|
(the first declared mode is mode 0, the second is mode 1, and so on).
|
|
These three or four components are separated by underscores.
|
|
The reset predicate takes a di/uo pair of I/O states as arguments.
|
|
The presence of these I/O state arguments in the reset predicate,
|
|
and the fact that tabled predicates cannot have unique arguments
|
|
together imply that a memo table cannot be reset
|
|
while a call using that memo table is active.
|
|
|
|
The @samp{statistics} attribute asks the compiler
|
|
to define a predicate that, when called,
|
|
returns statistics about the memo table.
|
|
The name of this predicate will be ``table_statistics_for'',
|
|
followed by the name of the tabled predicate, followed by its arity,
|
|
and (if the predicate has more than one mode) by the mode number
|
|
(the first declared mode is mode 0, the second is mode 1, and so on).
|
|
These three or four components are separated by underscores.
|
|
The statistics predicate takes three arguments.
|
|
The second and third are a di/uo pair of I/O states,
|
|
while the first is an output argument that contains information
|
|
about accesses to and modifications of the procedure's memo table,
|
|
both since the creation of the table,
|
|
and since the last call to this predicate.
|
|
The type of this argument is defined in the file table_builtin.m
|
|
in the Mercury standard library.
|
|
That module also contains a predicate for printing out this information
|
|
in a programmer-friendly format.
|
|
|
|
As mentioned above, the Mercury compiler implements tabling
|
|
only when targeting the generation of C code.
|
|
@c ... and when the gc method is not accurate,
|
|
@c but since no-one actually uses accurate gc ...
|
|
In other grades, the compiler normally generates a warning
|
|
for each tabling pragma that it is forced to ignore.
|
|
The @samp{disable_warning_if_ignored} attribute tells the compiler
|
|
not to generate such a warning for the pragma it is attached to.
|
|
Since the @samp{loopcheck} and @samp{minimal_model} pragmas
|
|
affect the semantics of the program,
|
|
and such changes should not be made silently,
|
|
this attribute may not be specified for them.
|
|
But this attribute may be specified for @samp{memo} pragmas,
|
|
since these affect only the program's performance, not its semantics.
|
|
|
|
The remaining two attributes, @samp{fast_loose} and @samp{specified},
|
|
control how arguments are looked up in the memo table.
|
|
The default implementation
|
|
looks up the @emph{value} of each input argument,
|
|
and thus requires time proportional to
|
|
the number of function symbols in the input arguments.
|
|
This is the only implementation allowed for minimal model tabling,
|
|
but for predicates tabled with the @samp{loop_check} and @samp{memo} pragmas,
|
|
programmers can also choose some other tabling methods.
|
|
|
|
The @samp{fast_loose} attribute asks the compiler to generate code
|
|
that looks up only the @emph{address} of each input argument in the memo table,
|
|
which means that the time required
|
|
is linear only in the @emph{number} of input arguments, not their @emph{size}.
|
|
The tradeoff is that @samp{fast_loose}
|
|
does not recognize calls as duplicates
|
|
if they involve input arguments that are logically equal
|
|
but are stored at different locations in memory.
|
|
The following declaration calls for this variant of tabling.
|
|
|
|
@example
|
|
:- pragma memo(@var{Name}(in, in, in, out),
|
|
[allow_reset, statistics, fast_loose]).
|
|
@end example
|
|
|
|
The @samp{specified} attribute allows programmers
|
|
to choose individually, for each input argument,
|
|
whether that argument should be looked up in the memo table
|
|
by value or by address,
|
|
or whether it should be looked up at all:
|
|
|
|
@example
|
|
:- pragma memo(@var{Name}(in, in, in, out), [allow_reset, statistics,
|
|
specified([value, addr, promise_implied, output])]).
|
|
@end example
|
|
|
|
The @samp{specified} attribute should have an argument which is a list,
|
|
and this list should contain one element
|
|
for each argument of the predicate or function concerned
|
|
(if a function, the last element is for the return value).
|
|
For output arguments, the list element should be @samp{output}.
|
|
For input arguments, the list element may be
|
|
@samp{value}, @samp{addr} or @samp{promise_implied}.
|
|
The first calls for tabling the argument by value,
|
|
the second calls for tabling the argument by address,
|
|
and the third calls for not tabling the argument at all.
|
|
This last course of action promises that any two calls
|
|
that agree on the values of the value-tabled input arguments
|
|
and on the addresses of the address-tabled input arguments
|
|
will behave the same regardless of the values of the untabled input arguments.
|
|
In most cases, this will mean that the values of the untabled arguments
|
|
are implied by the values of the value-tabled arguments
|
|
and the addresses of the address-tabled arguments,
|
|
though the promise can also be fulfilled
|
|
if the table predicate or function does not actually use
|
|
the untabled argument for computing any of its output.
|
|
(It is ok for it to use the untabled argument
|
|
to decide what exception to throw.)
|
|
|
|
@c Experimental:
|
|
@c The @samp{specified} attribute can additionally take an argument after
|
|
@c the list, which is either @samp{hidden_arg_value} or @samp{hidden_arg_addr}.
|
|
@c If @samp{hidden_arg_addr} is specified, extra arguments introduced by the
|
|
@c compiler will be tabled by address, otherwise they are tabled by value.
|
|
@c @samp{hidden_arg_value} is assumed if neither is present.
|
|
|
|
If the tabled predicate or function has only one mode,
|
|
then a declaration like this can also be specified
|
|
without giving the argument modes:
|
|
|
|
@example
|
|
:- pragma memo(pred(@var{Name}/@var{Arity}), [allow_reset, statistics,
|
|
specified([value, addr, promise_implied, output])]).
|
|
@end example
|
|
|
|
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 a ``minimal model'' semantics,
|
|
specifically, the perfect model semantics.
|
|
Anything which is true or false in the completion semantics
|
|
is also true or false (respectively) in the perfect model semantics,
|
|
but there are goals for which the perfect 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 perfect model semantics requires a particular answer to be returned.
|
|
In particular, the perfect 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 perfect 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.
|
|
It is described in
|
|
@c XXX this citation may not come out properly in DVI format
|
|
@cite{Tabling in Mercury: design and implementation}
|
|
by Z. Somogyi and K. Sagonas,
|
|
Proceedings of the Eight International Symposium
|
|
on Practical Aspects of Declarative Languages.
|
|
|
|
@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, minimal model tabling is incompatible with
|
|
high level code and the use of trailing.
|
|
@c and accurate garbage collection.
|
|
@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 on
|
|
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},
|
|
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.
|
|
|
|
By default, the compiler assumes that
|
|
a procedure defined using the foreign language interface
|
|
will terminate for all input if it does not call Mercury.
|
|
If it does call Mercury then by default the compiler will assume
|
|
that it may not terminate.
|
|
|
|
The foreign code attributes @samp{terminates}/@samp{does_not_terminate}
|
|
may be used to force the compiler to treat a foreign_proc
|
|
as terminating/non-terminating irrespective of whether it calls Mercury.
|
|
As a matter of style,
|
|
it is preferable to use foreign code attributes for foreign_procs
|
|
rather than the termination pragmas described below.
|
|
|
|
The following declarations can be used to inform the compiler
|
|
of the termination properties of a predicate or function.
|
|
|
|
@example
|
|
:- pragma terminates(pred(@var{Name}/@var{Arity})).
|
|
:- pragma terminates(func(@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.
|
|
This declaration affects not only the predicate specified
|
|
but also any other predicates that are mutually recursive with it.
|
|
|
|
@example
|
|
:- pragma does_not_terminate(pred(@var{Name}/@var{Arity})).
|
|
:- pragma does_not_terminate(func(@var{Name}/@var{Arity})).
|
|
@end example
|
|
|
|
This declaration may be used to inform the compiler
|
|
that this predicate or function may not terminate.
|
|
This declaration affects not only the predicate or function specified
|
|
but also any other predicates and/or functions
|
|
that are mutually recursive with it.
|
|
|
|
@example
|
|
:- pragma check_termination(pred(@var{Name}/@var{Arity})).
|
|
:- pragma check_termination(func(@var{Name}/@var{Arity})).
|
|
@end example
|
|
|
|
This pragma tells the compiler
|
|
that it should try to prove the termination of this predicate or function,
|
|
and if it fails, then it should quit with an error message.
|
|
|
|
@c XXX TO DO!
|
|
@c @node Compile-time garbage collection
|
|
@c @section Compile-time garbage collection
|
|
@c
|
|
@c The compiler includes a compile-time garbage collection system (CTGC). This
|
|
@c system consists of a structure sharing analysis, followed by a structure
|
|
@c reuse analysis.
|
|
@c
|
|
@c @node Structure sharing analysis
|
|
@c @subsection Structure sharing analysis
|
|
@c
|
|
@c The compiler includes a structure sharing analysis system.
|
|
@c
|
|
@c @node Structure reuse analysis
|
|
@c @subsection Structure reuse analysis
|
|
@c
|
|
@c The compiler includes a structure reuse analysis system.
|
|
@c
|
|
|
|
@c @node Tail recursion check
|
|
@c @section Tail recursion check
|
|
@c
|
|
@c The @samp{require_tail_recursion} pragma can be used to enable and disable
|
|
@c warnings or errors for predicates and functions that contain recursive
|
|
@c calls which are not @emph{tail} recursive.
|
|
@c
|
|
@c XXX add pred() and func() wrappers
|
|
@c @example
|
|
@c :- pragma require_tail_recursion(@var{Name}/@var{Arity}, @var{Options}).
|
|
@c :- pragma require_tail_recursion(@var{Name}(@var{Modes}), @var{Options}).
|
|
@c :- pragma require_tail_recursion(@var{Name}(@var{Modes}) = @var{ReturnMode},
|
|
@c @var{Options}).
|
|
@c @end example
|
|
@c
|
|
@c This pragma affects all modes of a predicate or function (in the first form)
|
|
@c or a specific mode of a predicate or function (the second and third forms).
|
|
@c These pragmas can be used to enable or inhibit warnings for non tail
|
|
@c recursive code.
|
|
@c
|
|
@c When tail recursion warnings are enabled using the
|
|
@c @samp{--warn-non-tail-recursion} compiler option (see the user's guide),
|
|
@c the compiler may emit warnings for predicates that the developer knows and
|
|
@c accepts aren't tail recursive.
|
|
@c These can be suppressed using the @samp{none} option in the
|
|
@c @samp{require_tail_recursion} pragma.
|
|
@c
|
|
@c @example
|
|
@c :- pragma require_tail_recursion(foo/3, [none]).
|
|
@c @end example
|
|
@c
|
|
@c When the @samp{--warn-non-tail-recursion} compiler option is not enabled
|
|
@c then the pragma can be used to explicitly enable the tail recursion check
|
|
@c for a predicate or function.
|
|
@c If you think that a predicate or function will probably recurse deeply,
|
|
@c and may exhaust the stack unless its recursive calls are all tail recursive,
|
|
@c then use this pragma on that predicate
|
|
@c to get a warning or an error
|
|
@c if any of those recursive calls are not tail recursive.
|
|
@c You may also wish to enable this warning
|
|
@c if you expect the predicate or function to be called many times,
|
|
@c even if those calls are very unlikely to exhaust the stack,
|
|
@c simply because tail recursion is more efficient than non-tail recursion.
|
|
@c
|
|
@c @example
|
|
@c :- pragma require_tail_recursion(map/3).
|
|
@c @end example
|
|
@c
|
|
@c The following options may be given:
|
|
@c
|
|
@c @table @code
|
|
@c
|
|
@c @item warn
|
|
@c Non tail recursive code should generate a compiler warning.
|
|
@c This is the default.
|
|
@c This option is incompatible with @samp{error} and @samp{none}.
|
|
@c
|
|
@c @item error
|
|
@c Non tail recursive code should generate a compiler error.
|
|
@c This option is incompatible with @samp{warn} and @samp{none}.
|
|
@c
|
|
@c @item none
|
|
@c Disable the tail recursion check for this predicate or function.
|
|
@c This option is incompatible with every other option.
|
|
@c
|
|
@c @item self_or_mutual_recursion
|
|
@c Allow the recursive calls to be self or mutually recursive.
|
|
@c The compiler will generate warnings or errors for recursive calls that are
|
|
@c not tail calls (and not later followed by a recursive call that @emph{is} a
|
|
@c tail call).
|
|
@c This is the default.
|
|
@c This option is incompatible with @samp{self_recursion_only} and @samp{none}.
|
|
@c
|
|
@c @item self_recursion_only
|
|
@c Require that all recursive calls are self-recursive.
|
|
@c In addition to @code{self_or_mutual_recursion},
|
|
@c this option causes the compiler to generate a warning or error
|
|
@c when a mutually recursive call is a @emph{tail} call, even if it can
|
|
@c optimize the tail call.
|
|
@c Some backends can optimize self recursion but not mutual recursion,
|
|
@c or mutual recursion is less efficient.
|
|
@c This option can be used to alert the programmer of code that isn't tail
|
|
@c recursive on these backends.
|
|
@c This option is incompatible with @samp{self_or_mutual_recursion} and
|
|
@c @samp{none}.
|
|
@c
|
|
@c @end table
|
|
@c
|
|
@c Note that the compiler cannot analyse recursion across module boundaries
|
|
@c or through higher-order calls.
|
|
@c Therefore inter-module and higher-order calls are considered to be
|
|
@c non-recursive.
|
|
@c
|
|
@c This pragma has no effect with @samp{--no-optimize-tailcalls}.
|
|
@c
|
|
@c Issuing the pragma more than once for the same predicate or function, or a
|
|
@c mode off that predicate or function, will cause undefined behaviour.
|
|
|
|
@node Feature sets
|
|
@section Feature sets
|
|
|
|
The Melbourne Mercury implementation supports
|
|
a number of optional compilation model features,
|
|
such as @ref{Trailing} or @ref{Tabled evaluation}.
|
|
Feature sets allow the programmer to assert that a module requires
|
|
the presence of one or more optional features in the compilation model.
|
|
These assertions can be made
|
|
using a @samp{pragma require_feature_set} declaration.
|
|
|
|
The @samp{require_feature_set} pragma declaration has the following form:
|
|
@example
|
|
:- pragma require_feature_set(@var{Features}).
|
|
@end example
|
|
|
|
where @var{Features} is a (possibly empty) list of features.
|
|
|
|
The supported features are:
|
|
@table @asis
|
|
|
|
@item @samp{concurrency}
|
|
This specifies that the compilation model
|
|
must support concurrent execution of multiple threads.
|
|
|
|
@item @samp{single_prec_float}
|
|
This specifies that the compilation model
|
|
must use single precision floats.
|
|
This feature cannot be specified
|
|
together with the @samp{double_prec_float} feature.
|
|
|
|
@item @samp{double_prec_float},
|
|
This feature specifies tha
|
|
the compilation model must use double precision floats.
|
|
This feature cannot be specified
|
|
together with the @samp{single_prec_float} feature.
|
|
|
|
@item @samp{memo}
|
|
This feature specifies that the compilation model must support memoisation
|
|
(see @ref{Tabled evaluation}).
|
|
|
|
@item @samp{parallel_conj}
|
|
This feature specifies that the compilation model
|
|
must support parallel execution of conjunctions.
|
|
This feature cannot be specified together with the @samp{trailing} feature.
|
|
|
|
@item @samp{trailing}
|
|
This feature specifies that the compilation model
|
|
must support trailing, see @ref{Trailing}.
|
|
This feature cannot be specified
|
|
together with the @samp{parallel_conj} feature.
|
|
|
|
@item @samp{strict_sequential}
|
|
This feature specifies that
|
|
a semantics that is equivalent to the strict sequential operational semantics
|
|
must be used.
|
|
|
|
@item @samp{conservative_gc}
|
|
This feature specifies that a module
|
|
requires conservative garbage collection.
|
|
This feature is only checked when using the C backends;
|
|
it is ignored by the non-C backends.
|
|
|
|
@end table
|
|
|
|
When a module containing a @samp{pragma require_feature_set} declaration
|
|
is compiled,
|
|
the implementation checks to see that
|
|
the specified features are supported by the compilation model.
|
|
It emits an error if they are not.
|
|
|
|
A @samp{pragma require_feature_set} may only occur
|
|
in the implementation section of a module.
|
|
|
|
A @samp{pragma require_feature_set} affects
|
|
only the module in which it occurs;
|
|
in particular it does not affect any submodules.
|
|
|
|
If a module contains multiple @samp{pragma require_feature_set} declarations,
|
|
then the implementation should emit an error
|
|
if any of them specifies a feature
|
|
that is not supported by the compilation model.
|
|
|
|
@node Trailing
|
|
@section Trailing
|
|
|
|
In certain compilation grades
|
|
(see the ``Compilation model options'' section of the Mercury User's Guide),
|
|
the 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 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 foreign_proc} or @samp{pragma foreign_code} declarations
|
|
in Mercury code.
|
|
|
|
For an example of the use of this interface,
|
|
see the module @file{extras/trailed_update/tr_array.m}
|
|
in the Mercury extras 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(MR_Word *@var{address}, MR_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(MR_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
|
|
|
|
Note that @var{address} must be word aligned
|
|
for both @code{MR_trail_current_value()} and @code{MR_trail_value()}.
|
|
(The address of Mercury data structures
|
|
that have been passed to C via the foreign language interface
|
|
are guaranteed to be appropriately aligned.)
|
|
|
|
@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})(void *, 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 the 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 @samp{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 then 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 should 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.
|
|
|
|
Note that the address of the C function passed as the first argument of
|
|
@code{MR_trail_function()} must be word aligned.
|
|
|
|
@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 there 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 extras distribution includes an example of this:
|
|
see the @samp{ML_var_untrail_func()} function
|
|
in the file @file{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(@var{x}, @var{y})} true
|
|
iff the choicepoint indicated by @var{x}
|
|
is newer than (i.e.@: was created more recently than)
|
|
the choicepoint indicated by @var{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.
|
|
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.
|
|
|
|
If your mutable data structure is a C global variable,
|
|
then you can use @code{MR_null_choicepoint_id()}
|
|
for the initial value of the @samp{prev_choicepoint} field.
|
|
If on the other hand your mutable data structure
|
|
is created by a predicate or function that uses tabled evaluation
|
|
(@pxref{Tabled evaluation}),
|
|
then you @emph{should} use @code{MR_null_choicepoint_id()}
|
|
for the initial value of the field.
|
|
Doing so will ensure that the data will be reset to its initial value
|
|
if execution backtracks to a point
|
|
before the mutable data structure was created,
|
|
which is important because this copy of the mutable data structure
|
|
will be tabled and will therefore be produced again
|
|
if later execution attempts to create another instance of it.
|
|
|
|
For an example of avoiding redundant trailing, 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.
|
|
|
|
:- pragma foreign_decl("C", "
|
|
|
|
typedef struct @{
|
|
MR_ChoicepointId prev_choicepoint;
|
|
MR_Integer data;
|
|
@} C_IntRef;
|
|
|
|
").
|
|
|
|
:- pragma foreign_type("C", int_ref, "C_IntRef *").
|
|
|
|
:- pragma foreign_proc("C",
|
|
new_int_ref(Ref::uo, Value::in),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
C_Intref *x = malloc(sizeof(C_IntRef));
|
|
x->prev_choicepoint = MR_current_choicepoint_id();
|
|
x->data = Value;
|
|
Ref = x;
|
|
").
|
|
|
|
:- pragma foreign_proc("C",
|
|
update_int_ref(Ref0::mdi, Ref::muo, OldValue::out, NewValue::in),
|
|
[will_not_call_mercury, promise_pure],
|
|
"
|
|
C_IntRef *x = Ref0;
|
|
OldValue = 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(MR_Word));
|
|
assert(sizeof(x->prev_choicepoint) == sizeof(MR_Word));
|
|
MR_trail_current_value((MR_Word *)&x->data);
|
|
MR_trail_current_value((MR_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 = NewValue;
|
|
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 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}.
|
|
@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
|
|
@uref{https://www.mercurylang.org/documentation/papers/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
|
|
@uref{https://www.mercurylang.org/documentation/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
|
|
@uref{https://user.it.uu.se/~kostis/Thesis/thesis.ps.gz}.
|
|
|
|
@node [5]
|
|
@unnumberedsec [5]
|
|
B. Demoen and K. Sagonas, @cite{CAT: the Copying Approach to Tabling},
|
|
In C. Palamidessi, H. Glaser and K. Meinke, editors, @cite{Principles of
|
|
Declarative Programming, 10th International Symposium, PLILP'98},
|
|
Lecture Notes in Computer Science, Springer, 1998.
|
|
Available form @uref{https://user.it.uu.se/~kostis/Papers/cat.ps.gz}.
|
|
@bye
|