[m-rev.] first step towards functional dependencies (1/3)
Julien Fischer
juliensf at cs.mu.OZ.AU
Wed Mar 30 14:24:33 AEST 2005
On Wed, 23 Mar 2005, Mark Brown wrote:
> Estimated hours taken: 240
> Branches: main
>
> Remove the assumption made by polymorphism.m that all type variables
> appearing in class constraints also appear in the type being constrained.
> This is a first step towards adding functional dependencies, since in the
> presence of functional dependencies (or "improvement" in general) this
> assumption no longer holds.
>
> The assumption made by polymorphism manifests itself in the fact that
> constraints on atomic goals are reconstructed by unifying the types of
> formal parameters with the types of actual arguments, and then applying
> the resulting substitution to the constraints. Any type variables in
> constraints that don't appear in the formal parameters will therefore
> remain unbound.
>
> This change overcomes the assumption by building up a map from constraint
> identifiers to constraints during typechecking, and then looking up this
> map in order to reconstruct the constraint during the polymorphism
> transformation.
>
> To support this, the type 'class_constraint' has been removed and replaced
> by two distinct types, 'prog_constraint' and 'hlds_constraint'. The former
> is part of the parse tree and holds the same information as the old
> class_constraint. The latter is part of the HLDS, and is used during
> typechecking; in addition to the information in prog_constraints, it also
> stores a set of identifiers that represent where the constraint came from.
> These identifiers are used as the keys in the aforementioned map.
>
> At this stage the constraint identifiers are only used by typechecking to
> build the constraint map. Other passes use either prog_constraints or
> hlds_constraints with an empty set of identifiers.
>
> compiler/hlds_data.m:
> Define the constraint_id type, which is used to uniquely identify
> class constraints. A better scheme than this one has been suggested,
> but that will be left to a later change. An XXX comment to that
> effect has been added.
>
> Define the hlds_constraint type, which is like prog_constraint but
> it also includes a set of constraint_ids. Define a set of predicates
> to initialise and manipulate these.
>
> Define the constraint_map type here. Move the definition of
> constraint_proof_map to here, where it more sensibly belongs.
>
> Update the comments in hlds_instance_defn slightly, with information
> that I found I needed to know when making this change.
>
> compiler/hlds_pred.m:
> Add a field to the pred_info to store the constraint_map.
>
> Move the definition of constraint_proof_map from here.
>
> compiler/hlds_out.m:
> Print out a representation of the constraint map if it isn't empty.
>
> compiler/type_util.m:
> Change the predicates that used to operate on class_constraints so
> that they now operate on hlds_constraints. The old versions of these
> predicates have now moved to prog_util.
>
As we discussed in person, prog_type woud probably be the natural module
to put this in - that should be part of separate change though.
> Add some utility predicates to manipulate constraint_maps.
>
> Add a predicate to apply a variable renaming to constraint_proof_maps.
>
> compiler/prog_data.m:
> Rename class_constraint(s) to prog_constraint(s).
>
> compiler/prog_util.m:
> Provide a set of predicates for manipulating prog_constraints.
>
> compiler/typecheck.m:
> Ensure that goal_paths are filled in before the first iteration
> of typechecking.
>
> Pass the hlds_goal_info down through typecheck_goal_2 so that the
> goal_path can be retrieved when needed to assign identifiers to
> constraints. Thread the goal_path through to wherever it is needed.
>
> Store hlds_constraints in the args_type_assign rather than
> prog_constraints, so that the required information is available
> when creating the new set of type_assigns. Do likewise for the
> cons_type_info type. Don't pass the module_info through
> make_pred_cons_info*, since it isn't used. Do pass the goal_path,
> though, so that constraints in cons_type_infos can be given the
> correct identifier.
>
> Add a constraint_map field to the typecheck_info, initialised to empty.
>
> When retrieving the final information from a typecheck_info, return
> the resulting constraint_map, after applying any type bindings.
> Ensure that any constraints that may not have been entered into the
> constraint_map are put there now. Call the new predicate in type_util
> to rename the constraint_proof_map, rather than doing it longhand
> here.
>
> Make the following changes to context reduction:
>
> - Thread the constraint_map through, so that it can be updated
> as constraints are eliminated.
>
> - Instead of simply calling sort_and_remove_dups on the
> set of constraints remaining after one iteration, merge the
> constraints in such a way that the complete set of
> constraint_ids is retained.
>
> - Disregard the constraint_ids when deleting newly introduced
> constraints that are equivalent to constraints that have
> already been seen.
>
> - Simplify the code of find_matching_instance_rule_2 by
> moving the deterministic code out of the condition of the
> if-then-else.
>
> Move find_first_map into the library.
>
> compiler/polymorphism.m:
> Ensure that the goal_path is set when constructing lambda goals.
>
> In process_call, look up the constraints in the constraint_map
> using the goal_path as part of the key, rather than calculating
> the constraints by applying the ParentToActual type substitution.
> Rearrange this code so that it is divided into easier to understand
> blocks.
>
> Add a field to the poly_info to store the constraint_map, and
> initialise it from the pred_info.
>
> compiler/goal_path.m:
> Fill slots in lambda_goals, since constraints inside these will
> otherwise not be identified properly. The goal_paths inside here
> do not entirely make sense, since there is no goal_path_step for
> the lambda_goal itself. However, there is enough information
> retained to distinguish these goal_paths from any other possible
> goal_path, which is all that we require to identify constraints.
>
> Add a warning not to fill in the goal slots between the typechecking
> and polymorphism passes, since doing so could potentially render the
> constraint_maps incorrect.
>
> compiler/make_hlds.m:
> Initialise the constraint_map to empty in pred_infos.
>
> Move the code for updating the superclass_table into a separate
> predicate. Initially this change was made because, in an earlier
> version of the change, the superclass_table had some extra
> information that needed to be filled in. That part of the change
> is not needed in this diff, but the new predicate simplifies the
> code a bit so I've left it there.
>
> compiler/check_typeclass.m:
> Convert the prog_constraints into hlds_constraints before passing
> them to typecheck.reduce_context_by_rule_application. They are
> assigned no identifiers, since these constraints are not required
> to be put into the constraint map.
>
> Change the name of the function get_constraint_id to
> get_constraint_class_id, since it would now be ambiguous otherwise.
>
> compiler/cse_detection.m:
> Import parse_tree__prog_util, since that is where renamings of
> prog_constraints are now defined.
>
> compiler/higher_order.m:
> Initialise pred_infos here with an empty constraint_map.
>
> compiler/post_typecheck.m:
> When binding type vars to void, apply the void substitution to the
> constraint_map.
>
> compiler/table_gen.m:
> Pass the constraint_map when creating a new pred_info.
>
> compiler/unused_args.m:
> Create the pred_info with an empty constraint_map. The constraint_map
> won't be used by this stage anyway.
>
> compiler/*.m:
> Update to use the new type names. Also update to use the existing
> type synonyms typeclass_info_varmap and constraint_proof_map.
>
> Change names of predicates and functions to use prog_constraint
> instead of class_constraint, where applicable.
>
> library/list.m:
> Add find_first_map from typecheck. Also add find_first_map{2,3},
> since at one stage during development I needed find_first_map3, and,
> although it's not used in the current diff, there is little point
> removing it now.
>
> @@ -843,14 +845,66 @@
> % proc_ids of all the methods
> instance_tvarset :: tvarset,
> % VarNames
> - instance_proofs :: map(class_constraint,
> - constraint_proof)
> + instance_proofs :: constraint_proof_map
...
> +:- type constraint_type
> + ---> existential
> + ; universal.
> +
> + % THe identifier of a constraint is stored along with the constraint.
s/THe/The
> + % Each value of this type may have more than one identifier because
> + % if two constraints in a context are equivalent then we merge them
> + % together in order to not have to prove the same constraint twice.
> + %
> +:- type hlds_constraint
> + ---> constraint(
> + list(constraint_id),
> + class_name,
> + list(type)
> + ).
> +
> +:- type hlds_constraints
> + ---> constraints(
> + list(hlds_constraint), % Universal constraints.
> + list(hlds_constraint) % Existential constraints.
> + ).
> +
Is it worth giving field names to these things?
> + % During type checking we fill in a constraint_map which gives
> + % the constraint that corresponds to each identifier. This is used
> + % by the polymorphism translation to retrieve details of constraints.
> + %
> +:- type constraint_map == map(constraint_id, prog_constraint).
> +
> % `Proof' of why a constraint is redundant
> :- type constraint_proof
> % Apply the instance decl with the given number.
> @@ -871,9 +925,135 @@
>
> % The constraint is redundant because of the
> % following class's superclass declaration
> - ; superclass(class_constraint).
> + ; superclass(prog_constraint).
> +
> +:- type constraint_proof_map == map(prog_constraint, constraint_proof).
> +
> +:- pred init_hlds_constraint_list(list(prog_constraint)::in,
> + list(hlds_constraint)::out) is det.
> +
> +:- pred make_hlds_constraints(prog_constraints::in, goal_path::in,
> + hlds_constraints::out) is det.
> +
> +:- pred make_hlds_constraint_list(list(prog_constraint)::in,
> + constraint_type::in, goal_path::in, list(hlds_constraint)::out) is det.
> +
> +:- pred retrieve_prog_constraints(hlds_constraints::in, prog_constraints::out)
> + is det.
> +
> +:- pred retrieve_prog_constraint_list(list(hlds_constraint)::in,
> + list(prog_constraint)::out) is det.
> +
> +:- pred retrieve_prog_constraint(hlds_constraint::in, prog_constraint::out)
> + is det.
> +
> +:- pred matching_constraints(hlds_constraint::in, hlds_constraint::in)
> + is semidet.
> +
> +:- pred compare_hlds_constraints(hlds_constraint::in, hlds_constraint::in,
> + comparison_result::out) is det.
> +
> +:- pred update_constraint_map(hlds_constraint::in, constraint_map::in,
> + constraint_map::out) is det.
> +
> +:- pred lookup_hlds_constraint_list(constraint_map::in, constraint_type::in,
> + goal_path::in, int::in, list(prog_constraint)::out) is det.
> +
> +:- implementation.
> +
It would be worth adding a dashed line there just to make the separation
from interface to implementation more obvious.
> Index: compiler/hlds_pred.m
> ===================================================================
> RCS file: /home/mercury1/repository/mercury/compiler/hlds_pred.m,v
> retrieving revision 1.159
> diff -u -r1.159 hlds_pred.m
> --- compiler/hlds_pred.m 22 Mar 2005 06:40:00 -0000 1.159
> +++ compiler/hlds_pred.m 22 Mar 2005 12:23:48 -0000
> @@ -575,12 +575,6 @@
> % module, name and arity.
> :- type aditi_owner == string.
>
> - % The constraint_proof_map is a map which for each type class
> - % constraint records how/why that constraint was satisfied.
> - % This information is used to determine how to construct the
> - % typeclass_info for that constraint.
> -:- type constraint_proof_map == map(class_constraint, constraint_proof).
> -
> % Describes the class constraints on an instance method implementation.
> % This information is used by polymorphism.m to ensure that the
> % type_info and typeclass_info arguments are added in the order in
> @@ -590,9 +584,9 @@
> class_id,
> list(type), % The types in the head of the
> % instance declaration.
> - list(class_constraint), % The universal constraints
> + list(prog_constraint), % The universal constraints
> % on the instance declaration.
> - class_constraints % The contraints on the method's
> + prog_constraints % The contraints on the method's
> % type declaration in the
> % `:- typeclass' declaration.
> ).
...
> Index: compiler/lambda.m
> ===================================================================
> RCS file: /home/mercury1/repository/mercury/compiler/lambda.m,v
> retrieving revision 1.96
> diff -u -r1.96 lambda.m
> --- compiler/lambda.m 22 Mar 2005 06:40:02 -0000 1.96
> +++ compiler/lambda.m 22 Mar 2005 12:23:48 -0000
> @@ -118,14 +118,13 @@
> lambda_info(
> prog_varset, % from the proc_info
> map(prog_var, type), % from the proc_info
> - class_constraints, % from the pred_info
> + prog_constraints, % from the pred_info
> tvarset, % from the proc_info
> inst_varset, % from the proc_info
> map(tvar, type_info_locn),
> % from the proc_info
> % (typeinfos)
> - map(class_constraint, prog_var),
> - % from the proc_info
> + typeclass_info_varmap, % from the proc_info
> % (typeclass_infos)
> pred_markers, % from the pred_info
> pred_or_func,
> @@ -597,7 +596,7 @@
> InstVarSet, TVarMap, TCVarMap, Markers, POF, OrigPredName,
> Owner, ModuleInfo, MustRecomputeNonLocals).
>
> -:- pred lambda__constraint_contains_vars(list(tvar)::in, class_constraint::in)
> +:- pred lambda__constraint_contains_vars(list(tvar)::in, prog_constraint::in)
> is semidet.
>
> lambda__constraint_contains_vars(LambdaVars, ClassConstraint) :-
...
> OldConstraints = Constraints.
>
> @@ -3524,6 +3517,26 @@
> )
> ).
>
> + % insert an entry into the super class table
> + % for each super class of this class
Make that into a proper sentence.
> +:- pred update_superclass_table(class_id::in, list(tvar)::in, tvarset::in,
> + list(prog_constraint)::in, superclass_table::in, superclass_table::out)
> + is det.
> +
> +update_superclass_table(ClassId, Vars, VarSet, Constraints, !Supers) :-
> + list.foldl(update_superclass_table_2(ClassId, Vars, VarSet), Constraints,
> + !Supers).
> +
> +:- pred update_superclass_table_2(class_id::in, list(tvar)::in, tvarset::in,
> + prog_constraint::in, superclass_table::in, superclass_table::out) is det.
> +
> +update_superclass_table_2(ClassId, Vars, VarSet, Constraint, !Supers) :-
> + Constraint = constraint(SuperName, SuperTypes),
> + list__length(SuperTypes, SuperClassArity),
> + SuperClassId = class_id(SuperName, SuperClassArity),
> + SubClassDetails = subclass_details(SuperTypes, ClassId, Vars, VarSet),
> + multi_map__set(!.Supers, SuperClassId, SubClassDetails, !:Supers).
You may want to use the svmulti_map version of set there.
To be continued ...
Julien.
--------------------------------------------------------------------------
mercury-reviews mailing list
post: mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the reviews
mailing list