Modules, Submodules and Instances.

Ralph Becket rwab1 at cam.sri.com
Sat Jan 30 02:42:42 AEDT 1999


Hi,

I've got a few questions that I can't figure out from the manual or
sample code...

(1) MODULE QUALIFIERS

I've noticed a drift from `name__' as a module qualifier to `name:' -
personally I find the former easier on the eyes, but oh well.  ':' is
yukky, '.' is nice.  How long will '__' stick around?  Will '.' ever
make it in?

(2) TYPECLASS INSTANCES

Say I want to export a type t as an instance of some typeclass c.
Currently I have to do something like

	:- module foo.
	:- interface.
	:-	typeclass c(T) where [pred repn(T::in, string::out) is det].
	:-	type t.
	:-	instance c(t) where [pred(repn/2) is r].
	:- implementation.
	:-	use_module string.
	:-	type t == int.
	:-	pred r(t::in, string::out) is det.
		r(I,S) :- string__int_to_string(I, S).

But here I'm releasing information about the implementation of t to
the outside world.  Now, this is in the same class of minor crime as
the mode problem, but I wonder whether it would really be that much
harder to get the compiler to handle putting
	:- instance c(t).
in the interface and requiring
	:- instance c(t) where [...].
in the implementation.  This way, nothing about t is made visible to
the outside world other than that it implements c.

(3) SUBMODULES - THE BIGGY

The language reference is somewhat cryptic on the matter of submodules
and I've got a few questions I'd be grateful to get answers to.

(3.1) Declaring Submodules

So,
	:- module foo.
	...
	:- include_module bar, baz.
defines bar and baz to be separate submodules of foo.  And something
is a separate submodule of foo iff it is the subject of an
include_module directive in foo?

What exactly is the naming convention here?  Under 0.8.1 I take it
that bar and baz must be implemented in files foo.bar.m and foo.baz.m
respectively.

Do you need to module qualify separate submodule names?  That is,
should bar.m begin
	:- module foo__bar.
or is
	:- module bar.
sufficient?  Also, if bar is implemented in foo.bar.m etc., should the
include_module declaration in foo.m be written as
	:- include_module foo__bar, foo__baz.
What about use_/import_module declarations for bar and baz?

The only instance of include_module I've found in the distribution is
in the complex_numbers wrapper in extras, where submoduling doesn't
really appear to be exploited.

(3.2) Does it matter where the include_module declaration goes?

Is there any difference between placing it in the interface or the
implementation section?

(3.3) Submodules and Parent Modules.

Presumably a submodule cannot directly implement something declared in
the interface of a parent.  That is, one cannot have

:- module foo.
:- interface.
:-	type t.
:- implementation.
:-	module bar.		% Nested submodule.
:-	interface.
:-	type foo__t == int.

and indeed the compiler rejects this.  But there are all manner of
weird things afoot.

Indeed, trying to do
	$mmake foo.depend; mmake foo
on the file foo.m containing
	:- module foo.
	:- interface.
	:-      type t. 
	:- implementation.
	:-      module bar.             % Nested submodule.
	:-      interface.
	:-              type t == int. 
in the presence of a Mercury directory I get
	mercury_compile: can't open file `Mercury/int0s/foo.int0'.
	For more information, try recompiling with `-E'.
which is a tad opaque.

Also, when trying to close the bar nested submodule section I've tried
all the following
	:- 	end_module bar.
	:- 	end_module foo__bar.
	:- 	end_module foo.
(the latter trying to close the whole thing) and I get complaints from
the compiler about the end_module declaration not matching the opening
module declaration.  The only test file I've managed to get to
work is
	:- module foo.
	:- interface.
	:-      type t.
	:- implementation.
	:-      module bar.
	:-      interface.
	:-              type u == int.
	:-      end_module bar.
	:-      use_module foo__bar.
	:-      type t == bar__u.
	:- end_module foo.

[The point I'm making, so far, is that the manual really needs some
work if these facilities are going to be used -- and they are *good*
facilities.  It's taken me quite some time to find heuristics that
work -- sort of.]

(3.4) A Submodule Cannot Directly Implement Something
Exported From the Parent Module.

That is, I can't do
	:- module foo.
	:- interface.
	:-      type t.
	:- implementation.
	:-      module bar.
	:-      interface.
	:-              type foo__t == int.
	:-      end_module bar.

(3.5) Visibility

Everything in the parent module (interface and implementation) is
visible to its submodules.  Therefore, if the parent exports type t
and (some of) its children also export type t, then the parent can
only reference them via use_module (import_module would lead to a name
clash).

Nope, just tried
	:- module foo.
	:- interface.
	:-      type t.
	:- implementation.
	:-      module bar.
	:-      interface.
	:-              type t == int.
	:-      end_module bar.
	:-      import_module foo__bar.
	:-      type t == bar__t.
	:- end_module foo.

Oh well, weird stuff was afoot this morning.  Probably pre-coffee
stress disorder.  Still, an example is worth a thousand words in the
manual.

Either way, just to clear things up, an include_module directive does
not need to be qualified, but a use_/import_module directive does.



The upshot of this all is that I've had to try all permutations of
use_/import_module, nested and separate and qualified/non-qualified
names in order to find out how things work.  Can somebody lay down the
law on this matter in words of one syllable?  It'd be much
appreciated!

Cheers,

Ralph

p.s. Interestingly, this morning I was sober and everything was going
wrong, but now I'm a up to the end of a post-meeting bottle-o-plonk
and things are working much better.  There's a lesson in here
somewhere.

-- 
Ralph Becket  |  rwab1 at cam.sri.com  |  http://www.cam.sri.com/people/becket.html



More information about the users mailing list