[m-users.] di / uo -- some clarification please.

Julian Fondren jfondren at minimaltype.com
Tue Aug 6 05:07:45 AEST 2019


On 2019-08-05 12:19, emacstheviking wrote:
> Hello,
> 
> I seem to have somehow conflated the use of the state variable form !X
> with the use of the modes "di" and "uo" because so far the the only
> place I have used such notation has been with the special !IO state
> variable.
> 
> I now have a game loop:
> 
> :- pred game_loop(
>     app_state::di,  app_state::uo,
>     game_state::di, game_state::uo,
>     io::di,         io::uo)
> is det.
> 
> game_loop(!AppState, !GameState, !IO) :-
>      :
>      : GAME STATE AND APP STATE CODE...
>      :
>     game_loop(!AppState, !GameState, !IO).
> 
> This is condensed for clarity(!) but have I understood the concepts
> correctly. My intention is that after one pass of the game loop the
> "old" (di) application and game states can be junked i.e. their memory
> deallocated as the new incarnations are now the current ones, ready
> for the tail-cail back into the next iteration of the game loop.
> 
> Is that the correct use case?
> 
> The game state will contain all the mutable stuff for the game and the
> application state is slightly higher level stuff like "should I
> terminate" etc.

On efficiency, I've no idea. But you'll have a lot of trouble
maintaining the uniqueness of the state.

Consider:

   :- module dupe.
   :- interface.
   :- import_module io.
   :- pred main(io::di, io::uo) is det.
   :- implementation.
   :- import_module int.

   :- type app_state
       --->    app_state(
                   title :: string,
                   rounds :: int
               ).

   main(!IO) :-
       game(app_state("app", 0), !IO).

   :- pred game(app_state, io, io).
   :- mode game(di, di, uo) is det.
   game(!.A, !IO) :-
       new_round(!A),
       %io.print_line(!.A, !IO),
       io.nl(!IO),
       game(!.A, !IO).

   :- pred new_round(app_state::di, app_state::uo) is det.
   new_round(!A) :-
       !A^rounds := !.A^rounds + 1.

This compiles and works (and outputs infinite blank lines).

Try and uncomment the io.print though and you get this:

   Making Mercury/int3s/dupe.int3
   Making Mercury/ints/dupe.int
   Making Mercury/cs/dupe.c
   dupe.m:023: In clause for `game(di, di, uo)':
   dupe.m:023:   in argument 1 of call to predicate `dupe.game'/3:
   dupe.m:023:   mode error: variable `STATE_VARIABLE_A_9' has 
instantiatedness
   dupe.m:023:   `ground',
   dupe.m:023:   expected instantiatedness was `unique'.
   ** Error making `Mercury/cs/dupe.c'.

You'll need to make sure that such 'borrowings' of the state are
always done by passing it as a ui parameter to a predicate.

Anyway, I'd gotten the impression from somewhere that uniqueness
wasn't something you can really exploit in Mercury for your own
code. I'm not sure why, but note that even the array stdlib module
punts on ui/uo modes:

   :- mode array_di == di(uniq_array).
   :- mode array_uo == out(uniq_array).
   :- mode array_ui == in(uniq_array).

If uniqueness were more practical I'd expect the io module to use
it even for input/output streams, to enforce the caller going on
to close the streams.


More information about the users mailing list