[m-users.] Instantiatedness and handling io results

Julian Fondren jfondren at minimaltype.com
Sun Aug 4 18:38:42 AEST 2019


On 2019-08-04 02:48, Philip White wrote:
> Two questions:
> 1. How do I make this program type check?

The error tells you that the !.IO that you're passing into foldl is
mostly_unique, which is an error: the IO state must be unique. The
immediate error is that no foldl is defined that accepts mdi
parameters, but even if that were fixed you should still get other
errors due to this.

You've degraded the uniqueness of the IO state by using it in
semidet context, I believe. As the Mercury compiler isn't able to
generate programs that can roll the universe back to a prior state,
if I/O happens, it must /definitely/ happen. An easy fix is to use
conditionals and to put your I/O in the 'then' or 'else' cases.

This compiles and works, although the output isn't nice.

   :- module readtwo.
   :- interface.
   :- import_module io.
   :- pred main(io::di, io::uo) is det.
   :- implementation.
   :- import_module string, list, exception.

   main(!IO) :-
     read_word(Res1, !IO),
       read_word(Res2, !IO),
       ( if Res1 = ok(NStr) then
           ( if
               Res2 = ok(MStr),
               to_int(from_char_list(NStr), N),
               to_int(from_char_list(MStr), M)
           then
               foldl(io.write_int, (N .. M), !IO)
           else
               error("Bad second read")
           )
       else
           error("bad read")
       ).

   :- pred error(string::in) is erroneous.
   error(Reason) :-
       throw(Reason).

The input isn't that nice either, as you read in both numbers
before noticing that the first read was garbage.

> 2. What is the idiomatic way of handling a sequence of things which
> return results? In Haskell, there is do-notation for sequencing monads,
> but I haven't seen any monads in mercury.

I don't expect you to agree, but the xkcd joke about regular
expressions is how I think about Haskell solutions to problems.
So I'd just write a more convenient I/O predicate for this task:

   :- module readtwo2.
   :- interface.
   :- import_module io.
   :- pred main(io::di, io::uo) is det.
   :- implementation.
   :- import_module string, list, exception.

   main(!IO) :-
       read_int(N, !IO),
       read_int(M, !IO),
       foldl(io.write_line, (N .. M), !IO).

   :- pred read_int(int::out, io::di, io::uo) is det.
   read_int(N, !IO) :-
       read_word(Res, !IO),
       (
           Res = ok(NStr),
           ( if to_int(from_char_list(NStr), N0) then
               N = N0
           else
               throw("bad int")
           )
       ;
           (Res = eof ; Res = error(_)),
           throw("read failed")
       ).

Which is OK except for the sloppy error messages. What I'd rather
do is just:

   :- module readtwo3.
   :- interface.
   :- import_module io.
   :- pred main(io::di, io::uo) is det.
   :- implementation.
   :- import_module string, list.

   main(!IO) :-
       io.command_line_arguments(Args, !IO),
       ( if
           Args = [NStr, MStr],
           to_int(NStr, N),
           to_int(MStr, M)
       then
           foldl(io.write_line, (N .. M), !IO)
       else
           io.progname_base("readtwo3", Program, !IO),
           io.format(io.stderr_stream, "usage: %s <n> <m>\n",
               [s(Program)], !IO),
           io.set_exit_status(1, !IO)
       ).


More information about the users mailing list