[m-dev.] for review: update state transformation

Fergus Henderson fjh at cs.mu.OZ.AU
Wed Mar 29 19:58:17 AEST 2000


On 29-Mar-2000, Peter Ross <petdr at cs.mu.OZ.AU> wrote:

> library/int.m:
>     Add associativity declarations for + and *.

Hmm... that might be a bit problematic in future,
if/when we add (optional) range checking for ints.

In particular, the accumulator transformation could then transform a program
which does not overflow into one that does overflow.

Well, I suppose we can deal with that issue if/when we add
range checking.  Just something to bear in mind...

> Index: library/int.m
...
> -	% commutivity of +
> +	% commutivity and associativity of +
>  :- promise all [A,B,C] ( C = B + A <=> C = A + B ).
> +:- promise all [A,B,C,ABC] ( ABC = (A + B) + C <=> ABC = A + (B + C) ).
>  
> -	% commutivity of *
> +	% commutivity and associativity of *
>  :- promise all [A,B,C] ( C = B * A <=> C = A * B ).
> +:- promise all [A,B,C,ABC] ( ABC = (A * B) * C <=> ABC = A * (B * C) ).

Is there some reason why they can't be written as just

	:- promise all [A,B,C] ( A * B = B * A ).
	:- promise all [A,B,C] ( (A * B) * C = A * (B * C) ).
	
?

If so, I think it would be a good idea to document that reason.

> Index: library/list.m
...
> +	% construction equivalence law.
> +	% XXX when we implement rewrite rules change this law to a
> +	% rewrite rule.
> +:- promise all [L,H,T] ( append([H], T, L) <=> L = [H|T] ).

I think it would be a good idea to document why this rule is
worth declaring.

> Index: compiler/accumulator.m
...
> % Attempts to transform a single proc to a tail recursive form by
> % introducing accumlators.  The algorithm can do this if the code after
> % the recursive call has either the state update or associative
> % property.
> %
> % /* State update property */
> % :- promise all [A,B,S0,S]
> % 	(
> % 		(some[SA] (update(A, S0, SA), update(B, SA, S)))
> % 	<=>
> % 		(some[SB] (update(B, S0, SB), update(A, SB, S)))
> % 	).	

Hmm, that name is not a great name for that property.
There are many predicates which I would think of as
"state update predicates", for example `io__set_exit_status',
which do not have that property.

Perhaps "Commutative state update property" would be a better name.
It's not commutativity, but it is a bit like commutativity,
as the following alternative way of expressing it shows:

    :- promise all [A, B]
	((pred) --> update(A), update(B)) = ((pred) --> update(B), update(A)).

Note that currently this is not legal Mercury syntax,
because we require mode and determinism annotations on lambda expressions.
This is necessary in goals, but it is not necessary in
`:- promise' declarations (which do not need to be mode-correct),
so it might be nice to relax that restriction so that
it only applies to goals that need to be mode-correct.
(As a side effect, this change would help the compiler
give better error messages in the case where you forget
these annotations.)

Currently you would have to insert some dummy modes, e.g.

    :- promise all [A, B]
	(pred(in, in) is semidet --> update(A), update(B)) =
	(pred(in, in) is semidet --> update(B), update(A)).

> % The transformation recognises predicates in the form
> %
> % p(In, OutUpdate, OutAssoc) :-
> % 	minimal(In),
> % 	initialise(OutUpdate),
> %	base(OutAssoc).
> % p(In, OutUpdate, OutAssoc) :-
> % 	decompose(In, Current, Rest),
> % 	p(Rest, OutUpdate0, OutAssoc0),
> % 	update(Current, OutUpdate0, OutUpdate),
> % 	assoc(Current, OutAssoc0, OutAssoc).
> %
> % which can be transformed by the algorithm in "State Update
> % Transformation" to
> %
> % p(In, OutUpdate, OutAssoc) :-
> % 	initialise(AccUpdate),
> % 	p_acc(In, OutUpdate, OutAssoc, AccUpdate).
> %
> % p_acc(In, OutUpdate, OutAssoc, AccUpdate) :-
> % 	minimal(In),
> % 	base(OutAssoc),
> % 	OutUpdate = AccUpdate.
> % p_acc(In, OutUpdate, OutAssoc, AccUpdate0) :-
> % 	decompose(In, Current, Rest),
> % 	update(Current, AccUpdate0, AccUpdate),
> % 	p_acc(Rest, OutUpdate, OutAssoc0, AccUpdate),
> % 	compose(Current, OutAssoc0, OutAssoc).

