System modules and functional modules can be parameterized. A parameterized system module has syntax
mod M{
::
, ...
,
:: ![]()
} is ... endm
with
. Parameterized functional modules have completely analogous syntax.
The {
::
, ...,
:: ![]()
} part is called the
interface,
where each pair
is a
parameter, and each
is an identifier--the parameter name
or
parameter label--and
each
is an expression that yields a
theory--the parameter theory.
Each parameter name in an interface must
be unique, although there is no uniqueness restriction on the parameter
theories of a module--we can have, e.g., two TRIV parameters. The
parameter theories of a functional module must be functional theories.
In a parameterized module
, all the sorts and statement labels coming from
theories in its interface must be qualified by their names. Thus, given a
parameter
, each sort
in
must be
qualified as
, and each label
of a statement occurring in
must be qualified as
. In fact, the parameterized module
is flattened as follows. For each parameter
, a renamed copy of the theory
, called
is
included. The renaming maps each sort
to
, and each label
of a statement occurring in
to
. The renaming
percolates down through nested inclusions of theories, but has no effect on
importations of modules. Thus, if
includes a theory
, when the
renamed theory
is created and included into
, and the renamed theory
will also be created
and included into
.6.5However, the renaming will have no effect on modules imported by either the
or
; for example, if BOOL is imported by one of these theories,
it is not renamed, but imported in the same way into
.
For example, a parameterized module PRELIM-SET with TRIV as interface can be defined as follows:
fmod PRELIM-SET{X :: TRIV} is
protecting BOOL .
sorts Set NeSet .
subsorts X$Elt < NeSet < Set .
op empty : -> Set .
op _,_ : Set Set -> Set [assoc comm id: empty] .
op _,_ : NeSet NeSet -> NeSet [ditto] .
op _in_ : X$Elt Set -> Bool .
op _-_ : Set Set -> Set . *** set difference
var E : X$Elt .
vars S S' : Set .
eq E, E = E .
eq E in E, S = true .
eq E in S = false [owise] .
eq (E, S) - (E, S') = S - (E, S') .
eq S - S' = S [owise] .
endfm
In Maude--unlike OBJ3
and other similar languages--sorts are not
systematically qualified by their module name.
This convention of not qualifying sorts may be particularly weak when dealing
with parameterized modules. However, given that Maude supports ad-hoc
overloading and that constants can be qualified in order to be disambiguated
(see Section 3.9.3), the problem of ambiguity in a signature
is reduced to collisions of sorts. For example, in a module one may very easily
need sets of integers and sets of quoted identifiers, in which case, given
the specification of the PRELIM-SET module above, we would get two
Set sorts from different importations which would be confused into one sort.
Our solution consists in qualifying parameterized sorts,
not with the module
expression they belong to, but with the name of the view or views used in
the instantiation of the parameterized module. Since we assume that all views
are named, these names are the ones used in the qualification. Specifically, in
the body of a parameterized module ![]()
{
![]()
}, any sort
can be written in the form
![]()
{
![]()
}. When the module
is instantiated with views
, then this sort is instantiated to
![]()
{
![]()
}.
Note that, although we strongly recommend it, the parameterization of sorts is optional, and therefore, for example, the above PRELIM-SET specification is a perfectly valid parameterized module.
Sorts declared in the parameterized module ![]()
{
![]()
} may in general be parameterized as
![]()
{
![]()
}, with
,
and where each
is an
. It is recommended that all sorts declared in
a parameterized module be parameterized with
and
for
, but this is not enforced--parameterized sorts may duplicate, omit, or
reorder parameters and unparameterized sorts are also allowed.
Thus, the previous PRELIM-SET module to define sets could instead have been specified in a better way as follows:
fmod BASIC-SET{X :: TRIV} is
protecting BOOL .
sorts Set{X} NeSet{X} .
subsorts X$Elt < NeSet{X} < Set{X} .
op empty : -> Set{X} .
op _,_ : Set{X} Set{X} -> Set{X} [assoc comm id: empty] .
op _,_ : NeSet{X} NeSet{X} -> NeSet{X} [ditto] .
op _in_ : X$Elt Set{X} -> Bool .
op _-_ : Set{X} Set{X} -> Set{X} . *** set difference
var E : X$Elt .
vars S S' : Set{X} .
eq E, E = E .
eq E in E, S = true .
eq E in S = false [owise] .
eq (E, S) - (E, S') = S - (E, S') .
eq S - S' = S [owise] .
endfm
When this module is instantiated with the predefined view Int, the sort
Set{X} becomes Set{Int}, and when it is instantiated with the
predefined view Qid (see Section 7.11.1) it becomes Set{Qid}.
In the following sections we will see additional examples of how this
qualification convention for the sorts of a parameterized module avoids many
unintended collisions of sort names,
thus making renaming practically
unnecessary.6.6
As another simple example of parameterized module, we consider a
module MAYBE{X :: TRIV} in which we declare a sort Maybe{X} as
a supersort of the sort Elt of the parameter theory and a constant
maybe of this sort Maybe{X}. This technique is useful to declare
a partial function as a total function, as we will see in the PFUN
module of Section 14.3.2.
fmod MAYBE{X :: TRIV} is
sort Maybe{X} .
subsort X$Elt < Maybe{X} .
op maybe : -> Maybe{X} [ctor] .
endfm
The PRELIM-SET, BASIC-SET, and MAYBE
modules above have only one parameter. In general, however,
parameterized modules can have several parameters. It can furthermore happen
that several parameters are declared with the same parameter theory, that is,
we can have, for example, an interface of the form {X :: TRIV, Y :: TRIV}
involving two copies of the theory TRIV. Therefore, parameters cannot
be treated as normal submodules, since we do not want them to be shared when
their labels are different.
We regard the relationship between the body of a
parameterized module and the interface of its parameters not as an inclusion,
but as a module constructor which is evaluated generating renamed copies of the
parameters, which are then included. For the above interface, two copies of
the theory TRIV are generated, with names
and
.
As already mentioned, in such copies of parameter theories,
sorts are renamed as follows: if
is the label of a parameter theory
,
then each sort
in
is renamed to
and each statement label
is
renamed to
. All occurrences of these sorts and labels in the body
of the parameterized module must mention their corresponding renaming.
Let us consider as an example the following module PAIR, in which we would like to point out the use of the qualifications for the sorts coming from each of the parameters.
fmod PAIR{X :: TRIV, Y :: TRIV} is
sort Pair{X, Y} .
op <_;_> : X$Elt Y$Elt -> Pair{X, Y} .
op 1st : Pair{X, Y} -> X$Elt .
op 2nd : Pair{X, Y} -> Y$Elt .
var A : X$Elt .
var B : Y$Elt .
eq 1st(< A ; B >) = A .
eq 2nd(< A ; B >) = B .
endfm
As already mentioned, if a parameter theory is structured, this renaming process for parameter theories is carried out not only at the top level, but for the whole ``theory part,'' that is, renaming subtheories but not renaming submodules. Consider, for example, the following parameterized module defining a lexicographical ordering on pairs of elements of two totally strictly ordered sets.
fmod LEX-PAIR{X :: STOSET, Y :: STOSET} is
sort Pair{X, Y} .
op <_;_> : X$Elt Y$Elt -> Pair{X, Y} .
op _<_ : Pair{X, Y} Pair{X, Y} -> Bool .
op 1st : Pair{X, Y} -> X$Elt .
op 2nd : Pair{X, Y} -> Y$Elt .
vars A A' : X$Elt .
vars B B' : Y$Elt .
eq 1st(< A ; B >) = A .
eq 2nd(< A ; B >) = B .
eq < A ; B > < < A' ; B' > = (A < A') or (A == A' and B < B') .
endfm
Representing by boxes the modules (with initiality constraints), by ovals
the theories (with loose semantics), by triple arrows the protecting
and parameter importations, and by single arrows the including
importations, we can depict the structure of the LEX-PAIR functional
module defining a lexicographic order on pairs as in
Figure 6.2, where we have two copies not only
of STOSET but also of the SPOSET and TAOSET subtheories
(see also Figure 6.1 in page
), but only
one copy of the BOOL submodule.
The parameter theory of a module can be any module expression whose result is a theory. The following module defines bags of elements with an occurrences operation that returns the number of occurrences of a particular element in a given bag.
fmod BAG{X :: TRIV * (sort Elt to Element)} is
protecting NAT .
sorts Bag{X} NeBag{X} .
subsorts X$Element < NeBag{X} < Bag{X} .
op mt : -> Bag{X} .
op __ : Bag{X} Bag{X} -> Bag{X} [assoc comm id: mt] .
op __ : Bag{X} NeBag{X} -> NeBag{X} [ditto] .
op occurrences : X$Element Bag{X} -> Nat .
vars E E' : X$Element .
var S : Bag{X} .
eq occurrences(E, E S) = 1 + occurrences(E, S) .
eq occurrences(E, S) = 0 [owise] .
endfm
Module instantiation will be explained in the next section, and then we shall see some execution examples.