[mercury-users] State variables as function arguments.

Peter Schachte schachte at csse.unimelb.edu.au
Sat Feb 10 11:20:20 AEDT 2007

Julian Fondren wrote:
> The Language Reference Manual says:
>  `!X' may not appear as an argument in a function application
>  since this would not make sense given the usual interpretation
>  of state variables and functions.
> What is the 'usual interpretation' of these?

That's a very good question.  I expect we all know the usual interpretation of
a function invocation:  it denotes the unique value resulting from the
application of the function to the supplied arguments.  Since this is a
function in the mathematical sense, the value is unique.

In my view, the natural interpretation of !X is as a value that may be changed
throughout the execution of the clause.  The reference manual says something a
bit different:

	A state variable is written !.X or !:X, denoting the "current" or
	"next" value of the sequence labelled X. An argument !X is shorthand
	for two state variable arguments !.X, !:X; that is, p(..., !X, ...)
	is parsed as p(..., !.X, !:X, ...).

In either view, it's clear that the order of appearance of !X occurrences in a
clause is significant.  It's also clear that having multiple occurrences of !X
in a single atom would be rather strange.  But of course function applications
appear within an atom.  So if you have a function

>  :- func test(string, io, io) = int.

and were permitted to write, say, 0 < test("foo", !IO), then you could also
write test("foo", !IO) < test("bar", !IO).  We would naturally expect this to
be equivalent to test("bar", !IO) > test("foo", !IO), but it wouldn't be.

What it comes down to, is that state variable notation changes the meaning of
conjunction in clauses that use it.  This is pretty significant, but also
pretty easy to understand because the atoms conjoined together are at the "top
level" of the program.  If state variable notation were allowed in function
application, it would change the meaning of every function, which is much more

> Actual code that I fixed to deal with this now looks like
>        or_die("dir", readable(forget_dir, IO1, IO2), IO2, IO3),
>        or_die("forget", readable(forget, IO3, IO4), IO4, IO5),

If you can find a convenient way to use predicates instead of functions where
you want to do I/O, it would work out better for you.  Perhaps you could make
the second argument to or_die be a predicate rather than a function, and thread
the IO state through it:

	or_die("dir", readable(forget_dir), !IO),
	or_die("dir", readable(forget), !IO),

where or_die is coded:

	or_die(Str, Closure, !IO) :-
		Closure(Status, !IO),

Peter Schachte              I worry that 10 or 15 years from now, [my child]
schachte at cs.mu.OZ.AU        will come to me and say 'Daddy, where were you
www.cs.mu.oz.au/~schachte/  when they took freedom of the press away from
Phone: +61 3 8344 1338      the Internet?' -- Mike Godwin
mercury-users mailing list
Post messages to:       mercury-users at csse.unimelb.edu.au
Administrative Queries: owner-mercury-users at csse.unimelb.edu.au
Subscriptions:          mercury-users-request at csse.unimelb.edu.au

More information about the users mailing list