[m-users.] Problem with unique modes

Ricardo Correia lists.mercurylang.org at wizy.org
Sat Jul 24 01:49:50 AEST 2021

Hi Mark,

Thanks for your feedback! Please see below.

On Fri, Jul 23, 2021 at 03:08:42PM +0200, Mark Clements (gmail) wrote:
> Fellow beginner - so I possibly should not answer:).
> If you change the modes for the `fill` predicate back to `::sdi` and `::suo`
> and comment out `has_n(N2, !State)` then your code runs (attached).

Indeed. However, please note that the code I attached was already a
minimal version of the real code I'm using (minimal in the sense that it
still exhibited the problem but all irrelevant code was removed), so
it's not surprising that removing or commenting out another line of code
doesn't exhibit the problem anymore :)

Note, however, that your code is not really computing the same thing
anymore -- your test/4 predicate only checks whether N1 is in the hash
table (after being filled), while my test/4 predicate checks whether
both N1 and N2 are in the hash table. The discrepancy would be clearer
if test/4 returned different results on both branches of the `if`
statement (which is what happens on my real code).

Also, please note that I know how to fix this particular issue (indeed I
already did in my real code): I simply made sure that all the code that
modifies the hash table never backtracks (i.e. I made all functions
deterministic -- in this case, has_n/3). Another way to fix would be to
use some functional data structure (say, the `set_tree234` module)
instead of a hash table, but that would change the performance profile
more significantly.

But I think the bigger issue is that this runtime failure should never have
happened in the first place, i.e. I think the mercury compiler should
have given a warning or an error instead of successfully compiling this
code, which is why I was motivated to send my previous email.

> I suggest that the error for `hash_table.det_insert/4` has to do with writing
> the same values to an existing hash table (in parallel?) - but that
> explanation seems lacking, as the sequential tests are okay.

I think it's because when has_n/3 fails, the State variable goes back to
a previous value (i.e. there is backtracking), but the hash table
doesn't. In fact, hash tables are supposed to be unique, so it shouldn't
be possible to backtrack over them, which is why the code should have
never compiled in the first place, I think.

Note that as long as `step` is initialized to a value larger than 0
(which it is) and assuming that Next+Step doesn't overflow (which it doesn't
in this case) then fill/3 should never insert the same value in the hash table
twice, because the `state` type keeps track of the last value that was inserted
(well, the next value to insert, but the result is the same).

So, in theory, code outside fill/3 shouldn't have caused fill/3 to fail
(assuming that they don't mess with the internals of the State variable and
that there isn't any concurrency, of course).

> For the code, I also introduced a State variable - but that seems to be more
> a matter of style.

Thanks, I didn't know how to do that, that is very useful!
(stylistically speaking, at least) :)

More information about the users mailing list