[m-dev.] diff: typeclasses

Fergus Henderson fjh at cs.mu.oz.au
Sun Dec 7 21:22:01 AEDT 1997


On 21-Nov-1997, David Glen JEFFERY <dgj at cs.mu.oz.au> wrote:

> Index: compiler/polymorphism.m
...
> +% Tranformation of code using typeclasses:
> +%
> +% Every predicate which has a typeclass constraint is given an extra
> +% argument for every constraint in the predicate's type declaration.
> +% The argument is the "dictionary", or "typeclass_info" for the typeclass.
> +% The dictionary contains pointers to each of the class methods

Missing full stop.

> +% Representation of a typeclass_info:
> +%	The typeclass_info is represented in two parts (the typeclass_info
> +%	itself, and a base_typeclass_info), in a similar fashion to the
> +%	type_info being represented in two parts (the type_info and the
> +%	base_type_info).
> +%
> +%		The base_type_info contains:

s/base_type_info/base_typeclass_info/

> +%		  * arity of the instance declaration (ie. the number of
> +%		    constraints on the decl).

It's not really the "arity" of the instance declaration.
Consider e.g.
	:- instance  foo(list(T)) <= foo(T), bar(T) where [...].
The arity of the base_type_info, perhaps.

> +%		  * pointer to method #1
> +%		    ...
> +%		  * pointer to method #n
> +%
> +%		The type_info contains:

s/type_info/typeclass_info/

> +%		  * a pointer to the base typeclass info
> +%		  * typeclass info #1 for constraint on instance decl
> +%		  * ...
> +%		  * typeclass info #n for constraint on instance decl
> +%		  * typeclass info for superclass #1
> +%		    ...
> +%		  * typeclass info for superclass #n
> +%		  * type info #1 
> +%		  * ...
> +%		  * type info #n

How do you know how many superclasses or type infos a typeclass_info has?

> +% The base_type_info is produced statically, and there is one for each instance
> +% declaration. For each constraint on the instance declaration, the
> +% corresponding typeclass info is stored in the second part.
> +%
> +% eg. for the following program:
> +%
> +%	:- typeclass foo(T) where [...].
> +%	:- instance  foo(int) where [...].
> +%	:- instance  foo(list(T)) <= foo(T) where [...].

It would be helpful to give an example such as

	:- instance  foo(list(T)) <= foo(T), bar(T) where [...].

Also, are instance declarations such as

	:- instance  foo(list(T)) <= foo(T), bar(array(T)) where [...].

permitted?

> +%	The typeclass_info for foo(int) is:
> +%		The base_type_info:
> +%		  * 0 (arity of the instance declaration) 
> +%		  * pointer to method #1
> +%		    ...
> +%		  * pointer to method #n
> +%
> +%		The type_info:
> +%		  * a pointer to the base typeclass info
> +%		  * type info for int
> +%
> +%	The typeclass_info for foo(list(T)) is:
> +%		The base_type_info:
> +%		  * 1 (arity of the instance declaration)
> +%		  * pointer to method #1
> +%		    ...
> +%		  * pointer to method #n
> +%
> +%		The type_info contains:
> +%		  * a pointer to the base typeclass info
> +%		  * typeclass info for foo(T)
> +%		  * type info for list(T)

Shouldn't that be the type info for `T', not for `list(T)'?

> +% Where the "T" for the list is known, the whole typeclass_info will be static
> +% data. When we do not know until runtime, the typeclass_info is constructed
> +% dynamically.

It think it might be clearer if you said "If ..." instead of "Where ...".

> @@ -166,10 +287,10 @@
>  :- import_module hlds_pred, hlds_goal, hlds_data, llds, (lambda), globals.
>  :- import_module prog_data, type_util, mode_util, quantification, instmap.
>  :- import_module code_util, unify_proc, special_pred, prog_util, make_hlds.
> -:- import_module (inst), hlds_out.
> +:- import_module std_util, (inst), hlds_out, base_typeclass_info.
>  
>  :- import_module bool, int, string, list, set, map.
> -:- import_module term, varset, std_util, require.
> +:- import_module term, varset, std_util, require, assoc_list.

Please keep the compiler and standard library modules separate --
`std_util' should be in the second group.

