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.
815 lines
29 KiB
Plaintext
815 lines
29 KiB
Plaintext
\input texinfo
|
|
@setfilename mercury_transition_guide.info
|
|
@settitle The Prolog to Mercury transition guide
|
|
@c vim: ts=4 sw=4 expandtab ft=texinfo
|
|
|
|
@dircategory The Mercury Programming Language
|
|
@direntry
|
|
* Mercury Transition Guide: (mercury_transition_guide). The Prolog to Mercury Transition Guide.
|
|
@end direntry
|
|
|
|
@c @smallbook
|
|
@c @cropmarks
|
|
@finalout
|
|
@setchapternewpage off
|
|
@ifnottex
|
|
This file is an aid for people porting Prolog programs to Mercury.
|
|
|
|
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 Prolog to Mercury transition guide
|
|
@subtitle Version <VERSION>
|
|
@author Thomas Conway
|
|
@author Zoltan Somogyi
|
|
@author Fergus Henderson
|
|
@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
|
|
|
|
@ifnottex
|
|
@node Top,,, (mercury)
|
|
@top The Prolog to Mercury Transition Guide, version <VERSION>
|
|
|
|
This guide gives some advice about
|
|
translating Prolog programs into Mercury.
|
|
|
|
@menu
|
|
* Introduction:: Introduction.
|
|
* Syntax:: Syntax.
|
|
* IO:: Input and output.
|
|
* AssertRetract:: @code{assert} and @code{retract}.
|
|
* FailLoops:: Failure driven loops.
|
|
* Commits:: Cuts.
|
|
* Accumulators:: Accumulators and difference lists.
|
|
* Determinism:: Determinism.
|
|
* All-solutions:: All-solutions predicates: @code{findall} and @code{setof}.
|
|
@c * Problems:: Common Problems.
|
|
@end menu
|
|
@end ifnottex
|
|
|
|
@node Introduction
|
|
@chapter Introduction
|
|
|
|
This document is intended to help the reader
|
|
translate existing Prolog programs to Mercury.
|
|
We assume that the reader is familiar with Prolog.
|
|
This guide should be used in conjunction with
|
|
the Mercury User's Guide and Reference Manuals.
|
|
|
|
If the Prolog code is quite declarative
|
|
and does not make use of Prolog's non-logical constructions,
|
|
the job of converting it to Mercury will usually be quite straight forward.
|
|
However, if the Prolog program makes extensive use of non-logical constructions,
|
|
conversion may be very difficult,
|
|
and a direct transliteration may be impossible.
|
|
Mercury code typically has a very different style to most Prolog code.
|
|
|
|
@node Syntax
|
|
@chapter Syntax and declarations
|
|
|
|
Prolog and Mercury have very similar syntax.
|
|
Although there are a few differences,
|
|
by and large if the syntax of a program is accepted by a Prolog system,
|
|
it will be accepted by Mercury.
|
|
There are however a few extra operators defined by the Mercury term parser
|
|
(see the ``Operators'' section of the ``Syntax'' chapter of the
|
|
Mercury Language Reference Manual).
|
|
|
|
In addition, Mercury implements both existential and universal quantification
|
|
using the syntax
|
|
|
|
@example
|
|
some Vars Goal
|
|
@end example
|
|
|
|
@noindent
|
|
and
|
|
|
|
@example
|
|
all Vars Goal
|
|
@end example
|
|
|
|
String literals are atomic;
|
|
they are not abbreviations for lists of character codes.
|
|
|
|
The constructor for lists in Mercury is @samp{[|]/2}, not @samp{./2}.
|
|
|
|
Terms with functor '@{@}/@var{N}' are treated slightly differently in Mercury
|
|
than in ISO Prolog. ISO Prolog specifies that ``@{1, 2, 3@}'' is parsed as
|
|
@code{'@{@}'(','(1, ','(2, 3)))}. In Mercury, it is parsed as
|
|
@code{'@{@}'(1, 2, 3)}.
|
|
|
|
Mercury does not allow users to define their own operators.
|
|
|
|
@node IO
|
|
@chapter Input and output
|
|
|
|
Mercury is a purely declarative language.
|
|
Therefore it cannot use Prolog's mechanism for doing
|
|
input and output with side-effects.
|
|
The mechanism that Mercury uses is the threading of an object
|
|
that represents the state of the world through the computation.
|
|
The type of this object is @code{io.state}, or just @code{io} for short.
|
|
Each operation that affects the state of the world
|
|
must have two arguments of this type,
|
|
representing respectively the state of the world before the operation,
|
|
and the state of the world after the operation.
|
|
The modes of the two arguments that are added to calls are
|
|
@code{di} for ``destructive input'' and @code{uo} for ``unique output''.
|
|
The first means that the input variable
|
|
must be the last reference to the original state of the world,
|
|
and the latter means that the output variable is guaranteed to be the
|
|
only reference to the state of the world produced by this predicate.
|
|
|
|
For example, the direct translation of the Prolog predicate
|
|
|
|
@example
|
|
@group
|
|
write_total(Total) :-
|
|
write('The total is '),
|
|
write(Total),
|
|
write('.'),
|
|
nl.
|
|
@end group
|
|
@end example
|
|
|
|
@noindent
|
|
into Mercury yields this Mercury predicate:
|
|
|
|
@example
|
|
@group
|
|
:- pred write_total(int::in, io::di, io::uo) is det.
|
|
|
|
write_total(Total, IO0, IO) :-
|
|
print("The total is ", IO0, IO1),
|
|
print(Total, IO1, IO2),
|
|
print('.', IO2, IO3),
|
|
nl(IO3, IO).
|
|
@end group
|
|
@end example
|
|
|
|
The variables @code{IO0}, @code{IO1} etc each represent
|
|
one version of the state of the world.
|
|
@code{IO0} represents the state before the total is printed,
|
|
@code{IO1} represents the state after just @code{The total is} is printed,
|
|
and so on.
|
|
However, programmers usually don't want to give specific names
|
|
to all these different versions;
|
|
they want to name only the entities
|
|
that all these variables represent different versions of.
|
|
That is why Mercury supports state variable notation.
|
|
This is syntactic sugar
|
|
designed to make it easier to thread a sequence of variables
|
|
holding the successive states of an entity through a clause.
|
|
You as the programmer name only the entity,
|
|
and let the compiler name the various versions.
|
|
With state variables, the above clause would be written as
|
|
|
|
@example
|
|
@group
|
|
write_total(Total, !IO) :-
|
|
print("The total is ", !IO),
|
|
print(Total, !IO),
|
|
print('.', !IO),
|
|
nl(!IO).
|
|
@end group
|
|
@end example
|
|
|
|
and the compiler will internally convert this clause
|
|
into code that looks like the previous clause.
|
|
(The usual convention in Mercury programs
|
|
is to name the state variable representing the state of the world @code{!IO}.)
|
|
|
|
In the head of a clause,
|
|
what looks like an argument that consists of
|
|
a variable name prefixed by an exclamation mark
|
|
actually stands for two arguments which are both variables,
|
|
holding the initial and final state
|
|
of whatever entity the state variable stands for.
|
|
In this case, they stand for the state of the world,
|
|
respectively before and after the line about the total has been printed.
|
|
In calls in the body of a clause,
|
|
what looks like an argument that consists of
|
|
a variable name prefixed by an exclamation mark
|
|
also stands for two arguments which are both variables,
|
|
but these hold respectively, the current and the next state.
|
|
|
|
In Prolog, it is quite normal to give to @code{print}
|
|
an argument that is an atom that is not used anywhere else in the program,
|
|
or at least not in code related to the code that does the printing.
|
|
This is because the term being printed
|
|
does not have to belong to a defined type.
|
|
Since Mercury is strongly typed, the atom being printed
|
|
@emph{would} have to be a data constructor of a defined type.
|
|
A Mercury programmer @emph{could} define a meaningless type
|
|
just to give one of its data constructors to a call to @code{print},
|
|
but it is far better to simply call a predicate specifically designed
|
|
to print the string, or integer, or character, you want to print:
|
|
|
|
@example
|
|
@group
|
|
write_total(Total, !IO) :-
|
|
io.write_string("The total is ", !IO),
|
|
io.write_int(Total, !IO),
|
|
io.write_char('.', !IO),
|
|
io.nl(!IO).
|
|
@end group
|
|
@end example
|
|
|
|
The @code{io.} prefix on the predicates called in the body indicates that
|
|
the callees are in the @code{io} module of the Mercury standard library.
|
|
This module contains all of Mercury's primitive I/O operations.
|
|
These @emph{module qualifications} are not strictly necessary
|
|
(unless two or more modules define predicates
|
|
with the same names and argument types,
|
|
the Mercury compiler can figure out which modules called predicates are in),
|
|
but Mercury convention is to make the module qualifier explicit
|
|
in order to make the intent of the code crystal clear to readers.
|
|
|
|
The above could also be written more compactly like this:
|
|
@example
|
|
write_total(Total, !IO) :-
|
|
io.format("The total is %d.\n", [i(Total)], !IO).
|
|
@end example
|
|
|
|
The first argument of @code{io.format} is a format string
|
|
modelled directly on the format strings supported by @code{printf} in C,
|
|
while the second is a list of the values to be printed,
|
|
which should have one value for each conversion specifier.
|
|
In this case, there is one conversion specifier, @samp{%d},
|
|
which calls for the printing of an integer as a decimal number,
|
|
and the corresponding value is the integer @code{Total}.
|
|
Since Mercury is strongly typed,
|
|
and different arguments may have different types,
|
|
in the argument list
|
|
integers must be wrapped inside @code{i()},
|
|
floats must be wrapped inside @code{f()},
|
|
strings must be wrapped inside @code{s()}, and
|
|
chars must be wrapped inside @code{c()}.
|
|
Despite appearances, in the usual case of the format string being constant,
|
|
the wrappers and the list of arguments have neither time nor space overhead,
|
|
because the compiler optimizes them away,
|
|
replacing the call to @code{io.format} with
|
|
the calls to @code{io.write_string}, @code{io.write_int} etc above.
|
|
|
|
One of the important consequences of our model for input and output
|
|
is that predicates that can fail may not do input or output.
|
|
This is because the state of the world must be a unique object,
|
|
and each I/O operation destructively replaces it with a new state.
|
|
Since each I/O operation destroys the current state object
|
|
and produces a new one,
|
|
it is not possible for I/O to be performed in a context that may fail,
|
|
since when failure occurs the old state of the world will have been destroyed,
|
|
and since bindings cannot be exported from a failing computation,
|
|
the new state of the world is not accessible.
|
|
|
|
In some circumstances, Prolog programs that suffer from this problem
|
|
can be fixed by moving the I/O out of the failing context.
|
|
For example
|
|
|
|
@example
|
|
@group
|
|
@dots{}
|
|
( solve(Goal) ->
|
|
@dots{}
|
|
;
|
|
@dots{}
|
|
),
|
|
...
|
|
@end group
|
|
@end example
|
|
|
|
@noindent
|
|
where @samp{solve(Goal)} does some I/O
|
|
can be transformed into valid Mercury in at least two ways.
|
|
The first is to make @samp{solve} deterministic and return a status:
|
|
|
|
@example
|
|
@group
|
|
@dots{}
|
|
solve(Goal, Result, !IO),
|
|
(
|
|
Result = success(@dots{}),
|
|
@dots{}
|
|
;
|
|
Result = failure,
|
|
@dots{}
|
|
),
|
|
@dots{}
|
|
@end group
|
|
@end example
|
|
|
|
The other way is to transform @samp{solve} so that
|
|
all the input and output takes place outside it:
|
|
|
|
@example
|
|
...
|
|
io.write_string("calling: ", !IO),
|
|
solve.write_goal(Goal, !IO),
|
|
( solve(Goal) ->
|
|
io.write_string("succeeded\n", !IO),
|
|
...
|
|
;
|
|
...
|
|
),
|
|
...
|
|
@end example
|
|
|
|
@node AssertRetract
|
|
@chapter Assert and retract
|
|
|
|
In Prolog, calls to the builtin predicates @code{assert} and @code{retract}
|
|
can change the set of clauses of the program currently being executed.
|
|
This makes compilation very tricky,
|
|
and different Prolog systems react differently
|
|
when the program alters the definition of a predicate that has active calls.
|
|
It also makes program analysis almost impossible,
|
|
since the program that the compiler should analyze
|
|
is not actually available at compilation time.
|
|
Since Mercury is a compiled language,
|
|
it does not allow the compiled program to be altered in any way.
|
|
|
|
Most uses of @code{assert} and @code{retract} in Prolog programs
|
|
are not actually intended to alter the program.
|
|
Their purpose is just to maintain a set of facts,
|
|
with semantically separate sets of facts being stored in separate predicates.
|
|
(Most Prolog systems require these predicates
|
|
to be marked as @code{dynamic} predicates.)
|
|
A Mercury programmer who wants to store a set of facts
|
|
would simply store those facts as data (not as code) in a data structure.
|
|
|
|
The standard library contains
|
|
several abstract data types (ADTs) for storing collections of items,
|
|
each of which is useful for different classes of problems.
|
|
|
|
If the order of the items in the collection is important,
|
|
consider the @code{list} and @code{cord} ADTs.
|
|
@code{list} has lower constant factors,
|
|
but the @code{cord} ADTs supports concatenation in constant time.
|
|
The @code{stack} and @code{queue} ADTs implement
|
|
lists with specific semantics and operations appropriate to those semantics.
|
|
|
|
If the order of items in the collection is not important,
|
|
and if the items are key-value pairs,
|
|
you can store them in ADTs implementing several different kinds of trees,
|
|
including @code{rbtree} and @code{tree234}.
|
|
In the absence of a compelling reason to choose a different implementation,
|
|
we recommend the @code{map} ADT for generic use.
|
|
Maps are implemented using 234 trees,
|
|
which are guaranteed to be balanced and thus have good worst-case behavior,
|
|
but also have good performance in the average case.
|
|
@c but in the future it may change to a hash table, or a trie,
|
|
@c or it may become a module that chooses among several implementation methods
|
|
@c dynamically depending on the size and characteristics of the data.
|
|
@code{bimap}, @code{injection}, @code{multi_map} and @code{rtree} are
|
|
specialized version of maps.
|
|
|
|
If the items in the collection are not key-value pairs,
|
|
then consider the @code{set} and @code{bag} ADTs.
|
|
The @code{set} ADT itself has several versions,
|
|
some based on trees and some based on bit vectors,
|
|
each with its own tradeoffs.
|
|
|
|
The Mercury standard library has some modules
|
|
for more specialized collections as well, such as graphs.
|
|
And of course, if needed, you can always create your own ADT.
|
|
|
|
If for some reason you cannot thread variables holding some data
|
|
through the parts of your program that need access to that data,
|
|
then you can store that data in a @samp{mutable},
|
|
which is as close as Mercury comes to Prolog's dynamic predicates.
|
|
Each Mercury mutable stores one value,
|
|
though of course this value can be a collection,
|
|
and that collection may be (but doesn't have to be) implemented
|
|
by one of the Mercury standard library modules listed above.
|
|
|
|
Each mutable has a getter and setter predicate.
|
|
You can set things up so that the getter and setter predicates
|
|
both function as I/O operations,
|
|
destroying the current state of the world
|
|
and returning a new state of the world.
|
|
This effectively considers the mutable to be part of the state of the world
|
|
@emph{outside} the Mercury program.
|
|
|
|
Alternatively, you can set things up so that
|
|
the getter and setter predicates of a mutable are @emph{not} I/O operations,
|
|
but in that case calls to those predicates are not considered pure Mercury,
|
|
and must instead use Mercury's mechanisms for controlled impurity.
|
|
These mechanisms require all code that is not pure Mercury
|
|
to be explicitly marked as such.
|
|
They are intended to allow programmers
|
|
to implement pure interfaces using @emph{small} pieces of impure code,
|
|
for use in circumstances where there is no feasible way
|
|
to implement that same interface using pure code.
|
|
Most Mercury programs do not use impure code at all.
|
|
The ones that do make use of it use it very sparingly,
|
|
with 99.9+% of their code being pure Mercury.
|
|
|
|
@node FailLoops
|
|
@chapter Failure driven loops
|
|
|
|
In pure Mercury code,
|
|
the goal @code{Goal, fail} is interchangeable with the goal @code{fail, Goal},
|
|
and @code{Goal} cannot have any side effects.
|
|
As a consequence of these two facts,
|
|
it is not possible to write failure driven loops in pure Mercury code.
|
|
While one could try to use Mercury's mechanisms for controlled impurity
|
|
to implement failure driven loops using impure Mercury code,
|
|
this is not part of the culture of Mercury programming,
|
|
because failure driven loops are
|
|
significantly less clear and harder to maintain
|
|
than other means of iterating through a sequence.
|
|
Since they are inherently imperative and not declarative,
|
|
they are also very hard for compilers to optimize.
|
|
|
|
If the sequence must be generated through backtracking,
|
|
then a Mercury programmer could just collect all the solutions together
|
|
using the standard Mercury library predicate @code{solutions},
|
|
and iterate through the resulting list of solutions
|
|
using an ordinary tail recursive predicate.
|
|
|
|
However, most Mercury programmers would prefer to generate
|
|
a list of solutions directly.
|
|
This can be easily done by replacing code that generates
|
|
alternative solutions through backtracking,
|
|
using predicates like this:
|
|
|
|
@example
|
|
generate_solutions(In1, In2, Soln) :-
|
|
(
|
|
% Generate one value of Soln from In1 and In2.
|
|
generate_one_soln(In1, In2, Soln)
|
|
;
|
|
% Compute a new value for the second input.
|
|
In2' = ....
|
|
% Generate more values of Soln from In1 and In2'.
|
|
generate_solutions(In1, In2', Soln)
|
|
).
|
|
@end example
|
|
|
|
in which the different solutions are produced by different disjuncts,
|
|
with predicates in which
|
|
the different solutions are produced by different conjuncts,
|
|
like this:
|
|
|
|
@example
|
|
generate_solutions(In1, In2, [Soln | Solns]) :-
|
|
generate_one_soln(In1, In2, Soln),
|
|
In2' = ....
|
|
generate_solutions(In1, In2', Solns).
|
|
@end example
|
|
|
|
Unlike predicates following the previous pattern,
|
|
predicates following this pattern can exploit Mercury's determinism system
|
|
to ensure that they have considered all the possible combinations
|
|
of the values of the input arguments.
|
|
They are also more efficient,
|
|
since choice point creation is expensive.
|
|
|
|
They can be made even more efficient
|
|
if the consumption of the solutions can be interleaved
|
|
with their generation.
|
|
For example, if the solutions are intended to be inputs to a fold
|
|
(i.e. each solution is intended to update an accumulator),
|
|
then this interleaving can be done like this:
|
|
|
|
@example
|
|
generate_and_use_solutions(In1, In2, !Acc) :-
|
|
generate_one_soln(In1, In2, Soln),
|
|
use_solution(Soln, !Acc),
|
|
In2' = ....
|
|
generate_and_use_solutions(In1, In2', !Acc).
|
|
@end example
|
|
|
|
@node Commits
|
|
@chapter Cuts and indexing
|
|
|
|
The Prolog cut operator is not part of the Mercury language.
|
|
Most Prolog code that uses cuts
|
|
should probably be translated into Mercury using if-then-elses.
|
|
|
|
In both Prolog and Mercury,
|
|
the behavior of an if-then-else @samp{C -> T ; E}
|
|
depends on whether the condition @samp{C} has any solutions.
|
|
If it does, then they both execute the then-part @samp{T};
|
|
if it does not, then they both execute the else-part @samp{E}.
|
|
However, Prolog and Mercury differ in what they do
|
|
if the condition has @emph{more} than one solution.
|
|
|
|
In most versions of Prolog,
|
|
if the condition of an if-then-else has more than one solution,
|
|
the if-then-else throws away all its solutions after the first.
|
|
The way this is usually implemented is that
|
|
after the condition generates its first solution,
|
|
and before execution continues to the then-part goal
|
|
with the bindings in that first solution,
|
|
the Prolog implementation cuts away all the choice points in the condition.
|
|
This prevents backtracking into the condition,
|
|
which thus cannot generate any of its @emph{other} solutions.
|
|
|
|
Mercury does @emph{not} prune away later solutions in conditions.
|
|
If the condition has more than one solution,
|
|
Mercury will execute the then-part goal on every one of them in turn,
|
|
using the usual rules of backtracking.
|
|
|
|
Mercury allows if-then-elses to be written
|
|
not just as @samp{C -> T ; E}, but also as @samp{if C then T else E}.
|
|
These two syntaxes have identical semantics.
|
|
|
|
Prolog programs that use cuts and a `catch-all' clause
|
|
should be transformed to use if-then-else in Mercury.
|
|
|
|
For example
|
|
|
|
@example
|
|
p(this, ...) :- !,
|
|
...
|
|
p(that, ...) :- !,
|
|
...
|
|
p(Thing, ...) :-
|
|
...
|
|
@end example
|
|
|
|
@noindent
|
|
should be rewritten as
|
|
|
|
@example
|
|
p(Thing, ...) :-
|
|
( Thing = this ->
|
|
...
|
|
; Thing = that ->
|
|
...
|
|
;
|
|
...
|
|
).
|
|
@end example
|
|
|
|
The Mercury compiler does much better indexing than most Prolog compilers.
|
|
Actually, the compiler indexes on all input variables to a disjunction
|
|
(separate clauses of a predicate are merged into a single clause
|
|
with a disjunction inside the compiler).
|
|
As a consequence, the Mercury compiler indexes on all arguments.
|
|
It also does deep indexing.
|
|
That is, a predicate such as the following will be indexed.
|
|
|
|
@example
|
|
p([f(g(h)) | Rest]) :- ...
|
|
p([f(g(i)) | Rest]) :- ...
|
|
@end example
|
|
|
|
Since indexing is done on disjunctions rather than clauses,
|
|
it is often unnecessary to introduce auxiliary predicates in Mercury,
|
|
whereas in Prolog it is often important to do so for efficiency.
|
|
|
|
If you have a predicate that needs to test all the functors of a type,
|
|
it is better to use a disjunction instead of a chain of conditionals,
|
|
for two reasons.
|
|
First, if you add a new functor to a type,
|
|
the compiler will still accept the now incomplete conditionals,
|
|
whereas if you use a disjunction you will get a determinism error
|
|
that pinpoints which part of the code needs changing.
|
|
Second, in some situations the code generator
|
|
can implement an indexed disjunction (which we call a @emph{switch})
|
|
using binary search, a jump table or a hash table,
|
|
which can be faster than a chain of if-then-elses.
|
|
|
|
@node Accumulators
|
|
@chapter Accumulators and Difference lists
|
|
|
|
Mercury does not in general allow the kind of aliasing that is used
|
|
in difference lists. Prolog programs using difference lists fall
|
|
in to two categories --- programs whose data flow is ``left-to-right'',
|
|
or can be made left-to-right by reordering conjunctions (the
|
|
Mercury compiler automatically reorders conjunctions so that all
|
|
consumers of a variable come after the producer), and
|
|
those that contain circular dataflow.
|
|
|
|
Programs which do not contain circular dataflow do not cause any trouble
|
|
in Mercury, although the implicit reordering can sometimes mean that programs
|
|
which are tail recursive in Prolog are not tail recursive in Mercury.
|
|
For example, here is a difference-list implementation of quick-sort in Prolog:
|
|
|
|
@example
|
|
qsort(L0, L) :- qsort_2(L0, L - []).
|
|
|
|
qsort_2([], R - R).
|
|
qsort_2([X|L], R0 - R) :-
|
|
partition(L, X, L1, L2),
|
|
qsort_2(L1, R0 - R1),
|
|
R1 = [X|R2],
|
|
qsort_2(L2, R2 - R).
|
|
@end example
|
|
|
|
Due to an unfortunate limitation of the current Mercury implementation
|
|
(partially instantiated modes don't yet work correctly),
|
|
you need to replace all the @samp{-} symbols with commas.
|
|
However, once this is done, and once you have added the appropriate
|
|
declarations, Mercury has no trouble with this code. Although
|
|
the Prolog code is written in a way that traverses the input list left-to-right,
|
|
appending elements to the tail of a difference list to produce the
|
|
output, Mercury will in fact reorder the code so that it traverses
|
|
the input list right-to-left and constructs the output list bottom-up
|
|
rather than top-down. In this particular case, the reordered code is still
|
|
tail recursive --- but it is tail-recursive on the first recursive call,
|
|
not the second one!
|
|
|
|
If the occasional loss of tail recursion causes efficiency problems,
|
|
or if the program contains circular data flow, then a different
|
|
solution must be adopted. One way to translate such programs
|
|
is to transform the difference list into an accumulator.
|
|
Instead of appending elements to the end of a difference list by
|
|
binding the tail pointer, you simply insert elements onto the
|
|
front of a list accumulator. At the end of the loop, you can
|
|
call @samp{list.reverse} to put the elements in the correct order
|
|
if necessary. Although this may require two traversals of the list,
|
|
it is still linear in complexity, and it probably still runs faster
|
|
than the Prolog code using difference lists.
|
|
|
|
In most circumstances, the need for difference lists is negated by
|
|
the simple fact that Mercury is efficient enough for them to be unnecessary.
|
|
Occasionally they can lead to a significant improvement
|
|
in the complexity of an operation
|
|
(mixed insertions and deletions from a long queue, for example)
|
|
and in these situations an alternative solution should be sought
|
|
(in the case of queues,
|
|
the Mercury library uses the pair of lists proposed by Richard O'Keefe).
|
|
|
|
@node Determinism
|
|
@chapter Determinism
|
|
|
|
The Mercury language requires the determinism of all predicates
|
|
exported by a module to be declared.
|
|
The determinism of predicates that are local to a module
|
|
may be declared but don't have to be;
|
|
if they are not declared, they will be inferred.
|
|
By default, the compiler issues a warning message
|
|
where such declarations are omitted,
|
|
but if you want to use determinism inference,
|
|
you can disable this warning
|
|
using the @samp{--no-warn-missing-det-decls} option.
|
|
|
|
Determinism checking and inference
|
|
is an undecidable problem in the general case,
|
|
so it is possible to write programs that are deterministic,
|
|
and have the compiler fail to prove the fact.
|
|
The most important aspect of this problem
|
|
is that the Mercury compiler only detects the clauses of a predicate
|
|
(or the arms of a disjunction, in the general case) to be mutually exclusive,
|
|
allowing the execution of at most one disjunct at runtime,
|
|
if the clauses or disjuncts
|
|
each unify the same variable (or a copy of that variable)
|
|
with distinct functors,
|
|
with these unifications all taking place
|
|
before the first call in the clause or disjunct.
|
|
For such disjunctions, the Mercury compiler generates a @emph{switch}
|
|
(see the earlier section on indexing).
|
|
If a switch has a branch for every functor
|
|
in the type of the switched-on variable,
|
|
then the switch guarantees that exactly one of its arms will be executed.
|
|
If all the arms are deterministic goals,
|
|
then the switch itself is deterministic.
|
|
|
|
The Mercury compiler does not do any range checking of integers,
|
|
so code such as:
|
|
|
|
@example
|
|
factorial(0, 1).
|
|
factorial(N, F) :-
|
|
N > 0,
|
|
N1 is N - 1,
|
|
factorial(N1, F1),
|
|
F is F1 * N.
|
|
@end example
|
|
|
|
@noindent
|
|
would be inferred to be ``nondeterministic''.
|
|
The compiler would infer that the two clauses are not mutually exclusive,
|
|
because it does not know about the semantics of @code{>/2},
|
|
and it would infer that the predicate as a whole could fail
|
|
because (a) the unification of the first argument with @code{0} can fail,
|
|
so the first clause is not guaranteed to generate a solution,
|
|
and (b) the call to @code{>/2} can fail,
|
|
and so the second clause is not guaranteed to generate a solution either.
|
|
|
|
The general solution to such problems
|
|
is to use a chain of one or more if-then-elses.
|
|
|
|
@example
|
|
:- pred factorial(int::in, int::out) is det.
|
|
|
|
factorial(N, F) :-
|
|
( N < 0 ->
|
|
unexpected($pred, "negative N")
|
|
; N = 0 ->
|
|
F = 1
|
|
;
|
|
N1 is N - 1,
|
|
factorial(N1, F1),
|
|
F is F1 * N
|
|
).
|
|
@end example
|
|
|
|
The @code{unexpected} predicate is defined
|
|
in the @code{require} module of the Mercury standard library.
|
|
Calls to it throw an exception,
|
|
and unless that exception is caught, it aborts the program.
|
|
The terms @code{$pred} is automatically replaced by the compiler
|
|
with the (module-qualified) name of the predicate in which it appears.
|
|
|
|
@node All-solutions
|
|
@chapter All-solutions predicates.
|
|
|
|
Prolog's various different all-solutions predicates
|
|
(@samp{findall/3}, @samp{bagof/3},
|
|
and @samp{setof/3}) all have semantic problems.
|
|
Mercury has a different set of all-solutions predicates
|
|
(@samp{solutions/2}, @samp{solutions_set/2}, and @samp{unsorted_solutions/2},
|
|
all defined in the library module @samp{solutions})
|
|
that address the problems of the Prolog versions.
|
|
To avoid the variable scoping problems of the Prolog versions,
|
|
rather than taking both a goal to execute
|
|
and an aliased term holding the resulting value to collect,
|
|
Mercury's all-solutions predicates take as input
|
|
a single higher-order predicate term.
|
|
The Mercury equivalent to
|
|
|
|
@example
|
|
intersect(List1, List2, Intersection) :-
|
|
setof(X, (member(X, List1), member(X, List2)), Intersection).
|
|
@end example
|
|
|
|
@noindent
|
|
is
|
|
|
|
@example
|
|
intersect(List1, List2, Intersection) :-
|
|
solutions(
|
|
( pred(X::out) is nondet :-
|
|
list.member(X, List1),
|
|
list.member(X, List2)
|
|
), Intersection).
|
|
@end example
|
|
|
|
Alternately, this could also be written as
|
|
|
|
@example
|
|
intersect(List1, List2, Intersection) :-
|
|
solutions(member_of_both(List1, List2), Intersection).
|
|
|
|
:- pred member_of_both(list(T)::in, list(T)::in, T::out) is nondet.
|
|
|
|
member_of_both(List1, List2, X) :-
|
|
list.member(X, List1),
|
|
list.member(X, List2).
|
|
@end example
|
|
|
|
@noindent
|
|
and in fact that is exactly how the Mercury compiler
|
|
implements lambda expressions.
|
|
|
|
The current implementation of @samp{solutions/2}
|
|
is a ``zero-copy'' implementation,
|
|
so the cost of @samp{solutions/2} is
|
|
independent of the @emph{size} of the solutions,
|
|
though it is proportional to the @emph{number} of solutions.
|
|
|
|
@bye
|