[m-users.] Problem with unique modes

Ricardo Correia lists.mercurylang.org at wizy.org
Fri Jul 23 11:27:34 AEST 2021


Hi,

I'm a Mercury beginner that is trying to learn the language and I'm not
yet familiar with most of the Prolog/Mercury terminology, so please bear
with me :)

I have attached a Mercury program which is failing at runtime with an
exception due to what seems to be a known compiler bug, but I'm not
entirely sure.

I have a `state` type which is composed of two integers and a hash
table.

Since it has a hash table, variables of this type should be unique, I
assume, so that the program doesn't backtrack with respect to the
contents of the hash table.

However, I'm not entirely sure how to make type `state` unique.

I've tried simply using the ::di and ::uo modes, but then fill/3 fails
to compile the call to `hash_table.det_insert/4`,
although I don't understand exactly why.

Then, I tried to do what the `hash_table` standard library module does,
I think, by declaring an instantiation (?) and some custom `sdi` and
`suo` modes, because `hash_table` is also a type which has some integers
and a vector (which also has to be unique) so I assumed my type was
similar enough.

This compiled fine but then the program fails with an exception because
(as far as I can see) when backtracking, the integer fields within the
`state` type do backtrack but the hash table doesn't.

I am guessing that this is related to the first limitation mentioned in
the `LIMITATIONS` file and in the hash table module -- specifically,
that the Mercury compiler doesn't handle nested unique modes yet.

Although, even if this is true, I am disappointed that the Mercury
compiler didn't give me a warning or an error when compiling and allowed
my program to misbehave at runtime.

My questions are:

1. Is my understanding above correct?

2. Are there still plans to fix nested unique modes? Also, is this
something that is being worked on?

3. Is there a way to still use hash tables or vectors within other types
somewhat safely, i.e. in a way that the compiler warns if the code
may backtrack unexpectedly, like it usually happens with the `io` type?

Also, I should mention that as a beginner and even after reading both
tutorials and some of the reference manual, I find that the LIMITATIONS
file is extremely unclear with respect to the first limitation.

These are the issues in the first limitation that I am struggling with:

1. It says that "definite aliasing" is "not allowed", however I still
don't quite understand what "definite aliasing" is or what
"is not allowed" means (does the compiler give a warning or error in
this case or is the program simply miscompiled?).

2. It says that "partial instantiation" and "nested unique modes" are
"unusable", but again, it doesn't explain what "partial instantiation"
means nor what "unusable" means in this case. Again, does the compiler
give a warning or error or is the program simply miscompiled?

3. It then gives a detailed explanation, but I'm not sure if the detailed
explanation refers to the whole "definite aliasing" limitation or only to
the "partial instantiation working by chance" issue.

4. The detailed explanation talks about scope, but again I don't know
what scope means in this case (what other scopes are there?)

5. It refers to Mantis bug 311, which seems to have nothing to do with
nested unique modes, I think. The attached program which exhibits the
error in bug 311 *does* generate a compiler warning, but not my
attached program.

6. The first limitation would be much clearer if there were some
examples of code which works (including the special case mentioned in
the detailed explanation) and code which should work but doesn't (and
whether it doesn't because the compiler fails or because the program
will misbehave at runtime).

Thanks!
-------------- next part --------------
:- module error.

:- interface.

:- use_module io.

:- type io == io.io.

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

:- implementation.

:- import_module hash_table.
:- import_module int.
:- import_module unit.

:- type ht == hash_table(int, unit).

:- type state
	--->
		state(
			next :: int,
			step :: int,
			table :: ht
		).

:- inst state == bound(state(ground, ground, hash_table)).
:- mode sdi == di(state).
:- mode suo == out(state).

:- pred fill(int::in, state::di, state::uo) is det.
fill(UpTo, State0, State) :-
	State0 = state(Next, Step, H0),
	(if
		Next > UpTo
	then
		State = state(Next, Step, H0)
	else
		hash_table.det_insert(Next, unit, H0, H1),
		State1 = state(Next + Step, Step, H1),
		fill(UpTo, State1, State)
	).

:- pred has_n(int::in, state::sdi, state::suo) is semidet.
has_n(N, !State) :-
	fill(N, !State),
	hash_table.search(!.State^table, N, _).

:- pred test(int::in, int::in, state::sdi, state::suo) is det.
test(N1, N2, !State) :-
	(if
		has_n(N1, !State),
		has_n(N2, !State)
	then
		true
	else
		true
	).

main(!IO) :-
	Table = hash_table.init_default(int.hash),
	State1 = state(1, 2, Table),
	test(13, 14, State1, State2),
	test(13, 14, State2, _).


More information about the users mailing list