> +					% If the typeinfo is in a
> +					% typeclass_info, first extract it, 
> +					% then use it
> +				{ TypeInfoLocn =
> +					typeclass_info(TypeClassInfoVar,
> +					Index) },
> +				extract_type_info(Type, TypeVar,
> +					TypeClassInfoVar, Index,
> +					Goals, TypeInfoVar),
> +
> +				{ ArgVars = [TypeInfoVar, XVar, YVar] },
> +				{ Call = call(PredId, ProcId, ArgVars,
> +					BuiltinState, yes(CallContext), SymName)
> +					- GoalInfo },

The non-locals field for the GoalInfo on the call here is wrong.

> +					% The TypeClassInfoVar is also nonlocal
> +					% to this conj, since it is used to
> +					% extract the type_info
> +					%
> +					% XXX Do I need to do this?
> +				{ goal_info_get_nonlocals(GoalInfo, 
> +					NonLocals0) },
> +				{ set__insert(NonLocals0, TypeClassInfoVar,
> +					NonLocals) },
> +				{ goal_info_set_nonlocals(GoalInfo, NonLocals,
> +					NewGoalInfo) },
> +				{ Goal = conj([Call|Goals]) - NewGoalInfo }

I think you've got it backwards here.  The TypeClassInfoVar is not local
to the call, but it *is* local to the conjunction.

>  polymorphism__fixup_quantification(Goal0, Goal, Info0, Info) :-
>  	Info0 = poly_info(VarSet0, VarTypes0, TypeVarSet, TypeVarMap,
> -			PredName, ModuleInfo),
> +			TypeClassVarMap, Proofs, PredName, ModuleInfo),
>  	( map__is_empty(TypeVarMap) ->
>  		Info = Info0,
>  		Goal = Goal0
>  	;
>  		%
> -		% A type-info variable may be non-local to a goal if any of
> +		% A type-info variable may be non-local to a goal if any of 
>  		% the ordinary non-local variables for that goal are
>  		% polymorphically typed with a type that depends on that
>  		% type-info variable.
>  		%
> +		% In addition, a typeclass-info is non-local to a goal if any 
> +		% of the non-local variables for that goal are polymorphically
> +		% typed and are constrained by the typeclass constraints for
> +		% that typeclass-info variable

s/is/may be/

> +		solutions_set(lambda([Var::out] is nondet, (
> +				list__member(TheVar, NonLocalTypeVars),
> +				map__search(TypeVarMap, TheVar, Location),
> +				(
> +					Location = type_info(Var)
> +				;
> +					Location = typeclass_info(Var, _)
> +				)

The above 5 lines of code should be put in a subroutine.

>  polymorphism__process_lambda(PredOrFunc, Vars, Modes, Det, OrigNonLocals,
>  		LambdaGoal, Unification0, Functor, Unification,
>  		PolyInfo0, PolyInfo) :-
> -	PolyInfo0 = poly_info(VarSet, VarTypes, TVarSet, TVarMap, PredName,
> -			ModuleInfo0),
> +	PolyInfo0 = poly_info(VarSet, VarTypes, TVarSet, TVarMap, 
> +			TCVarMap, Proofs, PredName, ModuleInfo0),
> +
> +		% XXX This is wrong. What is the class context really?
> +	Constraints = [],

This should be fixed.

I think you can compute the Constraints (class context) for the lambda goal
by taking the Constraints for the containing predicate and restricting
them to the variables that occur in the lambda goal.

> +				% We extract the superclass typeclass_info by
> +				% inserting a call to
> +				% superclass_from_typeclass_info in
> +				% mercury_builtin.

Hmm, is that an efficient way of doing things?

> +polymorphism__get_arg_superclass_vars

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.



More information about the developers mailing list