<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<p>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).<br>
</p>
<p>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.<br>
</p>
<p>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.</p>
<p>Below is a somewhat minimal example of this contrast:<br>
</p>
<blockquote>
<p>%---- Inlined case: no abstract instance declaration ---- %</p>
<p>:- module test3.
<br>
:-
interface.
<br>
:- import_module io. <br>
:- import_module string. <br>
:- pred main(io::di, io::uo) is det.<br>
<br>
:- typeclass eval_type(T) where [ <br>
pred
eval(T), <br>
mode eval(out) is det <br>
].
<br>
:- pred eval_string(string::out) is det. <br>
<br>
:- implementation. <br>
<br>
:- import_module list. <br>
:- instance eval_type(string) where [ <br>
pred(eval/1) is eval_string
<br>
].
<br>
eval_string(Result) :- Result = "a". <br>
<br>
main(!IO)
:- <br>
eval(S11),
<br>
io.format("this string: %s\n", [s(S11)], !IO). <br>
</p>
<p>%------------------------------------------------------------------------%<br>
</p>
</blockquote>
<p>This file compiles and outputs: 'this string: a', and no abstract
instance declaration is necessary (as expected).<br>
</p>
<p>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:</p>
<blockquote>
<p>%------------------------------------------------------------------------%</p>
<p>:- module mod2.<br>
:- interface.<br>
:- import_module string.<br>
<br>
:- typeclass eval_type(T) where [<br>
pred eval(T), <br>
mode eval(out) is det <br>
].
<br>
<br>
% :- instance eval_type(string).<br>
<br>
:- pred eval_string(string::out) is det. <br>
<br>
:- implementation.<br>
<br>
:- instance eval_type(string) where [<br>
pred(eval/1) is eval_string <br>
]. <br>
<br>
eval_string(Result) :- Result = "a".<br>
</p>
<p>%------------------------------------------------------------------------%</p>
<p>:- module test2.<br>
:- interface.<br>
:- import_module io. <br>
:- pred main(io::di, io::uo) is det.</p>
<p>:- implementation.</p>
<p>:- import_module string, list.<br>
:- import_module mod2.</p>
<p>main(!IO) :- <br>
eval(S11),<br>
io.format("this string: %s\n", [s(S11)], !IO),<br>
io.nl(!IO). <br>
</p>
</blockquote>
<p>
%------------------------------------------------------------------------%
<br>
<br>
The error message on building test2 disappears if library mod2 is
rebuilt **after uncommenting** the abstract instance declaration
in the interface.</p>
<p>Why there should be an abstract instance declaration in the
interface of the module may be understood. <br>
</p>
<p>What is odd is that mod2 builds into a library whether the
abstract instance declaration is present or not in the interface.
<br>
</p>
<p>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.<br>
</p>
<p><br>
</p>
</body>
</html>