for review: abstract instance declarations
Fergus Henderson
fjh at cs.mu.OZ.AU
Tue Feb 9 20:52:13 AEDT 1999
Estimated hours taken: 9
Implement abstract instance declarations.
compiler/prog_data.m:
Rename the `instance_interface' type as `instance_body',
and make it a discriminated union: either `abstract',
or `concrete(Methods)'.
compiler/prog_io_typeclass.m:
compiler/hlds_data.m:
compiler/hlds_out.m:
compiler/equiv_type.m:
compiler/check_typeclass.m:
Change the code to reflect the new name and representation
of `instance_interface'.
compiler/prog_io_typeclass.m:
Parse abstract instance declarations.
compiler/make_hlds.m:
Clean up the code a bit, and make sure that it detects some errors
which previously we didn't detect: duplicate or overlapping
instance declarations, and instance declarations with methods for
classes with no methods.
compiler/check_typeclass.m:
If an instance is abstract, then we don't need to check
that the methods in the instance body match those in the class.
compiler/base_typeclass_info.m:
Only generate base_typeclass_infos for concrete instance
declarations, not for abstract ones.
doc/reference_manual.texi:
Document the change.
tests/hard_coded/typeclasses/Mmakefile:
tests/hard_coded/typeclasses/abstract_instance.m:
tests/hard_coded/typeclasses/use_abstract_instance.m:
tests/hard_coded/typeclasses/use_abstract_instance.exp:
tests/invalid/Mmakefile:
tests/invalid/typeclass_test_9.m:
tests/invalid/typeclass_test_9.err_exp:
Some test cases.
tests/hard_coded/typeclasses/Mmakefile:
Uncomment typeclass_test_5.m, since we pass that now
(and have done so for quite some time).
Index: compiler/base_typeclass_info.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/base_typeclass_info.m,v
retrieving revision 1.10
diff -u -b -r1.10 base_typeclass_info.m
--- base_typeclass_info.m 1999/02/04 14:58:08 1.10
+++ base_typeclass_info.m 1999/02/09 04:03:00
@@ -75,9 +75,10 @@
base_typeclass_info__gen_infos_for_instance_list(ClassId - Is,
ModuleName, ModuleInfo, CModules1),
InstanceDefn = hlds_instance_defn(ImportStatus, _TermContext,
- InstanceConstraints, InstanceTypes, _Interface,
+ InstanceConstraints, InstanceTypes, Body,
PredProcIds, _Varset, _SuperClassProofs),
(
+ Body = concrete(_),
% Only make the base_typeclass_info if the instance
% declaration originally came from _this_ module.
status_defined_in_this_module(ImportStatus, yes)
@@ -108,8 +109,8 @@
Status, Rvals, Procs),
CModules = [CModule | CModules1]
;
- % The instance decl is from another module, so
- % we don't bother including it.
+ % The instance decl is from another module,
+ % or is abstract, so we don't bother including it.
CModules = CModules1
).
Index: compiler/check_typeclass.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/check_typeclass.m,v
retrieving revision 1.20
diff -u -b -r1.20 check_typeclass.m
--- check_typeclass.m 1998/12/06 23:42:59 1.20
+++ check_typeclass.m 1999/02/09 09:45:13
@@ -133,30 +133,53 @@
check_class_instance(ClassId, SuperClasses, Vars, ClassInterface, ClassVarSet,
PredIds, InstanceDefn0, InstanceDefn,
- ModuleInfo0, ModuleInfo):-
+ Errors0 - ModuleInfo0, Errors - ModuleInfo):-
- % check conformance of the instance interface
+ % check conformance of the instance body
+ InstanceDefn0 = hlds_instance_defn(_, _, _, _, InstanceBody, _, _, _),
(
- PredIds \= []
- ->
+ InstanceBody = abstract,
+ InstanceDefn1 = InstanceDefn0,
+ ModuleInfo1 = ModuleInfo0,
+ Errors2 = Errors0
+ ;
+ InstanceBody = concrete(Methods),
list__foldl2(
check_instance_pred(ClassId, Vars, ClassInterface),
PredIds, InstanceDefn0, InstanceDefn1,
- ModuleInfo0, ModuleInfo1)
+ Errors0 - ModuleInfo0, Errors1 - ModuleInfo1),
+ %
+ % Check if there are any instance methods left over,
+ % for which we did not produce a pred_id/proc_id;
+ % if there are any, the instance declaration must have
+ % specified some methods that don't occur in the class.
+ %
+ InstanceDefn1 = hlds_instance_defn(_, Context, _, _,
+ _, MaybePredProcs, _, _),
+ (
+ MaybePredProcs = yes(PredProcs),
+ list__same_length(PredProcs, Methods)
+ ->
+ Errors2 = Errors1
;
- % there are no methods for this class
- InstanceDefn0 = hlds_instance_defn(A, B, C, D, E,
- _MaybeInstancePredProcs, G, H),
- InstanceDefn1 = hlds_instance_defn(A, B, C, D, E,
- yes([]), G, H),
- ModuleInfo1 = ModuleInfo0
+ ClassId = class_id(ClassName, ClassArity),
+ prog_out__sym_name_to_string(ClassName,
+ ClassNameString),
+ string__int_to_string(ClassArity, ClassArityString),
+ string__append_list([
+ "In instance declaration for `",
+ ClassNameString, "/", ClassArityString, "': ",
+ "incorrect method name(s)."],
+ NewError),
+ Errors2 = [Context - [words(NewError)] | Errors1]
+ )
),
-
% check that the superclass constraints are satisfied for the
% types in this instance declaration
check_superclass_conformance(ClassId, SuperClasses, Vars, ClassVarSet,
- InstanceDefn1, InstanceDefn, ModuleInfo1, ModuleInfo).
+ InstanceDefn1, InstanceDefn,
+ Errors2 - ModuleInfo1, Errors - ModuleInfo).
%----------------------------------------------------------------------------%
@@ -268,12 +291,12 @@
InstanceDefn, Info0, Info) :-
InstanceDefn0 = hlds_instance_defn(A, InstanceContext,
InstanceConstraints, InstanceTypes,
- InstanceInterface, MaybeInstancePredProcs,
+ InstanceBody, MaybeInstancePredProcs,
InstanceVarSet, H),
Info0 = instance_method_info(ModuleInfo, PredName, PredArity,
ExistQVars, ArgTypes, ClassContext, ArgModes, Errors0,
ArgTypeVars, Status, PredOrFunc),
- get_matching_instance_names(InstanceInterface, PredOrFunc, MethodName,
+ get_matching_instance_names(InstanceBody, PredOrFunc, MethodName,
PredArity, InstanceNames),
(
InstanceNames = [InstancePredName - Context]
@@ -300,7 +323,7 @@
InstancePredProcs = InstancePredProcs1
),
InstanceDefn = hlds_instance_defn(A, Context,
- InstanceConstraints, InstanceTypes, InstanceInterface,
+ InstanceConstraints, InstanceTypes, InstanceBody,
yes(InstancePredProcs), InstanceVarSet, H)
;
InstanceNames = [I1, I2 | Is]
@@ -324,17 +347,10 @@
InstanceTypesString),
string__append_list([
"In instance declaration for `",
- ClassNameString,
- "(",
- InstanceTypesString,
- ")': ",
+ ClassNameString, "(", InstanceTypesString, ")': ",
"multiple implementations of type class ",
- PredOrFuncString,
- " method `",
- MethodNameString,
- "/",
- PredArityString,
- "'."],
+ PredOrFuncString, " method `",
+ MethodNameString, "/", PredArityString, "'."],
ErrorHeader),
I1 = _ - I1Context,
Heading =
@@ -373,17 +389,10 @@
InstanceTypesString),
string__append_list([
"In instance declaration for `",
- ClassNameString,
- "(",
- InstanceTypesString,
- ")': ",
+ ClassNameString, "(", InstanceTypesString, ")': ",
"no implementation for type class ",
- PredOrFuncString,
- " method `",
- MethodNameString,
- "/",
- PredArityString,
- "'."],
+ PredOrFuncString, " method `",
+ MethodNameString, "/", PredArityString, "'."],
NewError),
Errors = [InstanceContext - [words(NewError)] | Errors0],
Info = instance_method_info(ModuleInfo, PredName, PredArity,
@@ -391,18 +400,20 @@
ArgTypeVars, Status, PredOrFunc)
).
-:- pred get_matching_instance_names(list(instance_method), pred_or_func,
+:- pred get_matching_instance_names(instance_body, pred_or_func,
sym_name, arity, list(pair(sym_name, prog_context))).
:- mode get_matching_instance_names(in, in, in, in, out) is det.
-get_matching_instance_names(InstanceInterface, PredOrFunc, PredName,
+get_matching_instance_names(InstanceBody, PredOrFunc, PredName,
PredArity, InstanceNames) :-
(
PredOrFunc = predicate,
solutions(
lambda([Pair::out] is nondet,
(
- list__member(Method, InstanceInterface),
+ InstanceBody =
+ concrete(InstanceMethods),
+ list__member(Method, InstanceMethods),
Method = pred_instance(PredName,
SymName, PredArity,
Context),
@@ -415,7 +426,9 @@
solutions(
lambda([Pair::out] is nondet,
(
- list__member(Method, InstanceInterface),
+ InstanceBody =
+ concrete(InstanceMethods),
+ list__member(Method, InstanceMethods),
Method = func_instance(PredName,
SymName, FuncArity,
Context),
@@ -584,14 +597,10 @@
InstanceString),
string__append_list(
["Introduced_pred_for_",
- ClassNameString,
- "__",
- InstanceString,
- "____",
- MethodNameString,
- "_",
- PredArityString
- ],
+ ClassNameString, "__",
+ InstanceString, "____",
+ MethodNameString, "_",
+ PredArityString],
PredNameString),
PredName = unqualified(PredNameString).
@@ -657,13 +666,9 @@
ConstraintsString),
string__append_list([
"In instance declaration for `",
- ClassNameString,
- "(",
- InstanceTypesString,
- ")': ",
+ ClassNameString, "(", InstanceTypesString, ")': ",
"superclass constraint(s) not satisfied: ",
- ConstraintsString,
- "."],
+ ConstraintsString, "."],
NewError),
Errors = [Context - [words(NewError)] | Errors0],
InstanceDefn = InstanceDefn0
Index: compiler/equiv_type.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/equiv_type.m,v
retrieving revision 1.17
diff -u -b -r1.17 equiv_type.m
--- equiv_type.m 1998/11/20 04:07:32 1.17
+++ equiv_type.m 1999/02/09 02:53:35
@@ -155,10 +155,10 @@
equiv_type__replace_in_item(
instance(Constraints0, ClassName, Ts0,
- InstanceInterface, VarSet0),
+ InstanceBody, VarSet0),
EqvMap,
instance(Constraints, ClassName, Ts,
- InstanceInterface, VarSet),
+ InstanceBody, VarSet),
no) :-
equiv_type__replace_in_class_constraint_list(Constraints0, VarSet0,
EqvMap, Constraints, VarSet1),
Index: compiler/hlds_data.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_data.m,v
retrieving revision 1.30
diff -u -b -r1.30 hlds_data.m
--- hlds_data.m 1998/11/24 03:57:03 1.30
+++ hlds_data.m 1999/02/09 05:42:16
@@ -753,7 +753,7 @@
prog_context, % context of declaration
list(class_constraint), % Constraints
list(type), % ClassTypes
- instance_interface, % Methods
+ instance_body, % Methods
maybe(hlds_class_interface),
% After check_typeclass, we
% will know the pred_ids and
Index: compiler/hlds_out.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/hlds_out.m,v
retrieving revision 1.212
diff -u -b -r1.212 hlds_out.m
--- hlds_out.m 1998/12/06 23:43:18 1.212
+++ hlds_out.m 1999/02/09 06:59:21
@@ -2249,8 +2249,8 @@
hlds_out__write_instance_defn(Indent, InstanceDefn) -->
{ InstanceDefn = hlds_instance_defn(_, Context,
- Constraints, Types, Interface,
- _MaybeClassInterface, VarSet, Proofs) },
+ Constraints, Types, Body,
+ MaybePredProcIds, VarSet, Proofs) },
{ term__context_file(Context, FileName) },
{ term__context_line(Context, LineNumber) },
@@ -2280,9 +2280,22 @@
io__nl,
hlds_out__write_indent(Indent),
+ ( { Body = abstract },
+ io__write_string("% abstract")
+ ; { Body = concrete(Methods) },
io__write_string("% Instance Methods: "),
- mercury_output_instance_methods(Interface),
+ mercury_output_instance_methods(Methods)
+ ),
io__nl,
+
+ ( { MaybePredProcIds = yes(PredProcIds) } ->
+ hlds_out__write_indent(Indent),
+ io__write_string("% procedures: "),
+ io__write(PredProcIds),
+ io__nl
+ ;
+ []
+ ),
hlds_out__write_constraint_proofs(Indent, VarSet, Proofs),
io__nl.
Index: compiler/make_hlds.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/make_hlds.m,v
retrieving revision 1.281
diff -u -b -r1.281 make_hlds.m
--- make_hlds.m 1999/02/08 22:42:45 1.281
+++ make_hlds.m 1999/02/09 06:42:00
@@ -508,11 +508,16 @@
add_item_decl_pass_2(nothing, _, Status, Module, Status, Module) --> [].
add_item_decl_pass_2(typeclass(_, _, _, _, _)
, _, Status, Module, Status, Module) --> [].
-add_item_decl_pass_2(instance(Constraints, Name, Types, Interface, VarSet),
+add_item_decl_pass_2(instance(Constraints, Name, Types, Body, VarSet),
Context, Status, Module0, Status, Module) -->
{ Status = item_status(ImportStatus, _) },
- module_add_instance_defn(Module0, Constraints, Name, Types, Interface,
- VarSet, ImportStatus, Context, Module).
+ { Body = abstract ->
+ make_status_abstract(ImportStatus, BodyStatus)
+ ;
+ BodyStatus = ImportStatus
+ },
+ module_add_instance_defn(Module0, Constraints, Name, Types, Body,
+ VarSet, BodyStatus, Context, Module).
%------------------------------------------------------------------------------
@@ -1191,13 +1196,7 @@
{ convert_type_defn(TypeDefn, Globals, Name, Args, Body) },
{ list__length(Args, Arity) },
{ Body = abstract_type ->
- ( Status0 = exported ->
- Status1 = abstract_exported
- ; Status0 = imported ->
- Status1 = abstract_imported
- ;
- Status1 = Status0
- )
+ make_status_abstract(Status0, Status1)
;
Status1 = Status0
},
@@ -1330,6 +1329,18 @@
)
).
+:- pred make_status_abstract(import_status, import_status).
+:- mode make_status_abstract(in, out) is det.
+
+make_status_abstract(Status, AbstractStatus) :-
+ ( Status = exported ->
+ AbstractStatus = abstract_exported
+ ; Status = imported ->
+ AbstractStatus = abstract_imported
+ ;
+ AbstractStatus = Status
+ ).
+
:- pred combine_status(import_status, import_status, import_status).
:- mode combine_status(in, in, out) is det.
@@ -1764,40 +1775,72 @@
Module1, Module).
:- pred module_add_instance_defn(module_info, list(class_constraint), sym_name,
- list(type), instance_interface, tvarset, import_status, prog_context,
+ list(type), instance_body, tvarset, import_status, prog_context,
module_info, io__state, io__state).
:- mode module_add_instance_defn(in, in, in, in, in, in, in, in, out,
di, uo) is det.
-module_add_instance_defn(Module0, Constraints, Name, Types, Interface, VarSet,
+module_add_instance_defn(Module0, Constraints, ClassName, Types, Body, VarSet,
Status, Context, Module) -->
{ module_info_classes(Module0, Classes) },
{ module_info_instances(Module0, Instances0) },
{ list__length(Types, ClassArity) },
- { Key = class_id(Name, ClassArity) },
+ { ClassId = class_id(ClassName, ClassArity) },
(
- { map__search(Classes, Key, _) }
+ { map__search(Classes, ClassId, _) }
->
{ map__init(Empty) },
- { NewValue = hlds_instance_defn(Status, Context, Constraints,
- Types, Interface, no, VarSet, Empty) },
- { map__lookup(Instances0, Key, Values) },
- { map__det_update(Instances0, Key, [NewValue|Values],
+ { NewValue = hlds_instance_defn(Status, Context,
+ Constraints, Types, Body, no, VarSet, Empty) },
+ { map__lookup(Instances0, ClassId, Values) },
+ check_for_overlapping_instances(NewValue, Values, ClassId),
+ { map__det_update(Instances0, ClassId, [NewValue|Values],
Instances) },
- { module_info_set_instances(Module0, Instances, Module) }
+ { module_info_set_instances(Module0, Instances,
+ Module) }
;
- io__stderr_stream(StdErr),
- io__set_output_stream(StdErr, OldStream),
- prog_out__write_context(Context),
- io__write_string("Error: typeclass `"),
- prog_out__write_sym_name(Name),
- io__write_char('/'),
- io__write_int(ClassArity),
- io__write_string("' not defined.\n"),
- io__set_exit_status(1),
- io__set_output_stream(OldStream, _),
+ undefined_type_class_error(ClassName, ClassArity, Context,
+ "instance declaration"),
{ Module = Module0 }
).
+
+:- pred check_for_overlapping_instances(hlds_instance_defn,
+ list(hlds_instance_defn), class_id, io__state, io__state).
+:- mode check_for_overlapping_instances(in, in, in, di, uo) is det.
+
+check_for_overlapping_instances(NewValue, Values, ClassId) -->
+ { IsOverlapping = lambda([(Context - OtherContext)::out] is nondet, (
+ NewValue = hlds_instance_defn(_Status, Context,
+ _, Types, Body, _, VarSet, _),
+ Body \= abstract, % XXX
+ list__member(OtherValue, Values),
+ OtherValue = hlds_instance_defn(_OtherStatus, OtherContext,
+ _, OtherTypes, OtherBody, _, OtherVarSet, _),
+ OtherBody \= abstract, % XXX
+ varset__merge(VarSet, OtherVarSet, OtherTypes,
+ _NewVarSet, NewOtherTypes),
+ type_list_subsumes(Types, NewOtherTypes, _)
+ )) },
+ aggregate(IsOverlapping,
+ report_overlapping_instance_declaration(ClassId)).
+
+:- pred report_overlapping_instance_declaration(class_id, pair(prog_context),
+ io__state, io__state).
+:- mode report_overlapping_instance_declaration(in, in, di, uo) is det.
+
+report_overlapping_instance_declaration(class_id(ClassName, ClassArity),
+ Context - OtherContext) -->
+ io__set_exit_status(1),
+ prog_out__write_context(Context),
+ io__write_string("Error: multiply defined (or overlapping) instance\n"),
+ prog_out__write_context(Context),
+ io__write_string("declarations for class `"),
+ prog_out__write_sym_name(ClassName),
+ io__write_string("/"),
+ io__write_int(ClassArity),
+ io__write_string("'.\n"),
+ prog_out__write_context(OtherContext),
+ io__write_string("Previous instance declaration was here.\n").
%-----------------------------------------------------------------------------%
Index: compiler/prog_data.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/prog_data.m,v
retrieving revision 1.43
diff -u -b -r1.43 prog_data.m
--- prog_data.m 1998/12/06 23:44:32 1.43
+++ prog_data.m 1999/02/09 03:01:10
@@ -85,7 +85,7 @@
% ClassMethods, VarNames
; instance(list(class_constraint), class_name, list(type),
- instance_interface, tvarset)
+ instance_body, tvarset)
% DerivingClass, ClassName, Types,
% MethodInstances, VarNames
@@ -341,7 +341,11 @@
% Line number of declaration
.
-:- type instance_interface == list(instance_method).
+:- type instance_body
+ ---> abstract
+ ; concrete(instance_methods).
+
+:- type instance_methods == list(instance_method).
% an abstract type for representing a set of
% `pragma_c_code_attribute's.
Index: compiler/prog_io_typeclass.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/prog_io_typeclass.m,v
retrieving revision 1.10
diff -u -b -r1.10 prog_io_typeclass.m
--- prog_io_typeclass.m 1998/11/20 04:09:01 1.10
+++ prog_io_typeclass.m 1999/02/09 03:02:36
@@ -354,11 +354,10 @@
->
Result = Result0
;
- Result0 = ok(instance(_, Name, Types, Interface,
- VarSet0))
+ Result0 = ok(instance(_, Name, Types, Body, VarSet0))
->
- Result = ok(instance(ConstraintList, Name, Types,
- Interface, VarSet0))
+ Result = ok(instance(ConstraintList, Name, Types, Body,
+ VarSet0))
;
% if the item we get back isn't an instance,
% something has gone wrong...
@@ -444,7 +443,7 @@
(
ErroneousTypes = [],
Result = ok(instance([], ClassName,
- TermTypes, [], TVarSet))
+ TermTypes, abstract, TVarSet))
;
% XXX We should report an error for _each_
% XXX erroneous type
@@ -476,7 +475,7 @@
NameString, Types, _, _))
->
Result = ok(instance(Constraints, NameString, Types,
- MethodList, TVarSet))
+ concrete(MethodList), TVarSet))
;
% if the item we get back isn't a typeclass,
% something has gone wrong...
Index: doc/reference_manual.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/reference_manual.texi,v
retrieving revision 1.120
diff -u -b -r1.120 reference_manual.texi
--- reference_manual.texi 1999/02/08 22:42:51 1.120
+++ reference_manual.texi 1999/02/09 09:36:35
@@ -2515,10 +2515,10 @@
Mercury provides support for abstract data types, by allowing the
definition of a type to be kept hidden, with the interface
only exporting the type name.
-The interface section may contain definitions of types, typeclasses,
-typeclass instances, data constructors, instantiation states, and
-modes, and declarations for abstract data types, functions, predicates,
-and (sub-)modules.
+The interface section may contain definitions of types,
+typeclasses, data constructors, instantiation states, and
+modes, and declarations for abstract data types, abstract typeclass
+instances, functions, predicates, and (sub-)modules.
The interface section may not contain definitions for functions or
predicates (i.e. clauses), or definitions of (sub-)modules.
@@ -2527,9 +2527,10 @@
Any entities declared in this section are local to the module
(and its sub-modules) and cannot be used by other modules.
The implementation section must contain definitions
-for all abstract data types, functions, predicates, and
-sub-modules exported by the module,
-as well as for all local types, functions, predicates, and sub-modules.
+for all abstract data types, abstract instance declarations,
+functions, predicates, and sub-modules exported by the module,
+as well as for all local types, typeclass instances, functions,
+predicates, and sub-modules.
The implementation section can be omitted if it is empty.
The module may optionally end with a @samp{:- end_module @var{ModuleName}}
@@ -2796,6 +2797,7 @@
@menu
* Typeclass declarations::
* Instance declarations::
+* Abstract instance declarations::
* Type class constraints on predicates and functions::
* Type class constraints on typeclass declarations::
* Type class constraints on instance declarations::
@@ -2804,13 +2806,18 @@
@node Typeclass declarations
@section Typeclass declarations
-A @samp{typeclass} declaration specifies a set of predicates and/or functions
-that must be defined on a type (or set of types) for it (them) to be
-considered to be a member of that type class.
+A @dfn{type class} is a name for a set of types (or a set of sequences of
+types) for which certain predicates and/or functions, called the @dfn{methods}
+of that type class, are defined.
+A @samp{typeclass} declaration defines a new type class, and
+specifies the set of predicates and/or functions
+that must be defined on a type (or sequence of types) for it (them) to be
+considered to be an instance of that type class.
-The @code{typeclass} declaration gives the name of the type class, the
+The @code{typeclass} declaration gives the name of the type class that
+it is defining, the
names of the type variables which are parameters to the type class, and the
-operations ("methods") which form the interface of the type class.
+operations (i.e. methods) which form the interface of the type class.
For example,
@@ -2829,8 +2836,8 @@
@end example
@noindent
-declares the typeclass @code{point}, which refers to points in two dimensional
-space.
+declares the typeclass @code{point}, which
+represents points in two dimensional space.
@code{pred}, @code{func} and @code{mode} declarations are the only legal
declarations inside a @code{typeclass} declaration. The number of parameters
@@ -2849,16 +2856,25 @@
@node Instance declarations
@section Instance declarations
-Once the interface of the typeclass has been declared in the @code{typeclass}
-declaration, we can use an @code{instance} declaration to specify how a
+Once the interface of the typeclass has been defined in the @code{typeclass}
+declaration, we can use an @code{instance} declaration to define how a
particular type satisfies the interface declared in the @code{typeclass}
declaration.
+An instance declaration has the form
+
+ at example
+:- instance @var{classname}(@var{typename}(@var{typevar}, @dots{}), @dots{})
+ where [pred(@var{methodname}/@var{arity}) is @var{predname},
+ func(@var{methodname}/@var{arity}) is @var{funcname},
+ @dots{}].
+ at end example
+
An @samp{instance} declaration gives a type for each parameter of the
typeclass. Each of these types must be either a type with no arguments, or
-a polymorphic type whose arguments are all distinct type variables. e.g.
- at code{int}, @code{list(T)} and @code{bintree(K,V)} are allowed but
- at code{T}, @code{list(int)} and @code{bintree(T,T)} are not.
+a polymorphic type whose arguments are all distinct type variables.
+For example @code{int}, @code{list(T)} and @code{bintree(K,V)} are allowed,
+but @code{T}, @code{list(int)} and @code{bintree(T,T)} are not.
The types in an instance declaration must not be abstract types which
are elsewhere defined as equivalence types.
A program may not contain more than one @code{instance} declaration for a
@@ -2867,7 +2883,28 @@
declarations, ie. there is at most one instance declaration that may be
applied to any type (or set of types).
-For example:
+Each entry in the @samp{where [@dots{}]} part of an @code{instance}
+declaration specifies a binding for one of the methods of the class.
+The @var{predname} or @var{funcname} must name a function or
+predicate of the specified arity whose type, modes, determinism, and
+purity are at least as permissive as the declared type, modes,
+determinism, and purity of the class method with the specified
+ at var{methodname} and @var{arity}, after the types of the arguments
+in the instance declaration have substituted in place of the
+parameters in the typeclass declaration.
+Each @samp{instance} declaration
+must specify a binding for every method declared in the corresponding
+ at samp{class} declaration.
+
+Any call to a method must have arguments types (and in the case of functions,
+return type) which are constrained to be a member of that method's
+typeclass, or which match one of the instance declarations visible at
+the point of the call. A method call will invoke the
+predicate or function specified for that method in the
+instance declaration that matches the types of the arguments
+to the call.
+
+Here's an example of some code using an instance declaration:
@example
:- type coordinate
@@ -2930,9 +2967,57 @@
= coloured_coordinate(X + Dx, Y + Dy, Colour).
@end example
+If we call @samp{translate/3} with the first argument having type
+ at samp{coloured_coordinate}, this will invoke
+ at samp{coloured_coordinate_translate}.
+Likewise, if we call @samp{translate/3} with the first argument having type
+ at samp{coordinate}, this will invoke @samp{coordinate_translate}.
+
Further instances of the typeclass could be made, e.g. a type which represents
the point using polar coordinates.
+ at node Abstract instance declarations
+ at section Abstract instance declarations
+
+Abstract instance declarations are instance declarations whose
+implementations are hidden. An abstract instance declaration has the
+same form as an instance declaration, but without the @samp{where
+[@dots{}]} part. An abstract instance declaration declares that
+certain type(s) are an instance of a particular type class without
+defining how the type class methods are implemented for those type(s).
+Like abstract type declarations,
+abstract instance declarations are only useful in the interface
+section of a module. Each abstract instance declaration must
+be accompanied by a corresponding non-abstract instance declaration
+that defines how the type class methods are implemented.
+
+Here's an example:
+
+ at example
+:- module hashable.
+:- interface.
+:- import_module int, string.
+
+:- typeclass hashable(T) where [func hash(T) = int].
+:- instance hashable(int).
+:- instance hashable(string).
+
+:- implementation.
+
+:- instance hashable(int) where [func(hash/1) is hash_int].
+:- instance hashable(string) where [func(hash/1) is hash_string].
+
+:- func hash_int(int) = int.
+hash_int(X) = X.
+
+:- func hash_string(string) = int.
+hash_string(S) = H :-
+ % use the standard library predicate string__hash/2
+ string__hash(S, H).
+
+:- end_module hashable.
+ at end example
+
@node Type class constraints on predicates and functions
@section Type class constraints on predicates and functions
Index: tests/hard_coded/typeclasses/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/hard_coded/typeclasses/Mmakefile,v
retrieving revision 1.13
diff -u -b -r1.13 Mmakefile
--- Mmakefile 1998/10/23 00:41:57 1.13
+++ Mmakefile 1999/02/09 06:36:50
@@ -24,7 +24,9 @@
operator_classname \
superclass_call \
test_default_func_mode \
- typeclass_test_6
+ typeclass_test_5 \
+ typeclass_test_6 \
+ use_abstract_instance
# These tests are all failing in jump and fast grades b/c we can't use static
# code initialisers.
@@ -51,16 +53,13 @@
# Actually, there is a bug, but it isn't in that test case. I'm trying to
# find exactly how to trigger the bug. Oh well...
-# we do not yet pass the following tests:
-# typeclass_test_5.m (this is really a WISHLIST item)
-#
-
MCFLAGS-extra_typeinfo = --optimize-higher-order --no-type-specialization \
--typeinfo-liveness
MCFLAGS-inference_test = --infer-all
MCFLAGS-inference_test_2 = --infer-all
MCFLAGS-existential_type_classes = --infer-all
MCFLAGS-lambda_multi_constraint_same_tvar = --infer-all
+MCFLAGS-abstract_instance = --infer-all
#-----------------------------------------------------------------------------#
Index: tests/hard_coded/typeclasses/abstract_instance.m
===================================================================
RCS file: abstract_instance.m
diff -N abstract_instance.m
--- /dev/null Tue Feb 9 20:39:39 1999
+++ abstract_instance.m Tue Feb 9 17:38:50 1999
@@ -0,0 +1,22 @@
+:- module abstract_instance.
+:- interface.
+:- import_module io, list.
+
+:- typeclass runnable(T) where [
+ pred run(T::in, io__state::di, io__state::uo) is det
+].
+
+:- instance runnable(int).
+:- instance runnable(string).
+:- instance runnable(list(T)) <= runnable(T).
+
+:- implementation.
+
+:- instance runnable(int) where [pred(run/3) is run_int].
+:- instance runnable(string) where [pred(run/3) is run_string].
+:- instance runnable(list(T)) <= runnable(T) where [pred(run/3) is run_list].
+
+run_int(I) --> io__write_int(I), io__nl.
+run_string(S) --> io__write_string(S), io__nl.
+run_list([]) --> [].
+run_list([X|Xs]) --> run(X), run(Xs).
Index: tests/hard_coded/typeclasses/use_abstract_instance.exp
===================================================================
RCS file: use_abstract_instance.exp
diff -N use_abstract_instance.exp
--- /dev/null Tue Feb 9 20:39:39 1999
+++ use_abstract_instance.exp Tue Feb 9 17:39:42 1999
@@ -0,0 +1,10 @@
+42
+hello world
+5
+4
+3
+2
+1
+hello
+world
+0
Index: tests/hard_coded/typeclasses/use_abstract_instance.m
===================================================================
RCS file: use_abstract_instance.m
diff -N use_abstract_instance.m
--- /dev/null Tue Feb 9 20:39:39 1999
+++ use_abstract_instance.m Tue Feb 9 17:37:50 1999
@@ -0,0 +1,15 @@
+:- module use_abstract_instance.
+:- interface.
+:- import_module io.
+
+:- pred main(io__state::di, io__state::uo) is det.
+
+:- implementation.
+:- import_module abstract_instance, list.
+
+main -->
+ run(42),
+ run("hello world"),
+ run([5,4,3,2,1]),
+ run(["hello", "world"]),
+ run([[[[0]]]]).
Index: tests/invalid/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/invalid/Mmakefile,v
retrieving revision 1.36
diff -u -b -r1.36 Mmakefile
--- Mmakefile 1998/11/09 05:28:38 1.36
+++ Mmakefile 1999/02/09 08:00:32
@@ -54,6 +54,7 @@
typeclass_test_4.m \
typeclass_test_5.m \
typeclass_test_7.m \
+ typeclass_test_9.m \
types.m \
unbound_inst_var.m \
undef_lambda_mode.m \
@@ -67,6 +68,8 @@
# parent.undeclared_child.m (just not yet implemented)
# sub_b.m and sub_c.m (bug with dependencies & nested modules)
# freefree.m (need bromage's aliasing stuff)
+# typeclass_test_8.m (minor formatting error in the output --
+# the type class name should be in quotes)
MCFLAGS-multisoln_func = --infer-types
MCFLAGS-any_mode = --infer-types
Index: tests/invalid/typeclass_test_9.err_exp
===================================================================
RCS file: typeclass_test_9.err_exp
diff -N typeclass_test_9.err_exp
--- /dev/null Tue Feb 9 20:39:39 1999
+++ typeclass_test_9.err_exp Tue Feb 9 20:41:55 1999
@@ -0,0 +1,12 @@
+typeclass_test_9.m:001: In module `typeclass_test_9':
+typeclass_test_9.m:001: warning: module `std_util'
+typeclass_test_9.m:001: is imported in the interface, but is not
+typeclass_test_9.m:001: used in the interface.
+typeclass_test_9.m:010: Error: multiply defined (or overlapping) instance
+typeclass_test_9.m:010: declarations for class `typeclass_test_9:foo/1'.
+typeclass_test_9.m:007: Previous instance declaration was here.
+typeclass_test_9.m:013: In instance declaration for `typeclass_test_9:bar/1':
+typeclass_test_9.m:013: incorrect method name(s).
+typeclass_test_9.m:018: In instance declaration for `typeclass_test_9:baz/1':
+typeclass_test_9.m:018: incorrect method name(s).
+For more information, try recompiling with `-E'.
Index: tests/invalid/typeclass_test_9.m
===================================================================
RCS file: typeclass_test_9.m
diff -N typeclass_test_9.m
--- /dev/null Tue Feb 9 20:39:39 1999
+++ typeclass_test_9.m Tue Feb 9 20:42:38 1999
@@ -0,0 +1,19 @@
+:- module typeclass_test_9.
+:- interface.
+:- import_module std_util.
+:- typeclass foo(T) where [pred p is semidet].
+:- typeclass bar(T) where [].
+:- typeclass baz(T) where [pred q is semidet].
+:- instance foo(int) where [
+ pred(p/0) is semidet_succeed
+].
+:- instance foo(int) where [
+ pred(p/0) is semidet_fail
+].
+:- instance bar(int) where [
+ pred(p/0) is semidet_fail
+].
+:- instance baz(int) where [
+ pred(r/0) is semidet_fail,
+ pred(q/0) is semidet_fail
+].
--
Fergus Henderson <fjh at cs.mu.oz.au> | "Binaries may die
WWW: <http://www.cs.mu.oz.au/~fjh> | but source code lives forever"
PGP: finger fjh at 128.250.37.3 | -- leaked Microsoft memo.
More information about the developers
mailing list