[mercury-users] Request for comments on this code

Ian MacLarty maclarty at csse.unimelb.edu.au
Tue Jul 11 13:32:03 AEST 2006


On Tue, Jul 11, 2006 at 12:03:55PM +1000, Peter Schachte wrote:
> On Tue, Jul 11, 2006 at 11:15:35AM +1000, Ian MacLarty wrote:
> 
> > For every IO primitive executed in the program the first IO state
> > argument is the state of the universe at the time that IO primitive is
> > executed, while the second IO state argument is the state of the
> > universe at the time the *next* IO primitive is executed.  The first
> > argument of main/2 is thus the state of the universe at the time the
> > first IO primitive in the program is executed and the second argument is
> > the state of the universe when the program terminates (if main does
> > nothing then both arguments are the state of the universe at the time
> > the program terminates).
> > 
> > People may have problems with this view since it means the IO state must
> > also contain the state of the heap, stack, etc (since these, along with
> > the speed of the machine, ambient temperature, and position of the
> > planets, etc determine when exactly the next IO primitive will be
> > executed).  I don't really have a problem with this though.  So what if
> > a primitive IO action must also know when the next future IO action is
> > to be executed?  It's still deterministic with respect to the current
> > state of the universe since we can't go back in time.  Reasoning about
> > IO state this way allows you to measure the time taken by code that
> > doesn't execute any IO primitives.
> 

I should have said this interpretation allows you to measure the time
between calls to IO primitives.

> But any goal that might affect the IO state must thread the IO state
> through.  If you consider the state of the Mercury process to be part
> of the IO state, then *every* Mercury goal would need to thread the IO
> state through.

I don't think so, because under my interpretation each IO primitive
takes account of all the Mercury code that will execute before the next
IO primitive executes.

Consider the following goal:

	get_time(T0, IO0, IO1),
	something_to_benchmark(X),
	get_time(T, IO1, IO2),

Lets suppose that something_to_benchmark takes half an hour and that the
program starts running at 10:30.  If IO1 is the state of the universe
after the first call to get_time, then the time stored in IO1 will be
10:30, which means the time returned by the second call to get_time will
also be 10:30.  However if we interpret IO1 to be the time at the start
of the second call to get_time, then the time stored in IO1 will be
11:00.  Under my interpretation the first call to get_time knows when
the second call to get_time will happen, so it sets the time stored in
IO1 to 11:00.  something_to_benchmark does update the IO state in a
sense, but we don't need to model that in the call to
something_to_benchmark, since its effect is already in the value IO1.

The compiler could of course put the two calls to get_time/3 after
something_to_benchmark/1 though.  I'm just offering an interpretation of
the IO states that allows us to measure the time elapsed between two
primitive IO actions.  If you interpret the IO state arguments as being
the state of the universe before and after the call to the IO primitive,
then you can't really measure the time elapsed between two primitives.

> And that means no goal reordering, and no
> nondeterminism.  Otherwise in a goal
> 
> benchmark_something(X, Z, Time, !IO) :-
> 	time_consuming(X, Y),
> 	get_cpu_time(T0, !IO),
> 	something_to_benchmark(Y, Z, !IO),
> 	get_cpu_time(T1, !IO),
> 	Time = T1 - T0.
> 
> Mercury is perfectly entitled to move the call to time_consuming/2
> after the first call to get_cpu_time/3.  I would also argue that if
> something_to_benchmark/4 never affects the IO state, the compiler
> should be allowed to remove the IO state arguments, and then should be
> able to move the call to something_to_benchmark/2 anywhere it likes.
> So while the IO state trick works now, keeping it working may limit
> optimizations we may really want to implement someday.
> 
> I think it's pretty important to Mercury's IO state idea that the IO
> state not be considered to include any artifacts of decisions made by
> the Mercury compiler.  Otherwise the Mercury compiler cannot change
> those things without affecting the correctness of the code.  I've
> always heard the IO state referred to as the state of the world
> *outside* of the current Mercury computation.

But that's impossible to define.  Say for example I have a thermometer
hooked up to my computer.  The predicate that reads the temperature of
the thermometer must have a pair of IO state arguments if it is to be
pure, no?  However the temperature of the air around the computer would be
influenced by decisions made by the Mercury compiler (for example less
optimizations might make the air warmer).  I think the Mercury process
must be part of the IO state, since it affects other things we agree are
part of the IO state.

> 
> The idea of treating benchmarking as a special debugging-like
> operation is much more attractive to me than making the IO state
> contain the state of the internals of the current computation.  Or
> using impurity should work, though there are still worms squirming
> around where you promise the program pure.
> 

Yes I agree.

Ian.
--------------------------------------------------------------------------
mercury-users mailing list
post:  mercury-users at csse.unimelb.edu.au
administrative address: owner-mercury-users at csse.unimelb.edu.au
unsubscribe: Address: mercury-users-request at csse.unimelb.edu.au Message: unsubscribe
subscribe:   Address: mercury-users-request at csse.unimelb.edu.au Message: subscribe
--------------------------------------------------------------------------



More information about the users mailing list