Prev Next Up Home Keys Figs Search New

Prolog and Mercury Compared

Appeared in Volume 9/3, August 1996

Keywords: mercury.


fjh@mundook.cs.mu.oz.au
Fergus Henderson
7th May 1996

The wording in the following post is mostly mine, but it is a collaborative effort that expresses the joint views of myself, Zoltan Somogyi and Thomas Conway.

Peter Van Roy writes:
Could a Mercury expert compare Mercury and Prolog.

We'll compare Mercury with Prolog as standardized by ISO, although since ISO Prolog is quite limited in some respects, it is somewhat of a "straw man", so we'll also mention what particular Prolog implementations offer. The eight headings were suggested by Peter Van Roy.



1. Coroutining Support (freeze and relatives)

ISO Prolog has no coroutining support at all. Some Prolog systems such as SICStus Prolog and NU-Prolog do support coroutining.

Mercury has no support for run-time coroutining, but it will perform mode-directed goal reordering at compile time. This level of support is enough to support multi-moded predicates, and to ensure soundness (e.g. of negation), but of course it only handles a fairly limited subset of the cases for which coroutining might be useful.

Thomas Conway is working on extending Mercury to support coroutining and stream AND-parallelism for his PhD.


2. Support for Program Transformation (term_expansion, reflective syntax)

ISO Prolog does not have term_expansion. Most Prolog systems do have term_expansion.

Mercury does not have term_expansion, although it is easy to write a term_expansion level source-to-source preprocessor, and very easy to tell 'mmake' (the Mercury front-end to GNU Make) to use this preprocessor. We'll include a preprocessor as one of the example programs in the next Mercury release. For now, see http://www.cs.mu.oz.au/~fjh/mercury/expand_terms.m

Prolog has a reflective syntax, in the sense that the syntax for representations of program fragments can be the same as for those program fragments themselves. Mercury does not. (Was that what you meant by a reflective syntax?)


3. Read/write of Arbitrary Terms

Prolog supports this.

Mercury provides a meta-programming library for term manipulation which will let you write arbitrary values of type 'term', but there is currently no way to read or write user-defined data types of other types without explicitly writing code to do so.

We've actually implemented read/write of arbitrary types in Mercury, but the current implementation slowed down compilation time by about 25% last time we measured it, which seemed to be a very high price to pay, so currently that feature is not enabled. But we'd like to support it in some future release.


4. Program Modification Support (assert/retract and relatives)

Prolog supports run-time program modification. Mercury does not, because modifying a running program cannot be declarative. Dynamically loading code into a running program can be declarative, and it is something that Mercury may eventually support.

Mercury does include standard library modules for handling sets, maps, etc.; these declarative alternatives can replace the use of assert/retract to store in-memory databases.


5. Higher-orderness (call and relatives)

ISO Prolog provides call/1, but there is no call/N (N>1). However, it is possible for a user to implement call/N (N>1) using call/1, univ/2, and append/3. For example:

call(G0, X) :-
    G0 =.. L0,
    append(L0, [X], L),
    G =.. L,
    call(G).

Most Prolog systems implement call/1 quite inefficiently, and the calls to univ/2 and append/3 make call/N even less efficient.

Mercury provides a reasonably efficient call/1 and call/N (N>1). The latest development version also does fairly aggressive inlining and specialization of higher-order predicates within a module. We think that in most cases, this will entirely eliminate the overhead of using higher calls, which means that you can use them much more freely. However, we don't do any cross-module inlining or specialization, so this only works within modules, not across modules.

As a convenience, Mercury also provides lambda expressions, so that you can write a higher-order term without resorting to using an auxiliary predicate.


6. Database Query Support (setof/3 and relatives)

Both Prolog and Mercury provide support for getting all solutions to a goal. With regard to expressiveness, I think they're about equal, and with regard to efficiency, each will be better in different circumstances but they probably come out roughly even overall. A theoretical difference is that the Mercury versions are purely logical, properly scoped predicates, whereas the Prolog versions are all non-logical and improperly scoped. That probably doesn't make a huge amount of difference from a practical perspective. One important practical difference is that Mercury doesn't allow you to depend on the order of solutions (this is necessary to ensure soundness).


