[m-users.] What makes this mostly_unique? Is there a quicker route through IO?

Jeremy W. Sherman jeremyw.sherman at gmail.com
Sun Dec 6 14:17:25 AEDT 2020

I've been using Mercury to do Advent of Code
(https://github.com/jeremy-w/adventofcode-2020). Every challenge
involves input parsing. As a result, I'm interested in only the happy
path when reading and parsing. I would prefer to avoid exhaustively
switching over the result of IO operations. So I hoped to be able to
basically stack a sequence of operations that I judge unlikely to
fail, then go "ah well, something went wrong" in a single, generic
unhappy path.

But this hope foundered quickly on an issue I'm having trouble
understanding with the inferred uniqueness of the IO state terms. I've
boiled it down to this minimal example:

:- module example_io_mostly_unique.

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

:- implementation.
main(!IO) :-
Path = "does not exist",
io.open_input(Path, ok(_), !IO)
io.write_line("ok", !IO)
io.write_line("err", !IO)

Then the compiler complains that !.IO is only mostly_unique, not fully
unique as open_input/4 requires:

mmc --make --use-subdirs -E example_io_mostly_unique
Making Mercury/int3s/example_io_mostly_unique.int3
Making Mercury/ints/example_io_mostly_unique.int
Making Mercury/cs/example_io_mostly_unique.c
example_io_mostly_unique.m:011: In clause for `main(di, uo)':
example_io_mostly_unique.m:011: in argument 3 of call to predicate
example_io_mostly_unique.m:011: `io.open_input'/4:
example_io_mostly_unique.m:011: mode error: variable `STATE_VARIABLE_IO_0'
example_io_mostly_unique.m:011: has instantiatedness `mostly_unique',
example_io_mostly_unique.m:011: expected instantiatedness was `unique'.
** Error making `Mercury/cs/example_io_mostly_unique.c'.

The Language Reference Manual
explains this would happen when the value might be needed on
backtracking, but I'm having trouble seeing the scenario where
execution might backtrack through this, particularly in this
simplistic scenario.

The only way I've found to work around this is to check each possible
constructor, e.g. matching out both the ok(Stream) and err(_), even if
I don't intend to do anything with the err(_) term itself. This
quickly grows tedious when there's a sequence of operations, so if
there's a more direct route, I am all ears!

Thank you,
Jeremy W. Sherman

More information about the users mailing list