[m-users.] Document "Module typeclasses should be instantiated in the interface"
fabrice nicol
fabrnicol at gmail.com
Thu May 13 16:11:04 AEST 2021
I've recently bumped into the following constraint, which does not seem
to me to be quite clearly documented (either in the reference manual or
the user manual) and perhaps should be. (But then it may be that I did
not search hard enough).
When a module typeclass is imported into a parent Mercury source file
using ':- import_module', it so appears that the module interface should
contain an abstract instance declaration corresponding to each usable
type of the exported typeclass. Otherwise, the compiler will issue an
error message to the effect that the typeclass constraint is unsatisfiable.
What may be puzzling to beginners and maybe more advanced testers is
that this constraint does not show up if the typeclass in question is
inlined in the parent source file.
Below is a somewhat minimal example of this contrast:
%---- Inlined case: no abstract instance declaration ---- %
:- module test3.
:- interface.
:- import_module io.
:- import_module string.
:- pred main(io::di, io::uo) is det.
:- typeclass eval_type(T) where [
pred eval(T),
mode eval(out) is det
].
:- pred eval_string(string::out) is det.
:- implementation.
:- import_module list.
:- instance eval_type(string) where [
pred(eval/1) is eval_string
].
eval_string(Result) :- Result = "a".
main(!IO) :-
eval(S11),
io.format("this string: %s\n", [s(S11)], !IO).
%------------------------------------------------------------------------%
This file compiles and outputs: 'this string: a', and no abstract
instance declaration is necessary (as expected).
In contrast, the following module mod2 will build into a library,
**without any error message**, although it cannot be imported to any
avail into a Mercury source file, as in this case the compiler will
issue an error message ('typeclass constraint is unsatisfiable") on
building the target executable test2:
%------------------------------------------------------------------------%
:- module mod2.
:- interface.
:- import_module string.
:- typeclass eval_type(T) where [
pred eval(T),
mode eval(out) is det
].
% :- instance eval_type(string).
:- pred eval_string(string::out) is det.
:- implementation.
:- instance eval_type(string) where [
pred(eval/1) is eval_string
].
eval_string(Result) :- Result = "a".
%------------------------------------------------------------------------%
:- module test2.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
:- implementation.
:- import_module string, list.
:- import_module mod2.
main(!IO) :-
eval(S11),
io.format("this string: %s\n", [s(S11)], !IO),
io.nl(!IO).
%------------------------------------------------------------------------%
The error message on building test2 disappears if library mod2 is
rebuilt **after uncommenting** the abstract instance declaration in the
interface.
Why there should be an abstract instance declaration in the interface of
the module may be understood.
What is odd is that mod2 builds into a library whether the abstract
instance declaration is present or not in the interface.
As a user, I would advise, if this makes any sense, to issue an error
message at library compile time (since the typeclass will not be usable
in parent source files). Or, minimally, document this requirement.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.mercurylang.org/archives/users/attachments/20210513/a633a82d/attachment.html>
More information about the users
mailing list