Skip to content
wangp edited this page May 6, 2017 · 2 revisions

Compiling your first Mercury program

Here is the traditional first program in Mercury:

:- module hello.
:- interface.

:- import_module io.

:- pred main(io::di, io::uo) is det.

:- implementation.

main(!IO) :-
    write_string("Hello, world!\n", !IO).

Save this in a file called hello.m, then you can compile it like this:

mmc hello.m

If all goes well, it will produce an executable that you can run:

./hello

Program structure

Mercury programs are organised into modules. The first line declares a module named hello. All declarations begin with the :- symbol.

Modules are composed of two parts, the interface and the implementation. The second line begins the interface.

The next line imports a module called io from the standard library, for input and output.

The next line exports a predicate called main. A predicate is similar to a function or procedure in other languages. Both of its parameters have the type io, imported from the io module (the same symbol can name different things in Mercury). We will explain the significance of di, uo and is det later. For now, it suffices to say that the first argument is input (in fact, destructive input), the second argument is output (unique output), and the predicate is deterministic.

The next line begins the implementation section of the module.

In the implementation section, we have the definition of the main predicate. It is defined by a clause consisting of three parts: the head, the neck (:-), and the body, followed by a full stop (.). The head contains the predicate name, and the body makes a call to write_string which comes from the io module. But what are the mysterious !IO bits?

Variables and state variables

Variables in Mercury always begin with a capital letter [A-Z] or underscore, e.g. Apple or _Banana are valid variable names.

An exclamation mark (!) followed by a variable name is called a state variable and represents two automatically numbered variables. Another way to write the clause without using state variables is this:

main(IO0, IO) :-
    write_string("Hello, world!\n", IO0, IO).

It works like this: a Mercury program enters main with a value representing the "state-of-the-world" at that point, bound to the input variable IO0 (it has the type io). The call to write_string takes IO0, writes a string to the console, then returns a new "state-of-the-world" -- the world in which the string was written -- which is then bound to a variable IO. When main exits, the value of IO is returned to its caller.

To make two calls to write_string, we could write the following. Notice the use of comma (,) to join two calls in the body.

main(IO0, IO) :-
    write_string("Hello, ", IO0, IO1),
    write_string("world!\n", IO1, IO).

For three calls:

main(IO0, IO) :-
    write_string("Goodbye, ", IO0, IO1),
    write_string("cruel ", IO1, IO2),
    write_string("world.\n", IO2, IO).

To call write_string you must provide an io value as input, and you get a new value back out as output. (We will explain why in future.) It quickly becomes tedious to number variables manually, which is why we introduce state variables so soon. The previous predicate can be written more conveniently:

main(!IO) :-
    write_string("Goodbye, ", !IO),
    write_string("cruel ", !IO),
    write_string("world.\n", !IO).

Each occurrence of a state variable will be expanded out by the compiler into two normal variables, numbered in an obvious way. State variables make it much easier to read and write programs involving a sequencing of "states".

Now that we understand the basic structure of a Mercury program, how to compile and run a program, and how to get some output on the screen, we can continue.

Exercises

  • Compile and run one of the programs above.

  • What happens if you change the order of the write_string calls without renumbering the variables, and without using state variables?

  • Try passing the same "state-of-the-world" value as input to two different calls to write_string, what happens?

Clone this wiki locally