[mercury-users] Re: your mail

Ralph Becket rafe at cs.mu.OZ.AU
Tue Jul 20 09:23:35 AEST 2004


hanberg at ruc.dk, Monday, 19 July 2004:
> Hi
> 
> I'm trying to run the following code, but keep getting the same error.
> proveble2 gets a list of expressions and proveable returns an int
> given an expression and an int.
> 
> :- pred proveable2(list(expr(T)), io__state, io__state).
> :- mode proveable2(in, ui, uo) is det.

A couple of points about modern Mercury style:

(a) we prefer the synonym `io' to `io__state';

(b) when a predicate has only one mode, we prefer combined `predmode'
syntax:

:- pred proveable2(list(expr(T))::in, io::di, io::uo) is det.

> proveable2([Head|Tail], IO_In, IO_Out) :- if proveable(Head, 4, INT) then
> print(INT, IO_In, IO_Out), proveable2(Tail, IO_In, IO_Out) else
> io__write_string("test", IO_In, IO_Out).
> 
> proveable2([], IO_In, IO_Out) :- print(0, IO_In, IO_Out).

Either you or your mailer is doing terrible things to the formatting!
Here's the formatted version:

proveable2([Head|Tail], IO_In, IO_Out) :-
	if proveable(Head, 4, INT) then
		print(INT, IO_In, IO_Out),
		proveable2(Tail, IO_In, IO_Out)
	else
		io__write_string("test", IO_In, IO_Out).

proveable2([], IO_In, IO_Out) :-
	print(0, IO_In, IO_Out).

Some more points:

(c) always put parentheses around if-then-else goals and expressions as
this helps avoid confusing syntax errors (these things do happen from
time to time);

(d) it's a good idea to fully qualify predicate names imported from
other modules (types and functions are usually best left unqualified),
so write `io__print' rather than just `print';

(e) it's usual to put the base case before the induction step(s), hence

proveable2([], IO_In, IO_Out) :-
	print(0, IO_In, IO_Out).

proveable2([Head|Tail], IO_In, IO_Out) :-
	( if proveable(Head, 4, INT) then
		io__print(INT, IO_In, IO_Out),
		proveable2(Tail, IO_In, IO_Out)
	else
		io__write_string("test", IO_In, IO_Out)
	).

Now, your error:

> filereader2.m:072: In clause for `proveable2(in, ui, uo)':
> filereader2.m:072:   in argument 2 of call to predicate `io:print/3':
> filereader2.m:072:   unique-mode error: the called procedure would clobber
> filereader2.m:072:   its argument, but variable `IO_In' is still live.

Look at the second clause for proveable2 above.  The mode signature
for the second argument tells us that on entry IO_In will be unique
(mode di is defined as (unique >> clobbered)).

Next we consider the `then' arm of the conditional goal:

		io__print(INT, IO_In, IO_Out),
		proveable2(Tail, IO_In, IO_Out)

The signature for io__print is

:- pred io__print(T::in, io::di, io::uo) is det.

telling us that *before* the io__print call IO_In must be unique (and we
know that it is), but *after* the io__print call IO_In will be
clobbered.

However, the next goal passes IO_In to proveable2 in its second
argument, but IO_In is now clobbered and not unique, hence the mode
error reported by the compiler.

The thing to bear in mind is that every IO call takes in a unique
"state-of-the-world" value, clobbers it, and returns a new, unique
"state-of-the-world" value as a result.

The way to fix your program is to name your IO states appropriately (I'm
going to use the standard convention where a sequence of "state values"
are labelled X0, X1, X2, ..., X):

proveable2([], IO0, IO) :-
	print(0, IO0, IO).

proveable2([Head|Tail], IO0, IO) :-
	( if proveable(Head, 4, INT) then
		io__print(INT, IO0, IO1),
		proveable2(Tail, IO1, IO)
	else
		io__write_string("test", IO0, IO)
	).

Now the call to io__print takes in a unique IO0, clobbers it and returns
a new, unique IO1.  Then proveable2 takes the unique IO1, clobbers it,
and returns a new, unique IO.

Which brings me to...
(f) to make life easier for the programmer we introduced "state
variable" syntax to Mercury.  You can look up the details in the
reference manual, but the preferred way of writing your predicate would
be like this:

proveable2([], !IO) :-
	print(0, !IO).

proveable2([Head|Tail], !IO) :-
	( if proveable(Head, 4, INT) then
		io__print(INT, !IO),
		proveable2(Tail, !IO)
	else
		io__write_string("test", !IO)
	).

The !IO actually stands for *two* arguments, not one, and the compiler
automatically expands this out to something equivalent to our definition
above using IO0, IO1, IO etc.

-- Ralph
--------------------------------------------------------------------------
mercury-users mailing list
post:  mercury-users at cs.mu.oz.au
administrative address: owner-mercury-users at cs.mu.oz.au
unsubscribe: Address: mercury-users-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-users-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the users mailing list