7. Constraint Systems (rational trees, finite domains, attributed variables)

ISO Prolog provides no support for constraint handling other than full unification (Herbrand constraints), although many Prolog and Prolog-like systems do provide such support. Mercury does not provide any support for constraint handling, not even Herbrand constraints.

We're working on adding support for constraints, using a small extension to Mercury's mode system, and some hooks in the generated code. To start with, we're interfacing to the CLP(R) constraint solver, since there is a research group here who have been working on CLP(R). After that we will look towards interfacing to other constraint solvers on atomic types, e.g. integer, boolean, and finite domain constraints.


8. Development Environment (interactive top level, incremental compiler)

ISO Prolog doesn't mandate anything here, but pretty much all Prolog systems provide some sort of interactive top level, and you can buy commercial systems with GUI development environments.

Mercury doesn't have anything much in the way of support for a GUI development environment. It also doesn't have any support for developing GUI programs (as opposed to developing programs using a GUI development environment). Even the C interface doesn't help much, since in the current public release it is one-way: Mercury can call C, but not vice versa. However, most of the work for a bidirectional C interface has been done, so the next release of Mercury will very likely support C calling Mercury.

Given that Mercury is a recent language, the lack of GUI development environments is not too surprising. But there is a reasonable chance that there will be at least one GUI environment for Mercury in the next 6-9 months.

Mercury doesn't have an interactive top-level either. The current implementation comes with some support for using SICStus or NU-Prolog to execute Mercury programs, although this support does not handle the full Mercury language.

Mercury does have quite good support for a UNIX-based development environment using the usual UNIX tools.

We're not sure exactly what you mean by an incremental compiler, but we suspect the underlying wish is for a fast compiler with fast turn-around time after small changes. The Mercury compiler supports separate compilation, and the Mercury build system only recompiles modules which have changed or which depend on an interface that has changed. The Mercury compiler is unfortunately not fast; as programmers who use it on a day-to-day basis for developing a large (100,000 line) program, we find its speed to be tolerable (probably about 5-10 times slower than SICStus or NU-Prolog but faster than Aquarius Prolog). If you're compiling smaller programs, it's probably quite OK.

We don't know of any Prolog system which has a working incremental compilation system with a granularity finer than a single source file.


In Conclusion

From a practical perspective, the most important difference between Mercury and Prolog is that the two languages were designed with different aims. Mercury is a pure logic language that was specifically designed to support the needs of large, long-lived programs: reliability, maintainability, and efficiency, among others. Supporting the development of large, long-lived software products was not a design goal of Prolog. Prolog is more oriented towards exploratory programming. If you want a dynamically typed language that supports imperative features and dynamic program modification and is good for rapid prototyping of small programs, then Prolog will be a better choice than Mercury. If you want a purely declarative language, and one that provides the support that teams of software engineers need to build robust, maintainable, efficient real-world applications, then Mercury will be a better choice.

Peter's questions explored various aspects of language design which are important for the applications in which Prolog is currently being used. His questions did not cover many aspects of language design which are more relevant to Mercury's intended application area. To make the comparison more complete, perhaps an expert on Prolog (or another language, e.g. OZ) would like to compare their language with Mercury in areas such as the ones below.

  1. What support does the language offer for improving program reliability? What classes of bugs does the language design eliminate altogether or catch automatically at compile time or run time? When bugs are caught by the system, how useful are the diagnostics?

  2. What support does the language (or implementation) offer for debugging? Is it feasible to apply declarative debugging to the language?

  3. What support does the language offer for program maintenance? For example, what information can programmers easily find out about existing code?

  4. What support does the language offer for modularity? Has the language been used for programs of more than 10,000 lines of code? If so, how well did the language fare?

  5. What support does the language offer for programmers working in teams? Has the language been used for programs written by more than say 6 programmers? If so, how well did the language fare?

  6. What support does the language offer for code reuse?

  7. What support does the language offer for parallelism? How hard is it to automatically parallelize programs written in the language? Do the language or its idioms impose any limits on the level of parallelism? Does the language impose any overheads on parallel implementations?

  8. Does the language have a simple declarative semantics?

Prev Next Up Home Keys Figs Search New