[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