# Mercury Notes
# Defining predicates
There is many method to defines predicates.
% defining a pure predicate with mode and determinism.
:- pred mypredicate(string::in, int::out) is det.
% defining a pure predicate with separated modes.
:- pred mypredicate(string, int).
:- mode mypredicate(in, out) is det.
% defining an impure predicate with I/O
:- pred mypredicate(string::in, int::out, io::di, io::uo) is det.
# Pattern Matching
If you are familiar with Prolog, you should probably know how to use pattern matching. Mercury uses the same method to decompose data-structures. In Haskell, you use Monad to avoid side effect or check the state of something. In Mercury, you will use pattern matching to ensure if something was correctly executed or not, by also using a kind of monad.
main(!IO) :-
io.open_input("myfile", Stream, !IO),
% in this part of the code, Stream can have multiple type
% like ok(Stream) or error(Error). If you are not checking
% the whole possibilities from this code it will generate
% a semidet function, not compatible with impure function.
% So, here the solution, using a if/then structure with
% pattern matching.
( Stream = ok(S) ->
% do somemthing here with the correct stream S ...
;
Stream = error(Error)
% do something with the error message
).
Here, the pattern matching is different from the one present
in Erlang. The right side of the pattern is matched with the
left side. The variable S will contain the content of the
Stream variable if this one has the type of ok().
# Strong Type
# using a map
Mercury supports many different kind of data-structure, like
set, bag or map. Both are defined in ${mercury_src}/library/*.m.
Here an example with a map data-structure
:- import_module int.
:- import_module string.
:- import_module map.
main(!IO) :-
% create a map. In our example,
% we will take a string as key,
% and associate an integer to
% the value. This one will
% represent the length of the
% string.
map.init(Map : map(string, int),
% we insert into Map a key "test"
% with a value "4". The result is
% another map called Map2. This
% insert can fail if the key is
% already present in the map. You
% must explicitely check it by using
% an if/then structure.
map.det_insert("test", 4, Map, Map2),
% to find if a key is set, you can
% use search/3. Same as the previous
% insert predicate, you should probably
% use a if/then structure in case
% of the key is missing.
map.search(Map, "test", Value),
% So, if the key exist, we can update
% it with det_update/4
map.det_update("test", 5, Map2, Map3).
# Create libraries
To create a modules or a library in Mercury, you will probably
need to compile your code without a main predicate. To make that
possible, you can use mmc -Ec ${module_name}. This command will
generate your library.
$(module_name).o:
mmc -Ec $(module_name)
Another required thing is the interface file, containing the
description of the predicate's interfaces. You can generate it
by using mmc -Ei $(module_name).
$(module_name).int:
mmc -Ei $(module_name)
Now, if you want to use your library in your main code, you must import it.
:- import_module mymodule.
And help the linker to find the required code.
mycode: $(module_name).o $(module_name).int
mmc --make -E mycode $(module_name)
You can execute mycode.
# Using POSIX library
Mercury can support POSIX standard by using the library present in the
source tree. This directory is under extra/posix and must be build
with mmake command.
cd ${mercury_src}/extra/posix
mmake
It will generate two libs: libposix.a and libposix.so. By looking
directly into code sample, you need to build your application with
these rules:
myapp:
mmc --search-lib-files-dir ${mercury_src}/extra/posix \
--init-file ${mercury_src}/extra/posix/posix.init \
--link-object ${mercury_src}/extra/posix/libposix.a \
--make -E $@
Now, myapp.m can import the POSIX library and use it.
% ...
:- implementation.
:- import_module posix.
% ...