Friday, October 12, 2007

The Mercury Programming Language

Mercury is a programming language that combines concepts from the logic and functional programming paradigms. In this post I'm going to show a couple of features of this language.

The hello world program looks like this:


:- module hello.


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

:- implementation.

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



Where module hello is a module declaration, interface declares elements exported by this module and implementation contains the code for this module.

A couple of days ago I started reading the Ralph Becket's Mercury tutorial which is a very nice tutorial for learning the language. Also there's useful documentation available in the website including a Prolog to Mercury Transition Guide .

The language allows the creation of functions, for example here's the mandatory factorial function:


:- func factorial(int) = int.
factorial(N) = (if N = 0 then 1 else N*factorial(N-1)).


But also the language allows the creation of predicates that result in multiple solutions as in Prolog. For example see the following predicate that generates the numbers from 0 to N:


:- pred numbers(int::in, int::out) is nondet.

numbers(0,0).
numbers(N,R) :-
N > 0,
(
numbers(N-1,R);
R = N
).


The pred section declares the numbers predicate. It says that the first argument is of type int and is for input and the second argument is also type int and is for output. Finally the is nondet says that this predicate may result in zero or more solutions.

The first rule says that when asking for numbers from 0, return 0. The second rule says that if asking for a number greater than 0 then return all the numbers from 0 to N-1 and then return N.

Using this predicate we can implement the following example from a previous post:

We need to write a program to find a 4-digit number such that ABCD*4 = DCBA where A,B,C,D are the digits of that number.

(Complete problem is described here)

A Mercury predicate that solves this problem looks like this:


:- pred solve_problem(list(int)::out) is nondet.

solve_problem(R) :-
numbers(9,A),
numbers(9,B),
numbers(9,C),
numbers(9,D),
A > 0,
(1000*A + 100*B + 10*C + D)*4 = (1000*D + 100*C + 10*B + A),
R = [A,B,C,D].


As with Prolog the backtracking mechanism will find the values of A,B,C and D that satisfy the constraints.

In order to use the result of this predicate the solutions predicate is used. This predicate returns a list with all the results from the specified predicate.


main(!IO) :-
solutions(solve_problem,R),
io.write(R,!IO),
io.write_string("\n",!IO).


This program writes:


[[2, 1, 7, 8]]


In future post I'll try to explore more features of this interesting language.