Shouldn't `compose' here be `assoc'?
The first code fragment contains a call to `assoc',
where the second code fragment contains a call to `compose'.

> % Note that if the recursive clause contains multiple calls to p, the
> % transformation is attempts to move each recursive call to the end

s/is attempts/attempts/

> 	% A goal is represented by two integers, the first integer
> 	% stores which conjunction the goal came from (base or
> 	% recursive), and the second stores the location of the goal in
> 	% the conjunction.
> :- type goal_id == pair(int).

How is the first int encoded?  Why use an int rather than
an enumeration type?

How is the second int encoded -- starting at zero or one?

> :- type warning 
> 			% warn that two prog_vars in call to pred_id
> 			% at prog_context were swapped, which may cause
> 			% an efficiency problem.
> 	--->	w(prog_context, pred_id, prog_var, prog_var).

I suggest s/w/warn/

> :- type warnings == list(warning).
> 
> %-----------------------------------------------------------------------------%
> 
> 	%
> 	% process_proc
> 	%
> 	% Attempt to transform one procedure into a accumulator
> 	% recursive form.

s/one/a/
s/a //

> process_proc(PredId, ProcId, ProcInfo0, ProcInfo, 
> 		ModuleInfo0, ModuleInfo) -->
...
> 		globals__io_lookup_bool_option(inhibit_accumulator_warnings,
> 				InhibitWarnings),
> 		(
> 			{ not (InhibitWarnings = no, Warnings \= []) }
> 		->

I think it would be clearer to avoid the double negation and write that
condition as `InhibitWarnings = yes ; Warnings = []'

		(	
			{
		->

> 					words("If a predicate has been"),
> 					words("declared associative via"),
> 					words("a promise declaration,"),

I suggest s/promise/`promise'/

> output_warning(w(Context, PredId, VarA, VarB), VarSet, ModuleInfo,
> 		Context, Formats) :-
> 	error_util__describe_one_pred_name(ModuleInfo, PredId, PredStr),
> 	varset__lookup_name(VarSet, VarA, VarAStr),
> 	varset__lookup_name(VarSet, VarB, VarBStr),
> 	Formats = [words("warning: the call to"), words(PredStr),
> 			words("has had the location of the variables"),
> 			words(VarAStr), words("and"), words(VarBStr),
> 			words("swapped to allow accumulator introduction.")
> 			].

The predicate name and variable names should be inside single quotes, e.g.
"`Foo'" rather than "Foo".

> 	standardise(Goal0, Goal),
> 
> 	identify_goal_type(PredId, ProcId, Goal, TopLevel, Base, Rec),
> 
> 	C = initialise_goal_store(Rec, Base, InitialInstMap),

I suggest s/standardise/standardize/g
and s/initialise/initialize/g,
for consistency with the spelling used in (most of)
the rest of the compiler.

> 	%
> 	% This predicate takes the original goal and identifies the
> 	% `shape' of the goal around the recursive and base cases.
> 	% Note that the base case can contain a recursive call, as the
> 	% transformation doesn't depend on what is in the base case.
> 	%
> :- pred identify_goal_type(pred_id::in, proc_id::in, hlds_goal::in,
> 		top_level::out, hlds_goals::out, hlds_goals::out) is semidet.
> 
> identify_goal_type(PredId, ProcId, Goal, Type, Base, Rec) :-
> 	(
> 		Goal = switch(_Var, _CanFail, Cases, _StoreMap) - _GoalInfo,
> 		Cases = [case(_IdA, GoalA), case(_IdB, GoalB)],
> 		goal_to_conj_list(GoalA, GoalAList),
> 		goal_to_conj_list(GoalB, GoalBList)
> 	->
> 		(
> 			is_recursive_case(GoalAList, proc(PredId, ProcId))
> 		->
> 			Type = switch_rec_base,
> 			Base = GoalBList,
> 			Rec = GoalAList
> 		;
> 			is_recursive_case(GoalBList, proc(PredId, ProcId))
> 		->
> 			Type = switch_base_rec,
> 			Base = GoalAList,
> 			Rec = GoalBList
> 		;
> 			fail
> 		)
> 	;
> 		fail
> 	).

Hmm... what about the other possible values for `Type',
e.g. when the goal is an if-then-else or a (semidet?) disjunction?

> :- type store_info
> 	--->	store_info(
> 			int,
> 			instmap,
> 			goal_store
> 		).

What does this type represent?
In particular, what does the `int' field represent?

[... to be continued ...]

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3        |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list