This document describes the language of the SpecwareTM system. Specware is a system for the specification and formal development of software.
Specware may be regarded as a system for the construction, combination, and manipulation of specifications. There are many levels of specification in Specware. Some describe the ultimate purpose of the target software in abstract terms, some describe the properties and operations of various data structures, and others describe the details of a language-dependent implementation. Domain theories are Specware specifications, and the system has sophisticated facilities for building task-oriented theories from more general ones.
A basic operation in Specware is refinement (also called interpretation), the passage from high-level task-descriptive specifications to low-level implementation-oriented specifications, and ultimately to code generation. This process involves the design of algorithms and the selection of data structures, as well as the generation of code. While mechanical aspects of this task are automated, it is not the intention of Specware to replace the human designer, but rather to support and facilitate the best software-development practices and to ensure that correctness is maintained at each stage in the development of large software systems.
This document is organized as follows. Part I describes the specification constructs in Slang, the Specware language. Section 1 describes basic specifications, which are formed by explicitly providing their constituent sorts, operations, and axioms. Section 2.1 is a brief overview of specification-building operations, which construct new specifications from simpler ones, using morphisms and diagrams, described in Section 2.2. With that background, the specification-building operations--translate, import, and colimit--are described in detail in Section 3.
Part II describes the constructs in Slang for the stepwise refinement of a specification into an implementation. Section 4 gives an overview of the conceptual basis for refinement. Section 5 describes the associated language concepts, interpretations and interpretation morphisms, and how these concepts support the stepwise-refinement process.
Part III contains the appendices, which provide an overview of names in Slang, a BNF grammar for Slang, a table of Slang terms, some sample specifications and interpretations, and an index.
Part I Specification Constructs in Specware
Slang, the Specware language, includes constructs for building specifications and their refinements. Refinements are described in Part II; in this part, we describe the specification concepts of Slang:
In Part II we shall discuss how to combine morphisms to build a refinement, a transformation of specifications, which can be used for the selection of data structures and the implementation of software.
Specifications are either given directly as basic specifications or constructed via specification-building operations. This section introduces basic specifications; Section 3 describes specification-building operations.
A full BNF description of the syntax of a specification appears in the appendix; in the text, we give only informal descriptions of syntax. A basic specification consists of a set of specification elements. (In the BNF description of Slang these are called development-elements.) Not all of these elements need appear, and the order of appearance of the elements is irrelevant. We discuss each of these specification elements subsequently in separate subsections.
Boolean
, which contains two objects, denoted by true
and false
, and which is not mentioned explicitly in the specification.
spec NAT-BASIC is
sorts Nat, Pos
const zero : Nat
op nonzero? : Nat -> Boolean
definition of nonzero? is
axiom (iff (nonzero? x)
(not (equal x zero)))
end-definition
sort-axiom Pos = Nat | nonzero?
op nat-of-pos : Pos -> Nat
definition of nat-of-pos is
axiom (equal nat-of-pos (relax nonzero?))
end-definition
op succ : Nat -> Pos
axiom (nonzero? (nat-of-pos (succ x)))
axiom succ-is-one-to-one is
(implies (equal (succ x)(succ y))
(equal x y))
constructors {zero, nat-of-pos} construct Nat
constructors {succ} construct Pos
theorem (fa (x : Pos)
(ex (y : Nat)
(equal x (succ y))))
end-spec
NAT-BASIC
contains two explicit primitive sorts, Nat
and Pos
, denoting the nonnegative integers and the strictly positive integers respectively; it also contains the implicit built-in sort Boolean
.
The constant declaration
const zero : Nat
zero
stands for an object of sort Nat
. The operation declaration op nonzero? : Nat -> Boolean
nonzero?
is a predicate on elements of sort Nat
; a predicate is a boolean-valued operation. (Although we often end predicate symbols with a question mark, it is not required.) The sort axiom sort-axiom Pos = Nat | nonzero?
Pos
is equivalent to a constructed sort Nat | nonzero?
(which is the subsort of elements of sort Nat
that satisfy the predicate nonzero?
).
For example, in the specification
NAT-BASIC
in Figure 1, the definition of the predicate nonzero?
consists of a single axiom, a logical sentence that asserts that a nonnegative integer is said to be nonzero when it is not equal to zero. Another definition, of the function nat-of-pos
, asserts that the constant nat-of-pos
stands for the function (relax nonnegative?)
--the function relax
will be introduced subsequently. Note that sentences are in higher-order logic--the function relax
has a predicate nonnegative?
as its argument and yields another function; the constant nat-of-pos
is equal to that function. Syntax is Lisp-like--thus the successor of x
is written (succ x)
rather than succ(x)
or x
.The specification has axioms, some of them in definitions, and a theorem. Axioms and theorems in specifications are implicitly universally quantified; thus the axiom
succ-is-one-to-one
holds for all nonnegative integers x and
y. In addition to the explicit axioms, which appear literally in the specification, there are implicit axioms corresponding to some specification constructs. The definitions do not alter the theory but merely provide meanings for the defined constants, in this case nonzero?
and nat-of-pos
. The specification also has axioms that are not definitions, e.g., the axiom succ-is-one-to-one
. The theorem is a provable logical consequence of the implicit and explicit axioms. Introducing a theorem does not change the meaning of a specification. (See Sections 1.6 and 1.7 for more on the distinction between axioms, definitions, and theorems.)
The specification has two constructor sets, one for each of its two sorts,
Nat
and Pos
. The first constructor set, constructors {zero, nat-of-pos} construct Nat
zero
or is in the range of the function nat-of-pos
. The second constructor set constructors {succ} construct Pos
succ
. Together these constructor sets correspond to an implicit structural induction axiom for the nonnegative integers.1.1 Sorts
The primitive sorts of a specification are introduced via sort declarations. Each sort declaration consists of the keyword sort
or sorts
followed by a list of one or more sort identifiers. NAT-BASIC
, 1 viewed as a positive integer is distinguished from 1 viewed as a nonnegative integer; we may imagine that the two versions of 1 are invisibly subscripted, 1Nat
and 1Pos
. The function nat-of-pos
maps each positive integer into the same number viewed as a nonnegative integer; the function succ
maps each nonnegative integer into its successor viewed as a positive integer. Thussucc
0Nat
) = 1Pos
nat-of-pos
1Pos
) = 1Nat
succ
, and the downward-vertical arrows indicate the inclusion function nat-of-pos
. (nonzero? (succ x))
succ
yields a positive integer but nonzero?
accepts only nonnegative integers. For this reason, the axiom in the specification had to say (nonzero? (nat-of-pos (succ x)))
Pos
and declare the successor function to yield a nonnegative integer. That would have simplified this specification but complicated matters later, when we want to extend the specification and define a predecessor function pred
to subtract 1 from a positive integer. Using Pos
, we can defineop pred : Pos -> Nat
definition of pred is
axiom (equal (pred (succ x)) x)
end-definition
(pred zero)
has no meaning and is syntactically illegal.op pred : Nat -> Nat
(pred zero)
is a nonnegative integer, even though the axioms do not determine which nonnegative integer it is. It would thus be a legal operation to take the predecessor of zero
. This would be a subtly different version of the theory, not incorrect but different.Boolean
is the sort of the two truth values, true
and false
. This sort is built into every specification and need not be declared.1.2 Sort Constructors
Sort constructors are operators that apply to sorts. They are used to generate constructed sorts from primitive sorts or other constructed sorts. Slang has five sort constructors:
E1, E2,...,En
of two or more component sorts. They consist of tuples of elements from the component sorts, in order.
E1+E2+...+En
of two or more component sorts. Intuitively a coproduct consists of the ``disjoint union'' of elements from the component sorts.
D -> E
, where D
is a domain sort and E
is a range (or codomain) sort. It consists of functions from the domain sort D
into the range sort E
.
E/r?
, where E
is a base sort and r?
is an equivalence relation. It consists of the equivalence classes of elements of the base sort E
modulo the equivalence relation r?
.
Subsorts are denoted by a E|p?
, where E
is a supersort and p?
is a unary predicate. It consists of those elements of the supersort E
that satisfy the predicate p?
.
e1
through en
are of sorts E1
through En
, respectively, then
<e1 e2 ... en>
is a tuple whose sort is the product
E1,E2,...,En
. For example, if one
is of sort Nat
and X
is of sort Atom
, then <one X>
is of sort Nat, Atom
.In Specware, an operation that we think takes multiple arguments actually takes only a single argument, a tuple. For example, the binary relation
br
is declared as follows:
op br : E, E -> Boolean
The term ``
E, E
'' is a product sort; it indicates that the predicate br
takes a tuple of two arguments, both of sort E
. In practice, we are more likely to write (br e1 e2)
than (br <e1 e2>)
, but both are legal and they have the same meaning. The empty product sort
()
contains a single tuple, the empty tuple <>
. When the empty product occurs as the domain of a function sort, its syntax may be omitted. Thus, instead of writing ()
-> F
, we may write -> F
.There are two kinds of built-in operations on every product sort: an n-ary tuple constructor, which constructs elements of the product sort, and n projection functions, which select components of tuples. The constructor function maps elements
e1,...,en
into the tuple <e1 ... en>
. Each projection function (project i)
is of sort
(project i): E1,...,En -> Ei
It maps
<e1 ... en>
into ei
. The application of a projection function is written as ((project i) <e1 ... en>)
. Note that
project
is a higher-order function; it maps i
into (project i)
. Also, project
is polymorphic; hence, it is implicitly indexed by the product sort, as in (projectE1,...,Eni
). Thus (projectA1,A21
) is distinct from (projectB1,B21
) even though both would be written (project
1
); the ambiguity is resolved by type inference. Tuples can be nested--thus <a <b c>>
is a legitimate tuple.For each product sort, there corresponds a set of implicit axioms (See ``Axioms and Theorems,'' Section 1.6) that serve as the definition of the projection functions. These axioms do not appear literally in the specification, but will be used automatically in proving theorems in the corresponding theory. For a product of two sorts, ``
E1, E2
'', we have two implicit axioms:
(equal ((project 1) <e1 e2>) e1)
(equal ((project 2) <e1 e2>) e2)
<d1 d2>
equals <e1 e2>
, we know that d1
equals e1
and d2
equals e2
.1.2.2 Coproduct Sorts
The coproduct of a set of sorts may be thought of as their disjoint union. In other words, each element of any of the component sorts corresponds to an element of the coproduct, and no two elements of distinct components correspond to the same element of the coproduct. The structure is known as a variant record in some programming languages.E1
is a sort containing two elements X and Y, and E2
is a sort containing two elements Y and Z, then E1+E2
is a sort containing four elements X, Y, Y, and Z. We may imagine that the two elements originating in sort E1
have invisible subscripts 1, and the two elements originating in E2
have invisible subscripts 2; at any rate, the two copies of Y
are not equal. The situation is illustrated by the following figure:[]
, is the coproduct of zero components; it has no elements. (embed i): Ei -> E1+...+En
(embed 1)
maps E1
into E1+E2
. The element X1 of E1
maps into X1 of E1+E2
and Y1 of E1
maps into Y1 of E1+E2
.embed
is higher order and polymorphic (similar to project
). Thus an application is written ((embed i) ei)
, with the embed
symbol implicitly indexed (embedE1+...+Eni)
E1+E2
, we have(implies (equal ((embed 1) d1) ((embed 1) e1))
(equal d1 e1))
(implies (equal ((embed 2) d2) ((embed 2) e2))
(equal d2 e2))
(fa (d : E1+E2)
(or (ex (e1 : E1) (equal d e1))
(ex (e2 : E2) (equal d e2))))
(not (equal ((embed 1) e1)((embed 2) e2)))
1.2.3 Function Sorts
Given a domain sort D
and a range (or codomain) sort E
, the function sort D -> E
contains the functions from D
into E
. Most operations belong to function sorts. For example, the reflexive-closure operation cl
maps one binary relation into another: op cl : (E,E -> Boolean) -> (E,E -> Boolean)
D
is a sort term and exp
is a term of sort E
, then the lambda term (lambda (d : D) exp)
D -> E
. Occurrences of d
in exp
must be of sort D
; if the sort of d
can be determined to be of sort D
syntactically, we may omit the sort term, as in (lambda (d) exp)
d
, yields the value of the corresponding term exp
. The variable d
is regarded as a bound variable of the lambda term. Similarly for sequences of variables (x1 x2 ... xn)
; thus (lambda (x1 x2) (plus (times x1 x1) x2))
Nat, Nat -> Nat
in a specification in which plus
and times
also have that sort. f
is a function of sort D -> E
and d
is a term of sort D
, then the apply operation yields the result (f d)
of applying f
to d
. (See Section 1.5.)
The operations on functions satisfy two implicit axioms: an alpha rule that allows us to rename bound variables systematically without changing the value of a term, and a beta-rule for application, namely (in the one-variable case)
(equal ((lambda (d) ex p) arg)
exp[arg])
exp[arg]
is the result of replacing all occurrences of d
in exp
with arg
, renaming bound variables systematically if necessary to avoid name clashes.1.2.4 Quotient Sorts
Given a base sort E
and an equivalence relation r?: E, E -> Boolean
E/r?
denotes the quotient sort of E
modulo r?
. The elements of the quotient sort E/r?
are equivalence classes of elements of the base sort E
. For each quotient sort E/r?
, there is a built-in abstraction function which maps each element of the base sort to the equivalence class that contains it. This abstraction function, called quotient
, is a higher-order polymorphic function: (quotient r?) : E -> E/r?
Sixteen
is a sort consisting of the integers from 0 through 15; we arrange them in a rectangular arrays follows:0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
mod4?
be the relation that holds between two elements of Sixteen
if they both belong in the same column of the above array; thus (mod4? 1 9)
is true but (mod4? 5 6)
is not.Sixteen/mod4?
is the sort of equivalence classes of elements, where two elements are in the same class if the relation mod4?
holds between them; in other words, Sixteen/mod4?
is the sort of columns in the above array. The abstraction function (quotient mod4?)
maps a nonnegative integer in Sixteen
into the column in which it appears. Thus ((quotient mod4?)
2)
and ((quotient mod4?)
6)
are both equal to the third column of the array. quotient
is defined by the following implicit axioms:(iff (r? e1 e2)
(equal ((quotient r?) e1)
((quotient r?) e2)))
r?
on E
maps under abstraction into the equality relation on E/r?
. For example, two elements in the Sixteen
array are equivalent with respect to the relation mod4
if and only if the columns they appear in are equal. Also (fa (d : E/r?)(ex e : E) (equal d ((quotient r?) e)))
Sixteen
array contains an element. 1.2.5 Subsorts
Given a sort E
and a unary predicate p?: E -> Boolean
, the sort E|p?
denotes the subsort of E
generated by p?
. The subsort E|p?
consists of those elements of the supersort E
that satisfy the predicate p?
. For each subsort E|p?
, there is a built-in inclusion function, which maps elements of the subsort to the corresponding elements of the supersort. This inclusion function is called relax
, and is a higher-order polymorphic function: (relax p?) : E|p? -> E
NAT-BASIC
for the nonnegative integers on page 4, the positive numbers have been defined to be the subsort of those nonnegative integers that satisfy the predicate nonzero?
. The function nat-as-pos
was defined to be equal to the inclusion function (relax nonzero?)
, the function that maps each positive integer x into the nonnegative integer x.(relax p?)
is the identity function, since it maps an element into itself. But, as we have noted earlier, it maps x viewed at an element of the subsort into x viewed as an element of the supersort; these are not the same because we don't think of the element as existing independently of its sort.access-array
, which is intended to return the value of the array entry a[i] for given array a and index i.
Suppose
E
is the sort of the entries. If we declared our function with the signature op access-array : Array, Nat -> E
op access-array : ((Array, Nat) | in-bounds?) -> E
in-bounds?
is a predicate that holds only for an array a and index i such that i is less than the size of a. Thus the function access-array
is only defined on a subsort of the product of arrays and nonnegative integers, those for which the integer is within the bounds of the array.(relax in-bounds?)
to an element, say ai
, of the subsort, yields a corresponding pair <a,i>
. One must be careful to apply the function access-array
only to the subsort element ai
, not to the pair <a,i>.
relax
is provided by the following implicit axioms: (p? ((relax p?) d))
(implies (p? e)
(ex (d : E|p?) (equal e ((relax p?) d))))
nonzero?
, and vice versa. Also (implies (equal ((relax p?) d1) ((relax p?) d2))
(equal d1 d2))
1.2.6 Precedence
The product and coproduct sort constructors ``,
'' and ``+
'' have equal precedence, which is higher than that of the function sort constructor ``->
''; thus ``C, D -> E
'' is parsed as the function sort ``(C, D) -> E
,'' not as the product sort ``C, (D -> E)
.''|
'' and ``/
'' have equal precedence, which is higher than that of the product or coproduct, ``,'' or ``+
''; thus ``D + E|p?
'' is parsed as ``D + (E|p?).
'' This precedence may be overridden by using parentheses. ->
'' is right associative; thus ``C -> D -> E
'' is parsed as ``C -> (D -> E).
'' The product and coproduct sort constructors are not associative; insertion of parentheses corresponds to grouping, and will generate different products and coproducts from the ungrouped version. 1.3 Sort Axioms
Sort axioms can be used to assert an equivalence between an (elsewhere introduced) primitive sort and a constructed sort. The sorts and operations used in a sort axiom must be declared separately. The left side of a sort axiom must be a primitive sort; the right side can be either a primitive sort or a constructed sort.NAT-BASIC
contains the sort axiom sort-axiom Pos = Nat | nonzero?
Pos
and Nat
and the operation nonzero?
have already been declared. (In this case there is actually a definition for nonzero?
, but this is not required for the predicate to be mentioned in a sort axiom). sort-axiom A = B, C sort-axiom A = B -> C
A
cannot be both a product and a function sort. This is an implementation decision to simplify the type-checking--it may change in future versions.1.4 Operations
Specifications introduce operations as named constants of a specified sort. For example, NAT-BASIC
contains the following operation declarations: const zero : Nat
op nonzero? : Nat -> Boolean
op
or const
followed by the name of the operation, followed by a colon and a sort term which specifies the signature of the operation. Typically, the signature of an op
is a function sort and the signature of a const
is a primitive sort, but they may be used interchangeably and the signature can be any sort term. The system chooses a specific keyword while printing: op
if the signature of the operation is a function sort, and const
otherwise. op f : E
op f : -> E
f
while the latter appears as (f)
.
1.4.1 Built-in Operations
Built-in operations are declared implicitly in a specification and need not be declared explicitly. We have mentioned built-in operations associated with certain sort terms, such as relax
, quotient
, lambda
, project
, and embed
. There are also built-in boolean operations: the constants true
and false
, the unary not
, and the binary and
, or
, implies
, and iff
; all yield a boolean. Note that there is no n-ary and
or
. 1.4.2 Quantifiers
The boolean universal quantifier fa
and existential quantifier ex
are built-in boolean operations. If D
is a sort term and exp
is a term of sort boolean, so are the quantified terms (fa (d : D) exp)
exp
holds for all d
of sort D
, and (ex (d : D) exp)
exp
holds for some d
of sort D
. The symbol d
is regarded as a bound variable in the quantified term. As in the case of lambda terms, the occurrences of d
in exp
must be of sort D
, and the sort term may be omitted if it is redundant. If an undeclared operator appears in an axiom or theorem, it will be given implicit universal quantification (see Section 1.5).
For example, in the specification
NAT-BASIC
, we have the theorem (fa (x : Pos) (ex (y : Nat) (equal x (succ y))))
succ
is Nat
, we can determine syntactically that the sort of y
is Nat
and omit that sort declaration. Similarly, because the range of succ
is Pos
we can determine the sort of x
syntactically and omit that sort declaration. Finally, we can omit the universal quantification on x
, because it is there implicitly. Thus the above theorem could have been written as follows with no change of meaning: (ex (y) (equal x (succ y)))
D
may be primitive or constructed. For example, we have seen the implicit axiom for the abstraction function (fa (d : E/r?)(ex e : E) (equal d ((quotient r?) e)))
1.4.3 Equality
For every sort, there is a built-in equality relation equal
declared implicitly on that sort. These relations are all represented by the same symbol--type inference must resolve any ambiguity. The built-in boolean operator iff
is identified with the equality relation on the sort Boolean; the two may be used interchangeably on boolean terms. If two objects within a sort are equal, the results of applying any operation to them will also be equal--they are indistinguishable within that specification. (equal x x)
D
and E
and operation f : D -> E
, (implies (equal d1 d2)
(equal (f d1) (f d2)))
equal
for a sort is declared explicitly in a specification, it will be treated as distinct from the built-in equality relation for that sort. It is permissible, however, to provide axioms that constrain the meaning of the equality relation. For example, in the specification NAT-BASIC
on page 4, the axiom succ
-is
-one
-to
-one
asserts that the equality relation cannot hold between the successors of two distinct nonnegative integers.1.5 Terms and Formulas
Terms are constructed according to conventional rules of typed lambda calculus. In particular:
d
is a term of sort D
and f
is an operator of sort D -> E
, then the application (f d)
is a term of sort E
.
All functions in Slang accept one argument and return one result. Functions that accept more than one argument , or none , and functions that return more than one value are handled by accepting and returning tuples. The function application notation implicitly builds tuples if there is more than one argument. For example,
(plus x y)
is parsed as (plus <x y>)
.When there is only one argument, a tuple is not automatically constructed. As a consequence, the composition
(union (split s))
below is well-formed:
op union : Set, Set -> Set
op split : Set -> Set, Set
axiom (equal s (union (split s)))
The appendix (Appendix C) contains a table of terms in Slang and their sorts.
1.6 Axioms and Theorems
Axioms and theorems in a specification are formulas that use the symbols (sorts and operations) appearing in the signature of that specification. The distinction between axioms and theorems is that theorems can be proved from the rest of the specification and thus do not add to the theory generated by the specification. The order of the axioms and theorems in a specification is not significant.NAT-BASIC
contains the axioms axiom (iff (nonzero? x) (not (equal x zero)))
axiom (equal nat-of-pos (relax nonzero?))
axiom (nonzero? (nat-of-pos (succ x)))
axiom succ-is-one-to-one is
(implies (equal (succ x)(succ y)) (equal x y))
theorem (fa (x : Pos) (ex (y : Nat) (equal x (succ y))))
(p e)
, where neither p
nor e
has been declared. Then the axiom will be taken as an abbreviation for (fa (p e) (p e))
p
is not declared, because p
is syntactically in the position of an operator--it is probably an error. It will give no warning about e
because e
is in the position of an argument--it assumes that e
is intended to be universally quantified. The omitted initial universal quantifiers will be added internally; however, the system will print the formula in the original form, without the quantifier prefix. theorem (fa (x : POS) (ex (y : NAT) (equal x (succ y))))
theorem (ex (y) (equal x (succ y))
succ
-is
-one
-to
-one
, the specification NAT-BASIC
on page 4 would have additional models, in which the successor of 8 would be the same as, say, the successor of 4, namely 5; these models are excluded by the axiom.
1.7 Definitions
A definition for an operation f:D -> E
in Slang is a set of axioms that characterize f
. For example, the specification NAT-BASIC
defines the predicate nonzero?
as follows: definition of nonzero? is
axiom (iff (nonzero? x) (not (equal x zero)))
plus
, which adds two nonnegative integers, and pred
, which subtracts 1 from a positive integers: definition of plus is
axiom (equal (plus zero y) y)
axiom (equal (plus (nat-of-pos (succ x)) y)
(nat-of-pos (succ (plus x y))))
end-definition
definition pred-def of pred is
axiom (equal (pred (succ x)) x)
end-definition
definition
and end-definition
. Optionally, the definition may have a name or the name of the operation being defined, or both. Note that the user may select the name of the definition but the name of the operation in the heading must agree with the actual name of the operation that appears in the axioms. See the BNF grammar in the Appendix (B.1) for the precise syntax of definitions
A definition does not change the class of models for the specification, but it does assign a name to an object or function that exists in each of the models. For example, in each model for the nonnegative integers, there exists a unique function that maps x +1 into x; the effect of the definition
pred
-def
is to declare that the name of that function is pred
, not to eliminate any of the models.1.8 Constructor Sets
A constructor set is a set of operations with the same range sort; it implicitly introduces an induction axiom for that sort. It means that every element of the range sort can be obtained by repeated application of the elements of the constructor set. constructors {at, cons} construct Tree
at: Atom -> Tree cons: Tree, Tree -> Tree
a
corresponds to a binary tree (at a)
, and any two trees s
and t
can be combined into a new tree (cons s t)
.at
, of the atom X
. The left tree is the result of applying the function cons
to two other trees. (fa (p)
(implies
(and
(fa (a : Atom) (p (at a)))
(fa (s : Tree t : Tree)
(implies (and (p s) (p t)) (p (cons s t)))))
(fa (t : Tree) (p t))))
axiom (nonzero? (nat-of-pos (succ x)))
asserts that the images of
nat-of-pos
are distinct from zero
.
The operations
translate
, import
, and colimit
will be described in Section 3. However, before these operations can be explained, morphisms and diagrams need to be described. In particular, before applying the colimit operations, which combines more than one specification, we must indicate how the specifications are to relate with each other. The way of relating specifications in Specware is in terms of a morphism that describes how one specification can be viewed as part of another. The colimit is applied to a diagram of specifications related by morphisms. Furthermore, each of the operations constructs new morphisms that describe how the newly constructed specification is related to the given ones.
2.2 Morphisms
Definition 2.1: Morphism. A morphism is a mapping from a specification called the source specification to a specification called the target specification. Intuitively, it describes how the source theory can be regarded as a part of the target theory. A morphism m from a source specification S to a target specification T maps the sorts of S into the sorts of T, and the operations of S into the operations of T such that
When an element of S is mapped into an element of T under a morphism, that means those elements are being identified. For example, a morphism that maps the sort
Seq
into the sort Array
is identifying the sequences with the arrays, in the appropriate specifications. Morphisms are described in Slang by listing a translation of each of the explicitly declared sorts and operations. The translation of constructed sorts and formulas is then computed inductively. Morphisms are represented by expressions of the form
morphism [name] : <source spec> -> <target spec> is
{<name> -> <name>,
<name> -> <name>,
...}
Every symbol of the source specification must be mapped into a symbol of the target specification; however, if a symbol of the source specification is not mentioned explicitly in the mapping, it is assumed that it is mapped into a symbol of the same name in the target specification.
Although we have said that the source theory can be regarded as part of the target theory, in fact multiple elements of the source theory can be mapped into the same element in the target theory. That is, distinct sorts can map into the same sort, or distinct operations can map into the same operation.
We typically give only the name of the source and target specifications in a morphism, and define the corresponding specifications elsewhere, but we may provide any expression whose value is a specification. The name we give to a morphism is optional. The precise syntax for a morphism is given in the appendix (Section B.1, Syntax).
Let us define the identity morphism and the composition operation for morphisms.
Definition 2.2: Identity and Composition. For any specification S, the identity morphism is the morphism whose source and target are both S and which maps each element of S into itself.
For any morphisms m : R ->S and n : S ->T, the composition of m and n is a morphism m; n : R ->T, which maps each element of S into the result of applying first m and then n. Example 2.3 Consider the following two specifications:
spec FOO is spec BAR
sort A, B sort C, D, E
op f: A -> B op g: C -> D
end-spec op h: D -> E
end-spec
MOO
is well-formed. morphism MOO : FOO -> BAR is
{A -> C,
B -> D,
f -> g}
f
is mapped into the function g
; hence the domain A
of f
is mapped into the domain C
of g
, and the range B
of f
is mapped into the range D
of g
.GOO
is not a well-formed morphism:morphism GOO : FOO -> BAR is
{A -> C,
B -> E,
f -> g}
f
is mapped into the function g
, but the range B
of f
is not mapped into the range of g
. Example 2.4 Morphism over Pairs.
As an example, suppose we have the two specifications for pairs of elements. In the first specification, PAIR
(Figure 2) each component of a pair is of a different sort, D
and E
respectively. For example, if D
is the letters of the alphabet and E
is the decimal digits, [X, 2] would be of sort Pair
.
spec PAIR is
sorts D, E, Pair
op make-pair : D, E -> Pair
op first : Pair -> D
op second : Pair -> E
axiom (equal (first (make-pair d e)) d)
axiom (equal (second (make-pair d e)) e)
constructors {make-pair} construct Pair
theorem (equal p (make-pair (first p) (second p)))
end-spec
Figure 2: The Specification
The function PAIR
make-pair
forms a pair from two elements, of sorts D
and E
respectively. Thus makepair
applied to X and 2 yields the pair [X, 2]. There are two functions, first
and second
, that extract the first and second components, respectively, from a pair. Thus first
and second
applied to [X, 2] yield X and 2, respectively. (fa (P)
(implies
(fa (d : D e : E) (P (make-pair d e)))
(fa (p : Pair) (P p))))
(make-pair d e)
. (It follows that all pairs actually have this form.) This is a degenerate induction axiom; it has no induction hypothesis, because the function make-pair
in the constructor set does not take an argument of sort Pair
; its arguments are of sorts D
and E
, but these sorts have no constructor set. The induction axiom for binary trees (Section 1.8), in contrast, is a proper induction axiom, because the function cons
in the constructor set for the sort Tree
takes arguments of sort Tree
.
spec CONS-PAIR is
sorts Atom, Pair
op cons : Atom, Atom -> Pair
axiom uniqueness is
(implies (equal (cons a b) (cons aa bb))
(and (equal a aa) (equal b bb)))
constructors {cons} construct Pair
op head : Pair -> Atom
op tail : Pair -> Atom
definition of head is
axiom (equal (head (cons a b)) a)
end-definition
definition of tail is
axiom (equal (tail (cons a b)) b)
end-definition
theorem (equal p (cons (head p) (tail p))
op rev-pair : Pair -> Pair
definition of rev-pair is
axiom (equal (rev-pair (cons a b)) (cons b a))
end-definition
end-spec
Figure 3: The Specification
In the second specification, CONS-PAIR
CONS-PAIR
(Figure 3), both components of a pair are of the same sort, Atom
. For example, if Atom
is the letters of the alphabet, [X, Y] would be of sort Pair
.
The functions
cons
, head
, and tail
play the role of make-pair
, first
, and second
, respectively, in PAIR
. In addition, CONS-PAIR
includes the definition of a function rev-pair
that reverses the components of a pair; thus the result of reversing the pair [X, Y] is [Y, X]. We could not define this function in the first specification, PAIR
, because the result of reversing a pair would not be a pair--the sorts would be reversed. The following morphism, then, embeds PAIR
into CONS-PAIR
and indicates the relationship between these two specifications: morphism PAIR-TO-CONS-PAIR : PAIR -> CONS-PAIR is
{D -> Atom,
E -> Atom,
make-pair -> cons,
first -> head,
second -> tail}
Pair
from the specification PAIR
is mapped into the same symbol in the specification CONS-PAIR
, even though no replacement Pair -> Pair
is included explicitly in the mapping.PAIR
, the axioms for first
and second
are not regarded as definitions, because they restrict the models of the specification. Without these axioms, for example, we could have a model in which there were many elements of sort D
or E
but only one pair, p1
; in such a model, whatever its arguments, the value of (make-pair d e)
would be p1
.first
and second
preclude this possibility. If there are at least two distinct elements of sort D
, say d1
and d2
, the axiom for first
would then imply that the first element of p1
=(make-pair d1 e)
is d1
, and also that the first element of p1
= (make-pair d2 e)
is d2
, which is impossible. Similarly, if there are at least two distinct elements of sort E
, the axiom for second
implies a contradiction.head
and tail
in the specification CONS-PAIR
are true definitions. The uniqueness axiom of this specification already guarantees that there cannot be any such bizarre models. From this axiom and the implicit axiom corresponding to the constructor set, we can establish that there exist unique functions satisfying the axioms for head
and tail
; the definitions serve only to name these functions. first
from the specification PAIR
: axiom (equal (first (make-pair d e)) d)
head
in the specification CONS-PAIR
: axiom (equal (head (cons a b)) a)
a
, b
, d
, and e
are dummy variables: they are implicitly quantified universally and do not need to be translated.) In general, however, it would suffice if each axiom from the source were mapped into a theorem of the target; the theorem need not be listed explicitly in the target specification, so long as it is provable from the axioms of the target.CONS-PAIRS
and PAIR
, because we cannot map the sort Atom
into two distinct sorts D
and E
.Boolean
, the Boolean operations (and
, or
, not
, etc.), quantifiers (fa
, ex
, lambda
, etc.), and equality. MOO
mentioned earlier maps sorts A
into C
and B
into D
, it also maps, for example, the constructed sort A, B -> A
into C, D -> C
.
The source and target of a morphism are sometimes referred to as its domain and codomain. The image of a morphism comprises those elements of its codomain that are mapped onto by some elements of its domain; thus
E
is in the image of {X -> E}
but D
is not. We say that a morphism is injective or one-to-one if it doesn't collapse two distinct sorts or operations of its domain into a single sort or operation, respectively, of its codomain; thus {X -> E, Y -> E}
is not one-to-one.identity-morphism
. There is no syntax in Slang for denoting the composition of two morphisms; this is done using the graphical facilities of Specware.
2.3 Diagrams
A diagram is a directed multigraph whose nodes are labeled with specifications and whose arcs are labeled with morphisms. A multigraph differs from a graph in that there may be more than one arc between nodes. For a diagram to be well formed, the source and target specifications of each of the morphisms must be the same as the specifications that label the source and target nodes of the corresponding arc. To give an example of a diagram, let us first introduce some simple specifications.Example 2.5 Preorder Diagram.
Here is a basic specification for the theory of reflexive relations: spec REFLEXIVE-RELATION is
sort E
op rr : E, E -> Boolean
axiom reflexive is (rr e e)
end-spec
rr
stands for a reflexive relation, such as <= or iff
; thus if rr
stands for <=, the condition (rr d e)
would mean d
<=e. The reflexive axiom states the reflexive property of the relation.spec TRANSITIVE-RELATION is
sort E
op tr : E, E -> Boolean
axiom transitive is
(implies (and (tr c d) (tr d e))
(tr c e))
end-spec
tr
in this specification plays the role of rr
in the specification for the reflexive relations. The transitivity axiom states the transitivity property of the relation tr
.
spec BINARY-RELATION is
sort E
op br : E, E -> Boolean
end-spec
Figure 4: Diagram for a Preorder
To combine these specifications we must indicate with a diagram what elements are to be identified. In graphical form, such a diagram is illustrated in Figure 4. The diagram indicates that the operation rr
in the reflexive-relation specification is to be identified with the operation tr
in the transitive-relation specification. The binary-relation specification acts as an intermediary in making these identifications. Morphisms map constructs from the binary-relation specification into the corresponding constructs in the other two specifications; if one construct is mapped into the other, the two are to be identified.
morphism BIN-REL-TO-REFLEXIVE :
BINARY-RELATION -> REFLEXIVE-RELATION is
{br -> rr}
br
is to be identified with the operation rr
.morphism BIN-REL-TO-TRANSITIVE :
BINARY-RELATION -> TRANSITIVE-RELATION is
{E -> E,
br -> tr}
E -> E
could have been omitted, since both sorts have the same name E
. Note that this morphism maps the operation br
into the operation tr
.
diagram PREORDER-DIAGRAM is
nodes BINARY-RELATION, REFLEXIVE-RELATION, TRANSITIVE-RELATION
arcs BINARY-RELATION -> REFLEXIVE-RELATION : BIN-REL-TO-REFLEXIVE,
BINARY-RELATION -> TRANSITIVE-RELATION : BIN-REL-TO-TRANSITIVE
end-diagram
br
is mapped into rr
by one morphism and into tr
by the other, all three operations will be identified in the colimit specification. This will be discussed further in Section 3.4.
We could not have constructed a morphism directly between
REFLEXIVE-RELATION
and TRANSITIVE
-RELATION
, or vice versa, because each specification has an axiom that would not be mapped into a theorem of the other. But we were able to construct morphisms from the impoverished specification BINARY-RELATION
into the other two.BINARY-RELATION
and REFLEXIVE-RELATION
of the source and target specifications, respectively, because these are the same as the labels of the nodes at the ends of the arc, and can be inferred.
spec
sort E
op br : E, E -> Boolean
end-spec
-> REFLEXIVE-RELATION : {br -> rr}
3 Specification-Building Operations
Now that we have discussed morphisms and diagrams, we can introduce the operations for constructing a specification from other specifications: translate
, import
, and colimit
.3.1 Translate
The translate operation creates a copy of a specification, perhaps renaming some components. Here is an example: Example 3.1 Translated Binary Relations.
The specification BINARY-RELATION
was introduced on page 35. The expression translate BINARY-RELATION by
{br -> rr}
spec TRANSLATED-BINARY-RELATION is
sorts E
op rr : E, E -> Boolean
end-spec
translate ...
cannot be given at the top level because it is not named; it could not be referred to elsewhere.
A translation is given by the keyword
translate
followed by a specification and a set of renaming rules, which indicate how the symbols of the specification are to be renamed. A renaming map is a one-to-one map used for copying a specification. If a renaming maps two sorts onto the same sort name, or two operations onto the same operation name, there will be multiple sorts or operations with the same name in the copied specification. Although this is not illegal, it is inconvenient in that references to these sorts or operations will be ambiguous. In a translation, the axioms are also rewritten to reflect the new names of the sorts and operations; however, the names of axioms, theorems, etc., remain the same. Also, the names of bound variables are unaffected by a translation, but changing the names of bound variables does not change the meaning of a formula anyway.translate
operation also constructs a translation morphism, which maps the elements of the original specification to the corresponding elements of the copied specification. This morphism can be denoted by translation-morphism
, without giving its domain, codomain, or rules, in a context in which these can be inferred (see Section 2.2). This can happen, for instance, in presenting an interpretation (see page 70 for an example).
3.2 Import
Another simple operation for constructing specifications in Slang is import
. The purpose of the import
operation is to enrich a specification with new sorts, operations, axioms, and theorems. The operation is not technically necessary--a specification generated with import
can also be constructed with other operations--but it is sometimes convenient. Example 3.2 Reflexive Relations.
The specification REFLEXIVE-RELATION
on page 34 is similar to BINARY
-RELATION
(see Example 2.5), except that it has an axiom and employs a different notation. In that example, we built the two specifications separately; however, when different specifications share structure in that way, it is wise to make the relationship explicit. For one thing, we save effort and reduce the chance of error, because we introduce each new concept once, not many times. Furthermore, any later change we make in the subspecification will be automatically reflected in the larger specification. These points will be evident in our larger examples.
In Example 3.1 of the previous section, the specification BINARY-RELATION
was translated so that its notation was made consistent with that of REFLEXIVE-RELATION
. We now use the import
operation to add the additional axiom:
spec REFLEXIVE-RELATION is
import
translate BINARY-RELATION by
{br -> rr}
axiom reflexive is
(rr e e)
end-spec
BINARY
-RELATION
; so may the sets with the proper subset relation Ã. A model of a specification assigns a meaning to each of its sorts and operations so that each of its axioms will be true.import
mechanism was used to extend a theory, by adding an axiom that restricted the models. For example, the reflexive axiom restricted the models of the specification BINARY
-RELATION
, because some binary relations are not reflexive. The nonnegative integers with <= are a model for REFLEXIVE
-RELATION
--the sets with à are not.(rcl br)
of a binary relation br
. spec REFLEXIVE-CLOSURE is
import BINARY-RELATION
op rcl : (E, E -> Boolean) -> (E, E -> Boolean)
definition of reflexive-closure is
axiom (iff ((rcl br) d e)
(or (br d e)(equal d e)))
end-definition
end-spec
BINARY
-RELATION
, because every binary relation has a reflexive closure. Thus this is a definitional extension of the binary relations.
Note that in this specification we are defining a higher-order operation
rcl
, which is applied to other operations. Its type is (E, E -> Boolean) -> (E, E -> Boolean)
(E, E -> Boolean)
import
in a specification (but see the discussion ``Import Abbreviations''on page 52). A specification term containing an import declaration (as in the example above) stands for a specification which contains all the elements of the imported specification together with any sorts, operations, axioms, or theorems added in the term.import
operation also constructs an import morphism which maps the elements of the imported specification to the corresponding elements of the importing specification. Rather than being spelled out explicitly, this morphism can be denoted simply by import-morphism
in a context in which the domain and codomain can be inferred (see Section 2.2), e.g., in an interpretation. This will be illustrated on page 70.
3.3 Application: Families of Specifications
While it is always possible to build up a large specification directly, there are many advantages to building it modularly from smaller components, as we have remarked. For one, we can see the relationship between various specifications--what they have in common and how they differ. If instead of building up these specifications from scratch separately, we develop them in a tree-like hierarchy, we can see immediately which axioms the theories share and which serve to distinguish between them.Example 3.3 Sets, Bags, and Sequences.
We need to develop three separate theories of finite collections of elements. These theories have a family resemblance. In each theory, all the elements are of the same sort and there is an empty collection and an insertion operation for introducing new elements to a collection. In each theory, every collection can be obtained by repeatedly inserting new elements to the empty collection. The theories differ, however, in whether the order of the elements or their multiplicity is regarded as significant.E
is the sort of upper-case letters, {X, Y}, {Y, X}, and {X, X, Y} are all the same set.COLLECTION
. In a collection, we do not say whether order or multiplicity is significant--that is unspecified. Thus we cannot prove that col(X, Y) and col(Y, X) are the same, but neither can we prove that they are distinct.SACK
, in which order is not significant but it is not specified whether multiplicity is significant. Thus, we can prove that sack(X, Y) and sack(Y, X) are the same but we cannot prove whether sack(X, Y) or sack(X, X, Y)are the same or distinct. Maybe so, maybe not. spec COLLECTION is
sorts E, Col
const empty-col : Col
op insert-col : E, Col -> Col
constructors {empty-col, insert-col} construct Col
theorem decomposition is
(implies (not (equal c empty-col))
(ex (e d)(equal c (insert-col e d))))
end-spec
empty-col
is the empty collection and (insert-col e c)
is the operation that inserts a new element e
into the collection c
. The collection that we informally write as col(d, e) is denoted in the theory by the term (insert-col d (insert-col e empty-col))
E
. It corresponds to an induction principle. There are no other explicit axioms. The decomposition theorem, which follows, says that every nonempty collection can be decomposed into the result of applying the insertion function to an element and a collection.spec SACK is
import
translate COLLECTION a
by {Col -> Sack,
empty-col -> empty-sack,
insert-col -> insert-sack}
op in-sack? : E, Sack -> Boolean
axiom empty is
(not (in-sack? e empty-sack))
axiom in-sack is
(iff
(in-sack? e (insert-sack d s))
(or (equal e d)
(in-sack? e s)))
axiom exchange is
(equal
(insert-sack e (insert-sack d s))
(insert-sack d (insert-sack e s)))
theorem retention is
(in-sack? e (insert-sack e s))
theorem conservation is
(not (equal empty-sack (insert-sack e s)))
end-spec
theorem decomposition is
(implies (not (equal s empty-sack))
(ex (e t)(equal s (insert-sack e t))))
c
and d
to s
and t
by hand to make the notation consistent with our other sack properties.)in-sack?
, for determining whether an element belongs to a sack. The axioms empty
and in
-sack
define the predicate. A third axiom exchange
asserts that the order in which elements are inserted into a sack is inconsequential. empty
and in-sack
are not merely definitions of the membership predicate--they extend the theory and restrict its models. They imply, for instance, the retention theorem, that the result of inserting an element into a sack does indeed contain that element; and hence the conservation theorem, that the empty sack is distinct from the result of inserting an element into a sack, because the empty sack has no members but the result of the insertion has at least one. Consequently, in contrast with the theory of collections, there is no model for the theory of sacks in which all sacks are equalspec SET is
import
translate SACK
by {Sack -> Set,
empty-sack -> empty-set,
insert-sack -> insert-set,
in-sack? -> in-set?}
axiom condensation is
(equal (insert-set e (insert-set e s))
(insert-set e s))
theorem equality is
(iff (equal s t)
(fa (e) (iff (in-set? e s)(in-set? e t))))
end-spec
spec BAG is
import
translate SACK
by {Sack -> Bag,
empty-sack -> empty-bag,
insert-sack -> insert-bag,
in-sack? -> in-bag?}
axiom uniqueness is
(implies
(equal (insert-bag e b) (insert-bag e c))
(equal b c))
end-spec
spec SEQ is
import
translate COLLECTION
by {Col -> Seq,
empty-col -> empty-seq,
insert-col -> prepend}
axiom conservation is
(not (equal (prepend e s) empty-seq))
axiom uniqueness is
(implies (equal (prepend e s) (prepend d t))
(and (equal e d) (equal s t)))
end-spec
prepend
; it is thought of as the operation that adds an element to the very beginning of a sequence (although nothing in the specification requires that, it could just as well be the end or middle). Note that the conservation property, which was a theorem for sacks, shows up as an axiom for sequences; without it there would be models for the theory in which all sequences are equal to the empty sequence. The uniqueness axiom for sequences is stronger than the uniqueness axiom for bags: it says that the only way the results of any two insertion operations can be equal is for both the corresponding new elements and the two original sequences to be equal. For instance, inserting the element X into a sequence never yields the same result as inserting the distinct element Y into a sequence. The analogous property for bags is false; for instance, inserting X into the bag {{Y}} gives the same result as inserting Y into the bag {{X}}.in-seq?
can be introduced by a definitional extension. This is in contrast to the theory of sacks, in which the axioms for in-sack?
were an essential part of the theory and restricted its models.
Figure 5: Family of Collection Theories
Note that a theorem associated with any of the nodes is also a theorem of any of its descendents, after translation into the appropriate vocabulary. This gives us a certain economy--for instance, we need to prove the decomposition theorem only once, not five or more times.3.4 Colimit
The colimit operation is the fundamental method in Slang for combining specifications. The operation takes a diagram of specifications as input and yields a specification, commonly referred to as the colimit (or apex) of the diagram. The colimit contains all the elements of the specifications in the diagram, but elements that are linked by arcs in the diagram are identified in the colimit.Figure 6: A Colimit
Figure 6 illustrates a colimit operation. On the left side is a diagram of four specifications, Sa through Sd, with morphisms between them. On the right side is the diagram with the colimit S. The dotted arrows represent cocone morphisms between the component specifications and the colimit.
Example 3.4 Preorders.
In the preorder diagram (Example 2.5), we indicated correspondences between elements of two specifications, REFLEXIVE
-RELATION
and TRANSITIVE
-RELATION
, by means of an intermediate specification, BINARY-RELATION
. By applying the colimit
operation to this diagram, we can combine these specifications, identifying the corresponding elements, to obtain a specification for PREORDER
, a theory of the reflexive, transitive relations. The combined specification will contain both the reflexive and transitive axioms.
spec BINARY-RELATION is
sort E
op br : E, E -> Boolean
end-spec
spec REFLEXIVE-RELATION is
import
translate BINARY-RELATION by
{br -> rr}
axiom reflexive is
(rr e e)
end-spec
spec TRANSITIVE-RELATION is
import
translate BINARY-RELATION by
{br -> tr}
axiom transitive is
(implies (and (tr c d) (tr d e))
(tr c e))
end-spec
diagram PREORDER-DIAGRAM is
nodes BINARY-RELATION, REFLEXIVE-RELATION, TRANSITIVE-RELATION
arcs BINARY-RELATION -> REFLEXIVE-RELATION :
{br -> rr},
BINARY-RELATION -> TRANSITIVE-RELATION :
{br -> tr}
end-diagram
spec PREORDER is
colimit of PREORDER-DIAGRAM
Figure 7: Colimit for PREORDER
The resulting specification PREORDER
will have a single sort that identifies the separate sorts and operations indicated by the morphisms. It is equivalent to the following specification:spec PREORDER is
sorts E
op pr : E, E -> Boolean
axiom reflexive is
(pr e e)
axiom transitive is
(implies (and (pr c d)(pr d e))
(pr c e))
end-spec
PREORDER
we have introduced new vocabulary; the relation operation is pr
. To get this effect, we may compose the colimit operation with a translation: spec PREORDER is
translate
colimit of PREORDER-DIAGRAM
by {br -> pr}
br
, rr
, and tr
, which are linked by morphisms of the diagram, are identified as a single operation pr
in the colimit.PREORDER-COLIMIT
, represent cocone morphisms.
The colimit specification and the cocone morphisms leading into it satisfy the property that the resulting diagram commutes. In other words, for every node in the diagram and for every sort or operation in the specification at that node, the translation of the sort or operation along any path leading from the node to the colimit specification is the same; thus, whatever path we follow from the operation
br
in the specification BINARY-RELATION
, we reach the same operation in PREORDER-COLIMIT
. Furthermore, the colimit specification only contains those sorts and operations which arise as the translations of some sort or operation in the specification at some node in the diagram.cocone-morphism from <node-name>
in a context in which the codomain can be inferred (see Section 2.2); the domain is indicated by <node-name>
.
``import colimit of diagram <diagram>''
can be abbreviated as ``import <diagram>.''
spec
import colimit of diagram
nodes <spec1>, <spec2>, ..., <specn>
end-diagram ...
end-spec
in which the diagram has no arcs, can be abbreviated as simply
spec import <spec1>, <spec2>, ..., <specn> ... end-spec
In the presence of sort axioms, it is possible for the basic equivalence classes to contain multiple constructed sorts. Hence, when using sort axioms, you must ensure that no two distinct constructed sorts are made equivalent: this would violate the freeness restriction--see the discussion of sort axioms in Section 1.3 on page 17.
As a special case of the colimit operation, if a diagram consists of just nodes with no arcs between them, the colimit is the disjoint union of the specifications labeling the nodes of the diagram. In other words, the equivalence classes are all singletons.
3.4.2 Colimit to Merge Elements
We have used the colimit operation to combine separate theories; morphisms indicate what elements of the theories are to be identified. The colimit operation can be used to identify two sorts or operations in a single specification. This is illustrated in the following example. Example 3.5 Binary Relations.
In our specification BINARY-RELATION
, the domain and codomain of our relations were of the same sort E
. Let us reconstruct this specification by assuming we have a specification BINARY-RELATION
-DISTINCT
, in which the domain and codomain may be of two different sorts, D
and E
respectively. We shall use the colimit operation to identify the two sorts D
and E
to obtain a specification equivalent to our BINARY-RELATION
, in which the domain and codomain of a relation are of the same sort.spec BINARY-RELATION-DISTINCT is
sorts D, E
op bd : D, E -> Boolean
end-spec
D
and E
, we introduce a specification ONE-SORT
with only a single sort. This specification is as follows: spec ONE-SORT is
sort X
end-spec
X
will be linked by two morphisms to D
and E
respectively; thus, all three sorts will be regarded as the same in the colimit. Actually, the colimit will have a single sort, the equivalence class {D,E,X}
. This class may also be referred to by the aliases D
, E
, and X
.spec BINARY-RELATION is
translate
colimit of
diagram
nodes ONE-SORT, BINARY-RELATION-DISTINCT
arcs ONE-SORT -> BINARY-RELATION-DISTINCT : {X -> D},
ONE-SORT -> BINARY-RELATION-DISTINCT : {X -> E}
end-diagram
by {bd -> br} colimit}
Figure 8: Binary Relation Colimit Diagram
Note that, as we mentioned earlier, there are two morphisms from ONE-SORT
to BINARY
- RELATION
-DISTINCT
:
X
into D
.
X
into E
.
D
and E
are collapsed into a single sort. As we saw in the previous example, the vocabulary for the colimit (br
instead of bd
) is introduced in a subsequent translation phase.
E
(Section 3.3on page 41). We shall now give a specification PAIR
for pairs [d
, e
], where d
and e
are of sorts D
and E
, respectively. We shall then use the colimit operation to construct a specification SET-OF-PAIRS
for sets whose elements are all pairs.
The specification for pairs, as on page 29, is as follows:
spec PAIR is
sorts D, E, Pair
op make-pair : D, E -> Pair
op first : Pair -> D
op second : Pair -> E
axiom (equal (first (make-pair d e)) d)
axiom (equal (second (make-pair d e)) e)
constructors {make-pair} construct Pair
theorem (equal p (make-pair (first p) (second p)))
end-spec
Pair
. The operation make-pair
constructs a pair from two elements; the two functions first
and second
extract the first and second components, respectively, from a pair.E
, the sort of the elements of the sets, the same as Pair
, the sort of the pairs. For this purpose, we introduce a third specification, the theory ONE-SORT
we used in the previous example, to indicate the sorts that are to be identified. This was the specification with a single sort X
and no operations or axioms. Two morphisms identify X
with the sort E
of SET
and the sort Pair
of PAIR
, respectively.spec SET-OF-PAIRS is
translate
colimit of
diagram
nodes ONE-SORT, SET, PAIR
arcs
ONE-SORT -> SET : {X -> E},
ONE-SORT -> PAIR : {X -> Pair}
end-diagram
by {Set -> Set-of-Pairs,
empty-set -> empty-set-of-pairs,
insert-set -> insert-set-of-pairs,
in-set? -> in-set-of-pairs?}
set-of-pairs
. Thus, the empty set in this specification is called empty-set-of-pairs
. A diagram of the essentials of the colimit is given in Figure 9.
Figure 9: Set-of-Pairs Colimit Diagram
The specification obtained by taking the colimit is equivalent to one presented directly in Figure 10.
spec SET-OF-PAIRS is
sorts Set-of-Pairs, Pair, D2, D1
op in-set-of-pairs: Pair, Set-of-Pairs -> Boolean
op insert-set-of-pairs: Pair, Set-of-Pairs -> Set-of-Pairs
const empty-set-of-pairs: Set-of-Pairs
op second: Pair -> D2
op first: Pair -> D1
op make-pair: D1, D2 -> Pair
constructors {empty-set-of-pairs, insert-set-of-pairs}
construct Set-of-Pairs
constructors {make-pair} construct Pair
conjecture equality is
(fa (t s)
(iff
(equal s t)
(fa (e) (iff (in-set-of-pairs e s) (in-set-of-pairs e t)))))
axiom condensation is
(fa (s e)
(equal
(insert-set-of-pairs e (insert-set-of-pairs e s))
(insert-set-of-pairs e s)))
theorem conservation is
(fa (s e)
(not (equal empty-set-of-pairs (insert-set-of-pairs e s))))
theorem retention is
(fa (s e) (in-set-of-pairs e (insert-set-of-pairs e s)))
axiom exchange is
(fa (s d e)
(equal
(insert-set-of-pairs e (insert-set-of-pairs d s))
(insert-set-of-pairs d (insert-set-of-pairs e s))))
axiom in-sack is
(fa (s d e)
(iff
(in-set-of-pairs e (insert-set-of-pairs d s))
(or (equal e d) (in-set-of-pairs e s))))
axiom empty is
(fa (e) (not (in-set-of-pairs e empty-set-of-pairs)))
theorem decomposition is
(fa (c)
(implies
(not (equal c empty-set-of-pairs))
(ex (e d) (equal c (insert-set-of-pairs e d)))))
conjecture
(fa (x) (equal x (make-pair (first x) (second x))))
axiom (fa (x2 x1) (equal (second (make-pair x1 x2)) x2))
axiom (fa (x2 x1) (equal (first (make-pair x1 x2)) x1))
end-spec
Figure 10: Specification of Sets of Pairs Defined Directly
This specification combines axioms from the two specifications. Note that, as our specifications grow larger, it becomes more economical to use the colimit and other specification-constructing operations than to define specifications directly.3.4.4 Qualified Names
As explained above, the sorts and operations in a colimit specification are equivalence classes. Each such sort or operation inherits all the names of its elements as aliases, and may be referred to (in a specification which imports the colimit) by any one of these aliases. However, it is frequently the case that the name of an element of an equivalence class does not uniquely determine the class. This can occur when more than one node in the diagram for the colimit is associated with the same specification.<qualifier>.<name>
. The qualifier is the name of a node in the diagram used to construct the colimit. The denotation of such a qualified name is the equivalence class that contains the sort or operation denoted by the unqualified name in the specification attached to the qualifier node. Qualified names need not be used if a sort (or operation) name alone uniquely identifies an equivalence class. This is true even if the equivalence class contains many names.Example 3.7 Double Binary Relations.
To illustrate the need for qualified names, consider the following specification, in which two binary relations are defined on the same sort. spec DOUBLE-BINARY-RELATION is
colimit of
diagram
nodes A: ONE-SORT,
B: BINARY-RELATION,
C: BINARY-RELATION
arcs A -> B : {X -> E},
A -> C : {X -> E}
end-diagram
ONE-SORT
. Two morphisms map the sort X
of ONE-SORT
into the two copies of the sort E
of BINARY-RELATION
, forcing them to be the same; the two copies of the relation br
are not linked, and hence are taken to be distinct.{E,X}
, with aliases E
and X
, and two operations with the same name and sort: br : {E,X}, {E,X} -> Boolean
DOUBLE-BINARY-RELATION
, we want to refer to these operations, we have to use qualified names, B.br
and C.br
, to distinguish the two copies. For example, we could rename these operations and require that they be inverses: spec FAMILY is
import
translate DOUBLE-BINARY-RELATION
by {E -> People,
B.br -> parent,
C.br -> child}
axiom (iff (parent x y) (child y x))
end-spec
<qualifier>.<qualifier>....<qualifier>.<name>
3.4.5 Consistency of Colimits
It is possible to use the colimit operation to construct an inconsistent theory, even if all the component specifications in the diagram are themselves consistent. This can happen when the axioms from the component theories contradict each other. zero
and one
. We specify the combination by the following colimit:spec SEQ-SET is
import
colimit of diagram
nodes COLLECTION, SEQ, SET, ONE-SORT, BIT
arcs
ONE-SORT -> BIT : {X -> Bit},
ONE-SORT -> COLLECTION : {X -> E},
COLLECTION -> SEQ :
{Col -> Seq,
empty-col -> empty-seq,
insert-col -> prepend},
COLLECTION -> SET :
{Col -> Set,
empty-col -> empty-set,
insert-col -> insert-set}
end-diagram
theorem (equal one zero)
theorem (not (equal one zero))
end-spec
E
.) Hence collections in the colimit have properties of both sequences and sets. Also the elements of the three specifications are linked, via the specification ONE-SORT
, with the bits; the specification for bits is as follows:spec BIT is
sort Bit
op zero : Bit
op one : Bit
axiom (not (equal zero one))
constructors {zero, one} construct Bit
end-spec
zero
and one
; the axiom ensures that these elements are distinct, and the constructor set guarantees that there are no others.zero
and one
are not equal is the axiom of the specification BIT
, which has been inherited via the colimit mechanism. That they are equal follows because, by axioms of the sets, col
(zero
, one)
is equal to col
(one
, zero)
. But then, by the uniqueness axiom for sequences, zero
equals one
.
Part II Refinement Constructs in Specware
The principal technique for software design and development in Specware is a process of refinement of a problem (or source) specification into a solution (or target) specification. Refinements replace behavioral constraints with algorithms and abstract data structures with implementations. Source and target specification as well as the refinements between them are precise, formal objects. Slang's refinement constructs, introduced and defined in subsequent chapters, address three important aspects of refinement:
In Specware, refinement of specifications proceeds by induction on the specification structure; in other words, we define the refinement of a structured specification, which has been defined by specification-constructing operations, in terms of the refinements of its components.
The next section gives an overview of refinement of basic specifications and the following section gives an overview of the refinement of structured specifications. These notions are more fully discussed in Section 5. It will then be seen that refinement of structured specifications requires a systematic lifting of specification notions (specifications, specification morphisms, and specification-constructing operations) to corresponding refinement notions (interpretations, interpretation morphisms, and interpretation-constructing operations).
Convention. All the morphisms and diagrams we treated in Part I were specification morphisms and diagrams. In Part II, we shall encounter other kinds of morphisms and diagrams, e.g., interpretation morphisms and interpretation diagrams. We have the convention, however, that when ``morphism'' or ``diagram'' is used without a qualifier, it means ``specification morphism'' or ``specification diagram,'' respectively. Other uses are qualified with the kind of objects involved.
4.1 Refinement of Basic Specifications
The basic refinement construct in Slang is an interpretation (see Section 5). Interpretations generalize morphisms as follows.
We have seen (Section 2.2) that a morphism from specification S to specification T maps the sorts, operations, and axioms of S into sorts, operations, and theorems, respectively, of T. We have also seen (Section 3.2) that a definitional extension of T is a specification that contains all the sorts, operations, and axioms of T plus definitions of additional sorts and operations. An interpretation from S to T, then, is a morphism from S into a mediator, often called S-as-T, which is a definitional extension of T. We shall then also say that T is a refinement of S. The words ``refinement'' and ``interpretation'' are synonymous.
For example, in the next section we implement sets in terms of bags. Under the interpretation we construct, each set corresponds to a bag with no repeated elements. In the basic specification for bags, there is no sort corresponding to bags with no repeated elements. Therefore, we define this sort in a mediator that is a definitional extension of the specification for bags. The morphism then maps the sort of sets in the source into this new sort in the mediator.
4.2 Refinement of Structured Specifications
We systematically exploit the specification structure to construct interpretations for complex specifications.5 Interpretations and their Composition
We first introduce the syntax for interpretations in Slang and illustrate with some examples. Subsequently, we discuss the sequential (vertical) and parallel (horizontal) composition of interpretations. The parallel compositions, i.e., the gluing of interpretations from pieces, requires us to consider interpretation morphisms and a generalization of interpretations, interpretation schemes. Parallel composition requires that the refinement components be compatible. This compatibility notion is made precise in Section 5.4.
Before we give the definition of an interpretation, let us give a more technical treatment of the notion of a definitional extension.
5.1 Definitional Extensions
An interpretation from S into T is a morphism from S into a definitional extension of T. We have already introduced definitional extensions informally (Section 3.2). Now let us go over the same material more formally.
For two specifications S and T, a morphism S to T is a strict definitional extension if it is injective (one-to-one) and if every sort or operation of T that is outside the image of the morphism is defined in terms of elements that are inside the image. A definitional extension is a strict definitional extension optionally composed with a specification isomorphism. (An isomorphism is an injection whose image includes all the elements of the specification, e.g., a translation.)
5.2 Basic Interpretations
Now that we have discussed definitional extensions, we can give the definition of an interpretation. Definition 5.1: Interpretation.
An interpretation with domain (or source) specification S and codomain (or target) specification T has several components:
Typically, the mediator S-as-T will import the target T and add whatever definitions are necessary to provide images or representations for the elements of S. If the target morphism were not a definitional extension, there would be no guarantee that we could use the interpretation to provide implementations for elements of the source specification.
A prototypical example of a named Slang interpretation is of the form
interpretation s-to-t: S => T is
mediator S-as-T
dom-to-med s
cod-to-med t
Note the use of the double arrow instead of a single arrow, to indicate an interpretation rather than a morphism.
A graphical rendering of this construct is as follows:
Because any specification can be regarded as a definitional extension of itself, any morphism can be the source morphism of an interpretation whose target morphism is the identity. In this sense, the notion of interpretation is considered to be a generalization of the notion of a morphism. Usually, though, we must extend the target specification with definitions of new sorts and operations to serve as images of the elements of the source specification.
Our specification for sets was given on page 45. It provided a constant
empty-set
, an operation insert-set
for adding a new element into a set, and a predicate in-set
- for determining whether an element belongs to a set. Our specification for bags was given on page 45. It provides a constant empty-bag
, an operation insert-bag
, and a predicate in-bag
- analogous to those for sets.Set
into Bag
, empty-set
into empty-bag
, insert-set
into insert-bag
, and so forth, because the condensation axiom for sets, which says that inserting an element twice in succession into a set is the same as inserting it once, will then translate into a sentence that is not true of bags. Instead, our specification for bags is augmented in the mediator with a new sort, Set-as-Bag
, which corresponds to bags with no duplicated elements. We also introduce operations on this sort that allow us to mimic the set operations. The axioms for sets will be translated into sentences that do hold for the new sort and operations. The extended specification, SET-AS-BAG, is given in Figure 11.
spec SET-AS-BAG is
import BAG
sort Set-as-Bag
op no-dup-bag? : Bag -> Boolean
definition of no-dup-bag? is
axiom (no-dup-bag? empty-bag)
axiom (iff (no-dup-bag? (insert-bag e b))
(and (not (in-bag? e b)) (no-dup-bag? b)))
end-definition
sort-axiom Set-as-Bag = Bag | no-dup-bag?
op bag-of-s-as-b : Set-as-Bag -> Bag
definition of bag-of-s-as-b is
axiom (equal bag-of-s-as-b (relax no-dup-bag?))
end-definition
const empty-s-as-b : Set-as-Bag
op insert-s-as-b : E, Set-as-Bag -> Set-as-Bag
op in-s-as-b? : E, Set-as-Bag -> Boolean
definition of empty-s-as-b is
axiom (equal (bag-of-s-as-b empty-s-as-b) empty-bag)
end-definition
definition of insert-s-as-b is
axiom (implies (in-bag? e (bag-of-s-as-b sb))
(equal (bag-of-s-as-b (insert-s-as-b e sb))
(bag-of-s-as-b sb)))
axiom (implies (not (in-bag? e (bag-of-s-as-b sb)))
(equal (bag-of-s-as-b (insert-s-as-b e sb))
(insert-bag e (bag-of-s-as-b sb))))
end-definition
definition of in-s-as-b? is
axiom (equal (in-s-as-b? e sb)
(in-bag? e (bag-of-s-as-b sb)))
end-definition
constructors {empty-s-as-b, insert-s-as-b} construct Set-as-Bag
end-spec
Figure 11: Specification for Sets Represented as Bags
no-dup-bag?
to determine whether a bag has no multiple occurrences of elements. That predicate is used to define Set-as-Bag
, the subsort of bags that satisfy no-dup-bag?
. We define bag-of-s-as-b
to be the function (relax no-dup-bag?)
, which maps x viewed as an element of the subsort Set-as-Bag
into x viewed as an element of Bag
.empty-set
, insert-set
, and in-set
?, respectively. For instance, the constant empty-s-as-b
is defined to be the empty bag, viewed as an element of the subsort. Finally we introduce a constructor set for Set-as-Bag
, to serve as the image for the constructor set of the set specification.SET-AS-BAG
. The source morphism, which maps the source into the mediator, will be morphism SET-TO-BAG : SET -> SET-AS-BAG is
{Set -> Set-as-Bag,
empty-set -> empty-s-as-b,
insert-set -> insert-s-as-b,
in-set? -> in-s-as-b?}
Therefore our entire interpretation is
interpretation SET-TO-BAG : Set => Bag is
mediator SET-AS-BAG
dom-to-med SET-TO-BAG
cod-to-med import-morphism
{}
instead of import
-morphism
; this would give the same result because the import morphism maps each element of the target into the same element in the mediator. However, if there were more than one element with the same name, it would be ambiguous to say {}.
Example 5.3 Interpretation of Bags as Sequences.
In our next example, we refine bags into sequences. This example illustrates the use of a quotient sort--each bag is mapped into an equivalence class of sequences, all of them permutations of each other. For example, the bag {{X, Y}} will be mapped into a class of two sequences, [X, Y] and [Y, X]. But the example is also of interest because we shall subsequently compose it with our previous refinement, from sets to bags--our first example of the (sequential) composition of interpretations. The composition will then refine sets into sequences. For example, the set {X, Y} will be represented by the equivalence class of two sequences, [X, Y] and [Y, X]. If we have an implementation for sequences, the composition will give us an implementation for sets.exchange
axiom for sacks and bags would map into an untrue sentence about sequences. Instead, just as we did when we represented sets as bags, we augment the sequence specification to include sorts and operations that allow us to mimic bags and bag operations. The extended specification, BAG-AS-SEQ, is given in Figure 12.
In this specification, we introduce a function
count(x s)
to count how many times the element x
occurs in the sequence s
. Rather than returning a nonnegative integer n as the answer--we have not imported a specification for the nonnegative integers--we return a sequence containing exactly n occurrences of x
. Thus (count
X ([X, X, Y]) = [X, X]perm?
that determines whether two sequences are permutations of each other. It does this using the count
function to see if every element occurs exactly the same number of times in each sequence. This defines an equivalence relation on the sequences.Bag
-as-Seq
is then defined to be the quotient of the sequences by the permutation relation. The function b-as-s-of-seq
is defined to be the quotient function that maps each sequence into its corresponding equivalence class.empty-b-as-s
, the function insert-b-as-s
, and the predicate in-b-as-s?
to be the analogues for equivalence classes to empty-bag
, insert-bag
, and in-bag?
, respectively, for bags. Each of these elements of the augmented specification for sequences will serve as the implementation of its analogue for bags. Because we have not introduced a membership function in-seq?
into our specification for sequences, we must define the implementation predicate in-b-as-s?
explicitly in the mediator. We also introduce a constructor set for Bag-as-Seq
, to serve as the image for the constructor set for Bag
.morphism BAG-TO-SEQ : BAG -> BAG-AS-SEQ is
{Bag -> Bag-as-Seq,
empty-bag -> empty-b-as-s,
insert-bag -> insert-b-as-s,
in-bag? -> in-b-as-s?}
interpretation BAG-TO-SEQ : BAG => SEQ is
mediator BAG-AS-SEQ
dom-to-med BAG-TO-SEQ
cod-to-med import-morphism
import-morphism
by{}
.spec BAG-AS-SEQ is
import SEQ
op count : E, Seq -> Seq
definition of count is
axiom (equal (count e empty-seq) empty-seq)
axiom (equal (count e (prepend e s)) (prepend e (count e s)))
axiom (implies (not (equal e d))
(equal (count e (prepend d s)) (count e s)))
end-definition
op perm? : Seq, Seq -> Boolean
definition of perm? is
axiom (iff (perm? s t)
(fa (e) (equal (count e s) (count e t))))
end-definition
sort Bag-as-Seq
sort-axiom Bag-as-Seq = Seq/perm?
op b-as-s-of-seq : Seq -> Bag-as-Seq
definition of b-as-s-of-seq is
axiom (equal b-as-s-of-seq (quotient perm?))
end-definition
const empty-b-as-s : Bag-as-Seq
op insert-b-as-s : E, Bag-as-Seq -> Bag-as-Seq
op in-b-as-s? : E, Bag-as-Seq -> Boolean
definition of empty-b-as-s is
axiom (equal empty-b-as-s (b-as-s-of-seq empty-seq))
end-definition
definition of insert-b-as-s is
axiom (equal (insert-b-as-s e (b-as-s-of-seq s))
(b-as-s-of-seq (prepend e s)))
end-definition
definition of in-b-as-s? is
axiom (not (in-b-as-s? e empty-b-as-s))
axiom (iff (in-b-as-s? e (insert-b-as-s d bs))
(or (equal e d) (in-b-as-s? e bs)))
end-definition
constructors {empty-b-as-s, insert-b-as-s} construct Bag-as-Seq
end-spec
Figure 12: Specification for Sequences Augmented to Represent Bags
Example 5.4 Interpretation of Sequences as Arrays.
In our next example, we shall implement sequences as arrays. Our arrays are actually one-dimensional vectors of entries a[0], . . ., a[n-1]. Sequences will be represented as arrays in reverse order; in other words, the first element of the sequence will be the last element of the array, and vice versa. This is because it is easier to add an element to a sequence at the beginning, via the operation prepend
, but it is easier to add an element to an array at the end. NAT
for the nonnegative integers (see Appendix D, page 158) to provide the indices. As we have seen, arrays are indexed from 0 to n-1, where n is the size of the array, just the way the floors of European buildings are numbered. We distinguish between ordinary static arrays (in the specification ARRAY
), whose size is fixed, and dynamic arrays (in the specification DYNAMIC-ARRAY
), which can be extended. To implement sequences we use dynamic arrays, so that we can always add new elements to the end.
Some of the operations in the specification of static arrays are:
make-array
: The function (make-array n e)
constructs an array of size n
, each of whose elements is initialized to e
.
access-array
: The function (access-array a i)
returns the i
th element (``a[i]'') of the array a
. The integer i
must be within the bounds of the array, that is, between 0 and n-1 inclusively, where n is the size of a
.
update-array
: The function (update-array a i e)
returns a new array, which is identical to a
except that its i
th element is e
. Again the integer i
must be within the bounds of the array.
empty-array
: The constant empty-array
is the array of size 0, with no elements.
extend-array
: The function (extend-array a e)
returns a new array, which is identical to a
except that it is one element larger, of size n+1
; its final (n
th) element is e
.
empty-s-as-a
and prepend-s-as-a
that mimic the sequence operations empty
and prepend
, respectively. The constant empty-s-as-a
is identified with the constant empty-array
; the function prepend-s-as-a
is defined in terms of the array function extend-array
. The resulting mediator specification SEQ-AS-ARRAY
is as follows:
spec SEQ-AS-ARRAY is
import translate DYNAMIC-ARRAY
by {empty-array -> empty-s-as-a}
op prepend-s-as-a : E, Array -> Array
definition of prepend-s-as-a is
axiom (equal
(prepend-s-as-a e a)
(extend-array a e))
end-definition
constructors {empty-s-as-a, prepend-s-as-a} construct Array
end-spec
The operation
prepend-s-as-a
, which will correspond to the operation prepend
, places the new element e
at the end of the array rather than the beginning. If we visualize sequences and arrays in the usual way, this has the effect of reversing the order of a sequence when it is represented as an array.The interpretation that maps basic sequences into arrays is then simply
interpretation SEQ-TO-ARRAY : SEQ => DYNAMIC-ARRAY is
mediator SEQ-AS-ARRAY
dom-to-med {Seq -> Array,
empty-seq -> empty-s-as-a,
prepend -> prepend-s-as-a}
cod-to-med {empty-array -> empty-s-as-a} to-array}
We represent sets of sort
E
, where E
is finite, by bit vectors of size k, where k is the number of elements of sort E
. If we number all the elements of sort E
as e0 through ek-1, a set s will be represented by a bit vector v, where e1 belongs to s if and only if the ith element of the bit vector is 1. This is a practical way of representing sets if E
is not too large.For instance, if
E
is the integers from 0 through 7, numbered in order, the bit vector [0, 1, 0, 1, 0, 0, 1, 0], in which the first, third, and sixth elements are 1, represents the set {1, 3, 6}. This is illustrated in the following display:We shall regard bit vectors as arrays whose elements are bits. Because we shall not need to make the bit vectors longer, we may use static rather than dynamic arrays. We have already seen the specification for sets in Section 3.3, page 41; the specification for static arrays is in Appendix E, page 160. The specification for bit vectors also depends on the specification for bits, which was given in Section 3.4.5, page 60. It says that there are two, and only two, distinct bits, denoted by
zero
and one
.
A bit vector, then, is an array whose elements are of sort
Bit
: spec BIT-VECTOR is
colimit of
diagram
nodes ONE-SORT, ARRAY, BIT
arcs ONE-SORT -> ARRAY : {X -> E},
ONE-SORT -> BIT : {X -> Bit}
end-diagram
E
into bit vectors all of the same size as E
. Under this refinement, E
will be identified with a sort of those nonnegative integers less than the size of E
; each element of sort E
will be identified with a different number. For this reason, we augment the bit-vector specification, obtaining a new specification BIT-VECTOR-FIXED
, which describes bit vectors all of the same size, size-vector
.BIT-VECTOR-FIXED
is given in the appendix (Section E, page 160). It contains the constant size-vector
, the length of a bit vector, and a sort Interval
, defined by the sort axiom
Interval = Nat | in-interval?
in-interval?
holds for nonnegative integers strictly less than size
-vector
. The sort Interval
will serve as the implementation for E
under the interpretation.Bit-Vector-Fixed
is then defined by the sort axiom Bit-Vector-Fixed = Array | of-given-size?
of-given-size
holds for arrays whose size is exactly size-vector
.update
-bvf
, access-bvf
, and others; the definitions relate the bit-vector operations and the corresponding array operations via the operator relax
.spec SET-AS-BIT-VECTOR-FIXED is
import BIT-VECTOR-FIXED
const empty-s-as-bvf : Bit-Vector-Fixed
definition of empty-s-as-bvf is
axiom (equal empty-s-as-bvf (make-bvf BIT.zero))
end-definition
op insert-s-as-bvf : Interval, Bit-Vector-Fixed
-> Bit-Vector-Fixed
definition of insert-s-as-bvf is
axiom (equal (insert-s-as-bvf i v)
(update-bvf v i BIT.one))
end-definition
op in-s-as-bvf? : Interval, Bit-Vector-Fixed -> Boolean
definition of in-s-as-bvf? is
axiom (iff (in-s-as-bvf? i v)
(equal (access-bvf v i) BIT.one))
end-definition
constructors {empty-s-as-bvf, insert-s-as-bvf} construct
Bit-Vector-Fixed
end-spec
empty-s-as-bvf
is defined to be the array of length size-vector
all of whose elements are zero
. Note that the definition refers to BIT.zero
to distinguish it from NAT.zero
. insert-s-as-bvf
implements the operation of inserting the element i
into the set represented by the bit vector v
by setting the i
th element of v
to one
. in-s-as-bvf?
implements the membership predicate; it tests if i
is in the set represented by v
by checking whether the i
th bit of v
is one
.interpretation SET-TO-BIT-VECTOR-FIXED :
SET => BIT-VECTOR-FIXED is
mediator SET-AS-BIT-VECTOR-FIXED
dom-to-med
{E -> Interval,
Set -> Bit-Vector-Fixed,
empty-set -> empty-s-as-bvf,
insert-set -> insert-s-as-bvf,
in-set? -> in-s-as-bvf?}
cod-to-med import-morphism
5.3 Sequential Composition of Interpretations
Sequential composition allows us to follow one interpretation with another; in this way, we can develop a system by successive refinement of its specification. But it is not immediately obvious that the composition of two interpretations is an interpretation. Why? What is the mediator of the composed intepretation? What is its target morphism and why is it a definitional extension? These questions are answered in this section; we also provide an example.Definition 5.6: Sequential (Vertical) Composition of Interpretations.
Suppose rr1 and rr2 are two interpretations such that rr1 : R=> S and rr2 : S => T. Then their sequential composition rr1 ; rr2 : R => T is indicated by the vertical arrows in the following diagram:Example 5.7 Interpretation of Sets as Sequences
As an example of the sequential composition of two interpretations, consider the interpretation of sets as bags in Example 5.2, page 70, together with the interpretation of bags as sequences in Example 5.3, page 72.
These two interpretations can be composed to yield an interpretation from sets to sequences. In the notation of the previous discussion, we simply take R to be
SET
, S to be BAG
, and T to be SEQ
. We obtain the following configuration:SET-AS-BAG-AS-SEQ
, is obtained by taking the following colimit: spec SET-AS-BAG-AS-SEQ is
colimit of
diagram
nodes BAG, SET-AS-BAG, BAG-AS-SEQ
arcs BAG -> SET-AS-BAG : import-morphism,
BAG -> BAG-AS-SEQ : BAG-TO-SEQ
end-diagram
SET-TO-BAG
from the first given interpretation SET-TO-BAG
, which takes sets (in SET
) into bags with no duplicated elements (in SET-AS-BAG
).
SET-AS-BAG
) into the corresponding equivalence classes of sequences (in SET
-AS-BAG-AS-SEQ
).
morphism SET-TO-SEQ : SET -> SET-AS-BAG-AS-SEQ is
{Set -> Bag-as-Seq,
empty-set -> empty-b-as-s,
insert-set -> insert-b-as-s,
in-set? -> in-b-as-s?}
The target morphism for the composition is also the composition of two morphisms:
BAG-TO-SEQ
, which is the import morphism and takes sequences in SEQ
into sequences in the extended interpretation BAG-AS-SEQ
.
BAG-AS-SEQ
into sequences in SET-AS-BAG-AS-SEQ
.
{}
, with the appropriate domain and codomain, and so is their composition.
The sequential composition of the two interpretations is then
interpretation SET-TO-SEQ : SET => SEQ is
mediator SET-AS-BAG-AS-SEQ
dom-to-med SET-TO-SEQ
cod-to-med {}
In addition to refining its component specifications, we can also change the shape of the given diagram itself. For example, we might begin with a diagram with three morphisms between four specifications and end with a diagram with two morphisms between three specifications. This could happen because we may need to identify components that are distinct in the given diagram of specifications. Thus, to perform a parallel composition we have to say how the shape of the given diagram of specifications is to change.
A parallel composition is illustrated in Figure 13.
Figure 13: A Parallel Composition
5.4.1 Interpretation Schemes
For parallel composition, it is necessary to introduce a generalization of an interpretation called an interpretation scheme (ip-scheme). An interpretation scheme has the same structure as an interpretation, but the target morphism can be an arbitrary morphism; it need not be a definitional extension.Example 5.8 Interpretation Scheme.
The following is an interpretation scheme from the simple specification ONE-SORT
into itself. Its mediator is a specification TWO-SORT
-QUOTIENT
with two sorts, one a quotient of the other, as follows:spec TWO-SORT-QUOTIENT is
sorts B, Q
op r? : B, B -> Boolean
sort-axiom Q = B / r?
end-spec
r?
is an undefined binary relation on B
, and Q
is the quotient of B
modulo r?
. The specification does not restrict the meaning of the sorts B
and Q
and the operation r?
except to assert the quotient relationship in the sort axiom.interpretation ONE-SORT-VIA-QUOTIENT :
ONE-SORT => ONE-SORT is
mediator TWO-SORT-QUOTIENT
dom-to-med {X -> Q}
cod-to-med {X -> B}
X
in the domain specification ONE-SORT
is identified with the quotient, modulo r?
, of the sort X
in the codomain specification ONE-SORT
.r?
, which is outside the image of the target morphism {X->B}
, is not defined, the target morphism is not a definitional extension, and the interpretation scheme is not an interpretation.5.4.2 Interpretation Morphisms
Up to now, we have applied the colimit operation only to specifications. To define the parallel composition of interpretations, we must employ a colimit of interpretations instead. Definition 5.9: Interpretation Morphism.
An interpretation morphism from an interpretation rr1 : S1 => T1 to another interpretation rr2 : S2 => T2 is a triple of specification morphisms such that the diagram on the right below commutes. Figure 14: An Interpretation Morphism
Example 5.10 Interpretation-Scheme Morphism.
Figure 14 illustrates an interpretation-scheme morphism, called ONE
-SORT
-SEQ
-QUOTIENT
. The target of this morphism in the interpretation BAG-TO-SEQ
, from bags to sequences, that we have seen in Section 5.3, page 72. The source of this morphism is the interpretation scheme ONE
-SORT
-VIA
-QUOTIENT
, from ONE-SORT
into itself, that we saw in the preceding section. The top part of the figure shows some of the details of the morphism--the bottom part is a summary.
Note that the diagram for the interpretation-scheme morphism commutes, as it must. For a morphism to exist between two interpretations or ip-schemes, they must be in a certain sense analogous. Each morphism between specifications at the source (upper) level is mapped into an appropriate morphism at the target (lower) level.
X
in ONE-SORT
gets mapped into the quotient sort Q
in TWO-SORT-QUOTIENT
, just as, in the target interpretation, Bag
in BAG
gets mapped into the quotient sort Bag-as-Seq
in BAG-AS-SEQ
. The morphism {X -> Q}
from ONE-SORT
into TWO-SORT-QUOTIENT
at the source level is mapped into the morphism that included the replacement Bag -> Bag-as-Seq
from BAG
into BAG-AS-SEQ
at the target level. This is as it must be, because the interpretation-scheme morphism maps the sort X
in ONE-SORT
into the sort Bag
in BAG
, and the sort Q
into the sort Bag-as-Seq
. Otherwise the diagram would not commute.ip-scheme-morphism ONE-SORT-SEQ-QUOTIENT :
ONE-SORT-VIA-QUOTIENT -> BAG-TO-SEQ is
domain-sm morphism ONE-SORT -> BAG is {X -> Bag}
mediator-sm morphism TWO-SORT-QUOTIENT -> BAG-AS-SEQ is
{(r?: B, B -> Boolean) -> (perm?: Seq, Seq -> Boolean),
Q -> Bag-as-Seq,
B -> Seq}
codomain-sm morphism ONE-SORT -> SEQ is {X -> Seq}
ONE-SORT
into itself, instead of the interpretation scheme ONE-SORT-VIA-QUOTIENT
. We are attempting to find an interpretation morphism from the identity into the interpretation BAG-TO-SEQ
. Figure 15 illustrates a partially filled-in interpretation morphism.
Figure 15: A Failed Interpretation Morphism
X
(on top) into any of the sorts of BAG-AS
-SEQ
(on the bottom) and obtain a commuting diagram. If we map it into Seq
, the left square does not commute; if we map it into Bag-as
-Seq
, the right square does not commute. The nonexistence of certain interpretation morphisms is related to the issue of compatibility in parallel composition of interpretations, as we shall see.5.4.3 Categories
In developing the notion of an interpretation morphism, we have lifted the concept of a morphism from the category of specifications and applied it to another category of objects, that of interpretations. In fact, the notion of category can be given a precise mathematical meaning, so that concepts that are introduced for an abstract category can be immediately applied to specific instances of that category.Definition 5.11: Category.
A category is an abstract mathematical structure with several components:
The composition operation is associative; that is, given the configuration
of objects and arrows, we have
(f ; g) ; h = f ; (g ; h)
The identity arrow must satisfy the identity property, namely, for all
arrows f and g with the configurations
we have
Let us give some examples of categories.
Sets are so pervasive that it is easy to forget that there are categories in which the objects are not sets. One such is the category of shapes.
The composition of two arrows is an arrow with the following configuration
Here the long arrow is the composition of the two short arrows.
The identity arrow is an arrow from a dot to itself:
Note that shapes are a multigraph; in other words, there may be more than one arrow between the same pair of dots. Of the several arrows between a dot and itself, one of them is designated as the identity for that dot.
Because objects in category theory are not necessarily sets, definitions in category theory must avoid relying on set properties of objects, although set-theoretic concepts do motivate some of the notions of category theory.
Definition 5.16: Diagram Refinement. A diagram refinement <bb,ss> has two components:
A diagram refinement can be regarded as an interpretation between diagrams of specifications. In the figure, d1 and d2 are two diagrams of specifications, which assign a specification from Spec to each of the nodes of the shapes I1 and I2, and a morphism to each of its arrows. Also, dom and cod map interpretations into their corresponding domains and codomains. The diagram refinement can be viewed as an interpretation whose domain is the diagram d1and whose codomain is the diagram d2.
Here d1 is a diagram of four specification, S1a through S1d, with shape I1. (We omit the morphisms between them.) For these specifications there are interpretations rra through rrd that map them into specifications S2a through S2d, respectively. As it turns out, the specifications S2b and S2c are the same.
The mapping dd is a diagram of the four interpretations rra through rrd --we omit the interpretation morphisms between them. The mapping ss is a shape mapping--it maps the shape of four nodes I1 into the shape of three nodes I2, collapsing the two nodes with the same specification. The pair <dd,ss> constitutes a diagram refinement.
The mapping d2 is a diagram of three specifications, S2a, S2b (= S2c), and S2c, with shape I2. The diagram refinement can be thought of as an interpretation from the diagram d1 into the diagram d2. Note that the composition ss ; d2 of the shape mapping ss with the diagram d2 can also be viewed as a diagram with shape I1, labeled with the four specifications S2a through S2d; we shall refer to this as the intermediate diagram. Thus hidden in the figure we actually have three specification diagrams, d1, ss ; d2, and d2, and a diagram of interpretations dd.
In the following definition, we invoke the notation of the definition of a diagram refinement.
We shall denote the parallel composition of a diagram refinement DD by |DD||.
E
, where E
is finite; for instance, if E
is the integers from 0 through 7, we would like to represent an object such as the sequence [{0, 7}, {1, 3, 6}].Sequences of sets of sort
E
will be represented by arrays of bit vectors of size k. For instance, the sequence [{0, 7}, {1, 3, 6}] would be represented by the array
[[0, 1, 0, 1, 0, 0, 1, 0], [1, 0, 0, 0, 0, 0, 0, 1]]
Note that the order of the sets is reversed in the representation. Note also that our representation choices must be coordinated: the size of the array elements must agree with the size of the bit vectors. If the size of array elements is specified by a declaration, so is the size of the sets we can represent.
We begin with the colimit of a diagram that has specifications
SEQ
and SET
glued together by the specification ONE-SORT
to indicate that the elements of the sequences are to be identified with the sets.
This colimit is illustrated in Figure 17. Here is the corresponding text:
spec SEQ-OF-SET is
colimit of diagram
nodes ONE-SORT, SEQ, SET
arcs ONE-SORT -> SEQ : {X -> E},
ONE-SORT -> SET : {X -> Set}
end-diagram
{X -> E}
from ONE-SORT
into SEQ
.ONE-SORT
, SEQ
, and SET
. The three interpretation assignments are as follows:
ONE-SORT
, assign the identity interpretation into ONE-SORT
.
SEQ
, assign the interpretation SEQ-TO
-ARRAY
we introduced in Example 5.4, page 73.
SET
, assign the interpretation SET-TO-BIT-VECTOR-FIXED
we introduced in Example 5.5, page 75.
SEQ-TO-ARRAY
, and the interpretation morphism assigned to the second arrow maps the identity interpretation into SET-TO-BIT-VECTOR-FIXED
. Some of the details of this diagram of interpretations are summarized as follows:
The top and bottom halves of the figure illustrate the interpretation morphisms assigned to the left and right arrows, respectively, of the shape I1. Note that the diagram commutes--if we could not find such interpretation morphisms, the parallel refinement would not be compatible. This figure reveals that the sort
E
of elements in the specification ARRAY
is identified with the sort Bit
-Vector-Fixed
; this means that the target theory will describe arrays whose elements are bit vectors of fixed length.The resulting interpretation diagram dd may be viewed as a morphism from I1 into the category Interp of interpretations. The final diagram d2 will have the same shape as d1. That is, I2 is identical to I1 and the shape mapping ss is the identity. The pair <dd,ss> is then a diagram refinement. To compute its parallel composition, Specware takes the colimit rr1 of the diagram of interpretations dd. Because the shape mapping in this case is the identity, this is also the desired parallel composition, an interpretation from the sequences-of-sets colimit into the arrays-of-bit-vectors colimit, illustrated as follows:
In this figure, the diagonal single arrows represent specification morphisms, the vertical double arrows represent interpretations. The parallel composition is the double arrow in the foreground.
Sorting. We suppose we want to specify a sorting function. The input will be a bag, the output will be a sequence, and the elements will be sorted according to a given transitive, total relation, called the sorting relation. The bag, sequence, and relation will all be defined over elements of the same sort. We shall require that the output have the same elements as the input, ordered according to the given relation. If an element occurs more than once in the input, it must occur the same number of times in the output. For example, if the input is {{4, 2, 4}} and the sorting relation is <=, the output should be [2, 4, 4]. Note that we do not specify the input to be a sequence, because the order in which the input elements appear is irrelevant.
The specification for sorting is given in Figure 18.
spec SORTING is
import colimit of
diagram
nodes ONE-SORT, BAG, SEQ, SORTING-RELATION
arcs ONE-SORT -> BAG : {X -> E},
ONE-SORT -> SEQ : {X -> E},
ONE-SORT -> SORTING-RELATION : {X -> E}
end-diagram
op ordered : Seq -> Boolean
op elements : Seq -> Bag
op sorted : Bag, Seq -> Boolean
definition of ordered is
axiom (ordered empty-seq)
axiom (ordered (prepend e empty-seq))
axiom (iff (ordered (prepend d (prepend e s)))
(and (rel-sort d e)
(ordered (prepend e s))))
end-definition
definition of elements is
axiom (equal (elements empty-seq) empty-bag)
axiom (equal (elements (prepend e s))
(insert-bag e (elements s)))
end-definition
definition of sorted is
axiom (iff (sorted b s)
(and (equal b (elements s))
(ordered s)))
end-definition
end-spec
Figure 18: Specification for Sorting
SORTING-RELATION
, given subsequently--this is the transitive, total relation. This and the specifications for bags and sequences are glued together by the specification ONE-SORT
, to ensure that they are all defined over elements of the same sort, to yield a colimit S1. The three operations, ordered
, elements
, and sorted
, are specified by definitions--thus the specification SORTING
is a definitional extension of the colimit S1.ordered
determines whether a given sequence is in increasing order, according to the relation rel-sort
, which is declared by the imported specification SORTING
-RELATION
. The axioms assert that any sequence of zero or one element is ordered. A longer sequence is ordered if its first two elements are in order, according to the relation rel-sort
, and if the sequence of all but the first element is ordered. These axioms define the predicate ordered
recursively. elements
yields the bag of elements of a given sequence. Finally, we define the predicate (sorted b s)
to hold if the input bag b
is the bag of the elements of the output sequence s
and the output sequence is in increasing order.rel-sort
is specified to be a transitive, total relation, as follows: spec SORTING-RELATION is
translate
colimit of
diagram
nodes
BINARY-RELATION, TRANSITIVE-RELATION, TOTAL-RELATION
arcs BINARY-RELATION -> TRANSITIVE-RELATION :
{br -> tr},
BINARY-RELATION -> TOTAL-RELATION :
{br -> tr}
end-diagram
by {tr -> rel-sort}
spec TOTAL-RELATION is
import
translate BINARY-RELATION by
{br -> tr}
axiom total is
(or (tr x y)(tr y x))
end-spec
SEQ
; this means that the target colimit theory would have two copies of the theory of sequences. This might be useful if we wanted to employ different representations for the input sequence (which represents a bag) and the output sequence. In subsequent refinements, we could implement these two sequences differently. It is wasteful, however, if we decide to use the same implementation for both sequences, because we would be constructing two copies of the same set of programs. Therefore, in this example we shall use a shape mapping that merges the two sequences into one.BAG
in the diagram, we assign the interpretation BAG-TO
-SEQ
from bags into sequences. To the other nodes, we assign the identity interpretation. We also assign an appropriate interpretation morphism to each of the three arrows. The result is an interpretation diagram dd, a morphism from the shape I1 into the category Interp of interpretations.SEQ
. This is the shape mapping ss:
Figure 19: Sorting Refinement
5.5 Interpretation of Definitional Extensions
As we have remarked, if a specification S' is a definitional extension of a specification S, we can extend an interpretation of S automatically into an interpretation of S'. (This is not true of an arbitrary specification S' that imports S--an axiom of S' may be inconsistent with the interpretation.)Example 5.22 Sorting, Continued.
In Example 5.21, we used parallel composition to obtain a refinement of part of the sorting specification, the colimit S1, into the new theory S2 of sequences and sorting relations over elements of the same sort. We remarked that the entire sorting specification is a definitional extension of the colimit, obtained by introducing definitions for the operations ordered
, elements
, and sorted
. Therefore we may automatically extend our refinement to obtain a refinement from the entire sorting specification into the theory of sequences and sorting relations. In the general discussion, S and T play the role of S1 and S2, respectively, in the sorting example; S' corresponds to the sorting specification.
5.6 Composing Diagram Refinements
Often we want to follow one parallel refinement with another. Diagram refinements can be composed sequentially by composing the individual interpretations which they comprise. This is illustrated in the following figure:Example 5.23 Bags of Bags.
In Example 5.20, we used parallel refinement to develop an implementation for sequences of sets, where the elements of the sets were of a finite sort E
. In this example, we shall develop a refinement of a specification that describes bags whose elements are themselves bags of sort E
, where E
is not necessarily finite. We shall represent both sorts of bags as sequences; the target theory will be sequences of sequences. Unlike in the sorting refinement (Example 5.21), we shall be forced to have two copies of the sequence specification, not one, in the target theory.
spec BAG-OF-BAGS is
colimit of
diagram
nodes ONE-SORT, OUTER : BAG, INNER : BAG
arcs
ONE-SORT -> OUTER : {X -> E},
ONE-SORT -> INNER : {X -> Bag}
end-diagram
ONE-SORT
. The sort X
of that specification is mapped into the elements of the outer bag specification and the bags of the inner bag specification; that is, these three sorts are identified. In a parallel refinement, when any of them is mapped into another by an interpretation, the other two must be mapped in such a way as to avoid incompatibility. In this case, it turns out that we cannot perform these two refinements in parallel. Instead we perform the refinement in two stages, as a sequential composition of two parallel refinements. In a subsequent note, we explore what mishaps occur if we attempt to perform both refinements at the same stage.BAG
into SEQ
, by applying the interpretation BAG
-TO-SEQ
we developed in Example 5.3, page 71. This refinement represents the bags by a quotient of sequences modulo the permutation relation; in other words, each bag is mapped into an equivalence class of several finite sequences, all of them permutations of each other.
We refine the specification ONE-SORT
to itself by applying the interpretation scheme ONE-SORT
-VIA
-QUOTIENT
we introduced in Example 5.10, (Interpretation Morphism), page 86. This ip-scheme maps a sort into the quotient of a sort modulo an equivalence relation.
To maintain compatibility, our refinement of the outer copy of
BAG
must be analogous; otherwise we couldn't construct an interpretation-scheme morphism into the refinement from ONE
-SORT
-VIA
-QUOTIENT
. We therefore represent the bag elements as the quotient of other elements modulo some relation. For this purpose, we introduce a specification that describes two sorts of bags B.Bag
and Q.Bag
, over elements of sort B
and Q
respectively, where Q
is a quotient sort of B
. The specification BAG-QUOTIENT
, which appears in part as follows, will serve as the mediator for the interpretation. The sort E
of elements of the outer copy of bags will be mapped into the quotient sort Q
in the mediator. spec BAG-QUOTIENT is
import
translate
colimit of
diagram
nodes B : BAG, Q : BAG
end-diagram
by {B.E -> B,
Q.E -> Q}
op r? : B, B -> Boolean
sort-axiom Q = B/r?
<axioms omitted>
end-spec
Q
-operations in terms of the B
-operations. This specification is discussed in the next subsection and appears in full in the appendix (Section G, page 168).
interpretation BAG-VIA-QUOTIENT : BAG => BAG is
mediator BAG-QUOTIENT
dom-to-med BAG-TO-Q-BAG
cod-to-med BAG-TO-B-BAG
BAG-TO-Q-BAG
and BAG-TO-B-BAG
are morphisms that map the usual bag sorts and operations into those for bags of elements of sorts Q
and B
, respectively, in BAG-QUOTIENT
. For example, the source morphism is morphism BAG-TO-Q-BAG : BAG -> BAG-QUOTIENT is
{Bag -> Q.Bag,
E -> Q,
empty-bag -> Q.empty-bag,
insert-bag -> Q.insert-bag,
in-bag? -> Q.in-bag?}
BAG-TO-B-BAG
, is analogous.BAG-VIA-QUOTIENT
, the sort E
of elements of the domain bags is mapped into the quotient sort Q
in the mediator; the sort E
of elements in the codomain bags is mapped into the sort B
of basic elements in the mediator. Because the relation r?
remains undefined, this is an interpretation scheme, not an interpretation.
Figure 20: First Diagram of Interpretations for Bags of Bags
Recall that the target morphisms of our interpretation schemes are not definitional extensions only because the relation
r?
is undefined in the mediators BAG-QUOTIENT
and TWO
-SORT
-QUOTIENT
. These relations are identified by morphisms with the relation perm?
in the mediator BAG-AS-SEQ
. Because this relation is defined, the target morphism of the parallel composition is a definitional extension. Thus the parallel composition will be an interpretation, even though two of its components are only interpretation schemes.ONE
-SORT
-VIA
-QUOTIENT
are library refinements and are reused in any parallel refinement of this kind.
Figure 21: Stage One: Inner Bags into Sequences
BAG-OF-BAGS
.BAG-QUOTIENT
in not a definitional extension of the codomain, because r?
is undefined, all the sorts and operations of the Q
-copy of the bag theory are defined in terms of the sorts and operations of the B
-copy. In particular, the Q
-bags are intuitively regarded as bags whose elements are equivalence classes of elements of sort B
, modulo the equivalence relation r?
. It is more convenient, however, to regard the Q
-bags as equivalence classes of B
-bags under a new equivalence relation eq-bag-mod-r?
, called equality modulo r?
. Two B
-bags are equal modulo r?
if we can establish a one-to-one correspondence between the elements of the two bags such that corresponding elements are equivalent under r?
.Q
-bag intuitively regarded as {{ {B1, B2}, {B, B} }}. The elements of this bag are equivalence classes of elements of sort B
modulo r?
; thus B1 and B2 are equivalent under r?
. The mediator will actually regard this as an equivalence class of two equivalent B
-bags, {{B1, BB}}and {{B2, BB}}, modulo eq-bag-mod-r?
.Q
-bags are defined in terms of operations on B
-bags. Thus, the mediator contains the following definition of Q.empty-bag
in terms of B.empty-bag
:definition of Q.empty-bag is
axiom (equal Q.empty-bag ((quotient eq-bag-mod-r?) B.empty-bag))
end-definition
Q
-bags in this unintuitive way.Q.insert-bag
and the predicate Q.in-bag?
. These are given in the full specification of the mediator, on page 169. We now resume our discussion of the refinement of the specification for bags of bags.BAG
into SEQ
, again by applying the interpretation BAG-TO
-SEQ
. This interpretation will represent the bags by a quotient, but will simply map the elements of the bags into the elements of the sequences. The corresponding sorts of elements (of ONE-SORT
) and sequences (of the inner copy of SEQ
) will be mapped into elements and sequences, respectively; we refine these nodes via the identity interpretations.ONE-SORT
into the other two interpretations, via two interpretation morphisms. The outer interpretation morphism maps the sort X
(in the domain, mediator, and codomain copies of ONE-SORT
) into the sort E
; the inner interpretation morphism maps the sortX
into the sort Seq
each time. This gives us our second diagram of interpretations dd which is summarized in Figure 22.
Figure 22: Second Diagram of Interpretations for Bags of Bags
Figure 23: Refinement of Bags of Bags
Figure 24: Incompatibility
`?,we
can see by following arrows around the diagram that two sorts in the inner mediator, Bag-as-Seq
and Seq
, will be identified, even though one is a quotient of the other, violating freeness.Example 5.24 Bags of Bags, Continued.
In the example Bags of Bags, we formed a diagram of three interpretations and constructed their parallel composition. We then formed a diagram of three subsequent interpretations and again constructed their parallel composition. Finally, we took the sequential composition of the two resulting interpretations.
Figure 25: Alternative Refinement of Bags of Bag
6 Code Generation
When specifications are sufficiently refined, we may use them to generate programs that satisfy them. The programs will have implementations, in a desired target language, for all the operations in the given specification. defun f (x)
(cond ((p x) (g x))
...))
and conditional equations, of the form
if (p x) (equal (f x) (g x))).
6.1 Restrictions on the Abstract Target Language
We probably will not find the built-in abstract target language sufficient to represent all the operations in our specification; for instance, the abstract target language SlangLisp contains realizations only for integers and lists. When we build an interpretation into the abstract target language, however, we have a morphism into a definitional extension of that language; that is, we have enlarged the language with new definitions. Also, we may use the Specware specification-building operations explicitly to enlarge the abstract target language. For the system to generate code, these extensions and enlargements must satisfy a number of restrictions. f
g
and h
; otherwise we would have two definitions for f
. definition of f is
axiom (equal (f x) E)
end-definition
as in
(equal (square x) (times x x))
definition of f is
axiom (implies (P1 x)
(equal (f x) E1))
axiom (implies (P2 x)
(equal (f x) E2))
end-definition
(P1 x)
and(P2 x)
must cover all possibilities; if both conditions hold, the values of E1
and E2
must agree. Of course the operation f
may have more than one argument, or none, or it may be a constant. There may be more than two clauses in the definition and it may be recursive--occurrences of f
may occur in E1
or E2
. For a boolean operation f
we may use iff
instead of equal
.f
must be applied directly to variable arguments, not constants or complex terms. Thus the following definition for the length
function, which is legal in Slang, is not constructive and is not allowed in SlangLisp: definition of length is
axiom (equal (length nil) 0)
axiom (equal (length (cons x l))
((relax nonzero?)(succ (length l))))
end-definition
length
are a constant and a term, not variables. Definitions of this style in Slang specifications must be mapped by the interpretation into constructive definitions if we are to generate code from them.head
and tail
or pred
, rather than the ``constructors'', such as nil
and cons
or succ
.f
being defined. For example, a constructive definition for a function ncons
may not contain the axiom axiom (equal (head (ncons x)) x)
head
surrounds the function ncons
being defined.relax
, quotient
, and embed
may surround the arguments or the defined function symbol in the definition. Special mechanisms in the es-morphism can translate such definitions into code. For example, in refining sets into bags, we have represented sets as a subsort of bags, those without duplicated elements. In the specification SET-AS-BAG
, we define the sort Set-as-Bag
by sort-axiom Set-as-Bag = Bag | no-dup-bag?
empty-s-as-b
of the empty set: definition of empty-s-as-b is
axiom (equal ((relax no-dup-bag?) empty-s-as-b) empty-bag)
end-definition
empty-s-as-b
is surrounded by a relax
function.BAG-AS-SEQ
, we have the following definition for the function insert-b-as-s
, which represents the bag insertion function: definition of insert-b-as-s is
axiom (equal (insert-b-as-s e ((quotient perm?) s))
((quotient perm?)
((relax nonempty?) (prepend e s))))
end-definition
s
of the defined function insert-b-as-s
is surrounded by a quotient
function. definition of length is
axiom (implies (null? nl)
(equal (length nl) zero))
axiom (equal (length ((relax nonnull?) nnl))
((relax nonzero?)(succ (length (tail nnl)))))
end-definition
nonnull? ((relax nonnull?) nnl)
. Hence the antecedent conditions do cover all possibilities, if we consider the invisible ones. (Note that nl
and nnl
are variables, with implicit universal (fa
) quantification.)Seq
of sequences but no separate sort of nonempty sequences. However, because we cannot give constructive definitions in terms of the constructors empty-seq
and prepend
, we must introduce destructors first-seq
and rest-seq
for sequences, to yield the first element of a nonempty sequence and the sequence of all the rest of the elements, respectively. Because the functions are not defined on the empty sequence, we introduce a sort NE-Seq of nonempty sequences and declare op first-seq : NE-Seq -> E
op rest-seq : NE-Seq -> Seq
head
and tail
. The function prepend
will now yield a nonempty sequence, not a sequence. (This explains why, in the definition for insert-b-as-s
, the occurrence of (prepend e s)
is surrounded by the operator (relax nonempty?)
). ->
and the product sort. A product sort cannot be the codomain of any operation. 6.2 The Entailment-System Morphism
The built-in es-morphism translates Slang constructs from the abstract target language into the corresponding programming-language constructs. For example, here is the SlangLisp definition for absolute value: spec SLANG-ABS is
import INTEGER
op abs : Int -> Int
definition of abs is
axiom (implies (ge x zero)
(equal (abs x) x))
axiom (implies (lt x zero)
(equal (abs x) (minus zero x)))
end-definition
end-spec
spec ES-ABS is
import SLANG-BASE
op abs
(defun abs (x)
(cond ((>= x 0) x)
((< x 0) (- 0 x))))
end-spec
abs
consists of a set of complementary axioms; the EsLisp version consists of a single conditional equation--sets of complementary axioms are not legal in EsLisp, while conditional equations are not legal in Slang. Also note that the SlangLisp version imports the specification for integers. The EsLisp version does not include definitions for integer operations, because these operations are built-in Lisp primitives. It does, however, import a specification SLANG-BASE
, which defines logical operations that are in Specware but are not primitive in Lisp. The specification SLANG-BASE
is as follows: spec SLANG-BASE is
ops implies, iff
(defun implies (x y)
(or (not x) y))
(defun iff (x y)
(or (and x y)
(and (not x) (not y))))
end-spec
6.2.1 The Specifications LIST-PRIM, INTEGER, and LIST
The following specification in the abstract target language SlangLisp describes lists of elements of sort List-Elem
. Spec LIST-PRIM is
Sorts List-Elem, List
op nil : List
op null? : List -> Boolean
op cons : List-Elem, List -> List
op head : List -> List-Elem
op tail : List -> List
constructors {nil, cons} construct List
<axioms for primitives omitted>
end-spec
List-Elem
is. Thus, although the es-morphism maps this specification into EsLisp, it does not have an independent implementation. It may be used as part of a diagram in which the meaning of List-Elem
is specified; the colimit of the entire diagram may be specified using the ``instantiation'' mechanism, described subsequently, instead of the usual colimit mechanism.INTEGER
, in contrast to our specifications NAT-BASIC
and Nat
, describes both nonnegative and negative integers. Spec INTEGER is
Sort Integer
op less-than : Integer, Integer -> Boolean
op greater-than : Integer, Integer -> Boolean
op less-than-or-equal : Integer, Integer -> Boolean
op greater-than-or-equal : Integer, Integer -> Boolean
op iplus : Integer, Integer -> Integer
op minus : Integer, Integer -> Integer
op times : Integer, Integer -> Integer
op min : Integer, Integer -> Integer
op max : Integer, Integer -> Integer
constructors {zero, one, iplus, minus} construct integer
%% axioms omitted
end-spec
one
, two
, ..., ten
, which denote the integers 1 through 10. There is an es-morphsim from this theory into EsLisp. Therefore, if we can refine a theory constructively into INTEGER
, we can compose that interpretation with the es-morphism to generate LISP code for the theory.LIST
, which imports both LIST-PRIM
and INTEGER
, that constructively defines additional Lisp functions, such as concat
(the append function), sublist
, and remove
. Since this theory is a definitional extension of LIST-PRIM
and INTEGER
, if we can refine a theory constructively into LIST
, we can generate Lisp code for the theory.LIST-PRIM
and INTEGER
. We can then create LISP code for a theory if we can refine it constructively into the extension.6.2.2 Translating Constructed Sorts
There are numerous details in es-morphisms such as that from SlangLisp to EsLisp. We shall briefly consider the translation of constructed sorts. empty-s-as-b
in the subsort of bags with no duplicated elements is represented by the bag((relax no-dup-bag?) empty-s-as-b)
in the supersort of bags. (As we have seen, this is defined to be equal to the empty bag.) Similarly, quotient sorts can be handled by representing an equivalence class by one of its elements. For example, the bag {{4,2,4}} might be represented by the sequence [2,4,4]. (relax p?)
and (quotient r?)
, associated with the subsorts and quotient sorts respectively, are dropped. For functions that are defined on a subsort, however, an explicit runtime check on the argument is inserted into the code; if the argument does not satisfy the predicate p?
, an error message is produced. For instance, before applying a function to a set represented as a bag with no duplicated elements, the implemented code would ensure that no-dup-bag?
was true of the bag. Also, the equality on a quotient sort E/r?
is replaced by the equivalence relation r?
that defines the quotient sort; thus the equality relation on bags will be replaced by the permutation relation on sequences; for example, two bags represented by the sequences [2,4,4] and [4,4,2] would be judged to be equal. sort-axiom Stack = E-Stack + NE-Stack
...
op size : Stack -> Int
definition of size is
axiom (equal (size ((embed 1) es))
zero)
axiom (equal (size ((embed 2) nes)) (
succ (size (pop nes))))
end-definition
This fragment is translated into the following piece of EsLisp:
op size, E-Stack?, NE-Stack?
(defun E-Stack? (s)
(= (car s) 1))
(defun NE-Stack? (s)
(= (car s) 2))
...
(defun size (s)
(cond
((E-Stack? s) 0)
((NE-Stack? s)
(1+ (size (pop (cdr s)))))))
car
is 1
, a nonempty stack by a list whose car
is 2
. E-stack
and NE-stack
, that is, empty stack and nonempty stack, in the SlangLisp version, are translated into functions E-Stack?
and NE-Stack?
in EsLisp. This would be impossible for an ordinary refinement, in which sorts can only be mapped into sorts, not functions.6.2.3 Translating Colimits
For suitable entailment-system morphisms, such as that from SlangLisp to EsLisp, we obtain a recursive procedure for code generation; code for the colimit is obtained by combining the code for its component specifications. Thus, if we can constructively refine each component of a diagram into a specification for which we have a realization in the target language, we can obtain a realization for the colimit of the diagram.6.2.4 Translation by Instantiation
A special mechanism exists for translating diagrams of the following form:FOO
into EsLisp. Recall that no translation exists from LIST-PRIM
into EsLisp; this is because we need a separate specification to describe the elements of the lists in LIST-PRIM
. However, the entire configuration can be translated into EsLisp by the instantiation mechanism. The lists of LIST-PRIM
will be translated into Lisp lists, and the elements of the list will be translated into the same Lisp objects as the elements of sort E
from the specification FOO
.6.3 Refinement for Code Generation
Although the following example illustrates many aspects of refinement that we have seen before, we use it to emphasize that special requirements are imposed on a refinement if we wish to use it to generate code.Example 6.1 Sets of Nonnegative Integers.
We assume we want to generate Lisp code for a specification for sets of nonnegative integers. As we have already seen, we can implement sets in terms of bags and, in turn, implement bags in terms of sequences. Sequences can then be implemented as lists, which exist in the abstract target language for Lisp. Furthermore, we can implement nonnegative integers in terms of Lisp integers--they are the subsort of the integers satisfying the nonnegative predicate. That is the basis for the proposed implementation. We give highlights of the refinement here.spec SET-OF-NAT-BASIC is
colimit of diagram
nodes ONE-SORT, SET, NAT-BASIC
arcs ONE-SORT -> SET : {X -> E},
ONE-SORT -> NAT-BASIC : {X -> Nat}
end-diagram
SET
is given in Section 3.3, page 45. The specification NAT-BASIC
is the basic specification for the nonnegative integers given in Figure 1, in Section 1, page 4.
We employ a sequential composition of parallel refinements; thus at each stage we refine
SET
, ONE-SORT
, and NAT-BASIC
separately.SET-AS-BAG
, in which sets are regarded as a subsort of bags, those with no duplicated elements; thus the set {2,4} is represented by the bag {{2,4}}, and no set is represented by the bag {{2, 2, 4}}. To define the appropriate subsort of the bags, we defined in the mediator a predicate no-dup-bag?
, which holds if a bag has no duplicated elements; we could then define the subsort Set-as-Bag
by
sort-axiom Set-as-Bag = Bag | no-dup-bag?
no-dup-bag?
did not have to be constructive. no-dup-bag?
predicate. Therefore, the definition of no-dup-bag?
must either be constructive itself or be mapped under refinement into a constructive definition. no-dup-bag?
because, in our theory, bags have no ``deconstructors'' analogous to head
and tail
in Lisp. We cannot map the definition of no-dup-bag?
into a constructive definition because it occurs in the mediator SET-AS
-BAG
, not in the specification BAG
, and is not influenced by the refinement process.no-dup-bag?
from the mediator into the specification BAG
itself. The resulting specification is called BAG-EXTEND
. The definition will then be mapped under refinement into the predicate no-dup-seq?
in the specification SEQ-EXTEND
, which is in turn mapped into the predicate no-dup-list?
in the specification LIST-EXTEND
, a definitional extension of LIST-PRIM
. Only this last definition is constructive. LIST-EXTEND
serves as the mediator of the interpretation from sequences into lists.(relax no-dup-bag?)
was abbreviated as bag-of-s-as-b
. However, as we indicated, in code generation the relax
function is given special treatment. Many of our axioms using the abbreviation bag-of-s-as-b
are not regarded as constructive, even though they are constructive when we replace them by the corresponding axiom that uses relax
explicitly. Therefore, when we are concerned about code generation, we sometimes need to use the relax
operation explicitly, instead of abbreviations such as bag-of-s-as-b
.ONE-SORT
and NAT-BASIC
; at this stage, we apply the identity interpretation to these specifications.
Figure 26: Stage One: Sets into Bags
Stage Two: Bags into Sequences. In the second stage of the refinement, we implement bags in terms of sequences as in Example 5.3, page 71; for code generation, however, we use a constructive mediator BAG-AS-SEQ-EXTEND
instead of the original mediator BAG-AS-SEQ
. Bags are regarded as a quotient sort, of sequences modulo the permutation relation. Each bag is mapped into an equivalence class of sequences; thus the bag {{2,4}} is mapped into the class of two sequences, [2,4] and [4,2]. According to the way quotient sorts are implemented, either of these sequences will stand for the bag. The equality relation on bags will be implemented as the permutation relation perm?
on sequences. Therefore we must have a constructive definition for perm?
.
perm?
was as follows: op perm? : Seq, Seq -> Boolean
definition of perm? is
axiom (iff (perm? s t)
(fa (e) (equal (count e s) (count e t))))
end-definition
(fa (e) ...)
. To evaluate this quantifier and check if the counts are equal for all elements e
of E
would require an infinite computation if E
is infinite; instead we replace it by a constructive definition, in which we test if the counts are equal only for those elements e
that actually occur in s
or in t
: definition of perm? is
axiom (iff (perm? s t)
(and (eqcount-seq? s s t)
(eqcount-seq? t s t)))
end-definition
(eqcount-seq? r s t)
is defined constructively to hold if every element of the sequence r
occurs equally often in s
and t
. This describes a finite computation because there are only a finite number of elements in r
ONE-SORT
and NAT-BASIC
. The resulting configuration is as given in Figure 27.
Figure 27: Sets into Sequences of Nonnegative Numbers
Stage Three: Nonnegative Integers into Integers. In the third stage, we refine NAT-BASIC
, our specification for the nonnegative integers, into INTEGER
, the SlangLisp specification for all the integers, including the negative integers, via a mediator NAT
-BASIC
-AS
-INTEGER
. In this refinement, the nonnegative integers are mapped into a subsort of the integers, those that satisfy the predicate nonnegative?
. More precisely, the sort Nat
in the nonnegative integers is mapped into the sort Nat-as-Int
in the mediator, defined by sort-axiom Nat-as-Int = Integer | nonnegative?
ONE-SORT
and SEQ-EXTEND
. This is because the three components share structure that is being altered by the refinement; because Nat
is altered in NAT-BASIC
, we must make corresponding alterations to X
in ONE-SORT
and E
in SEQ-EXTEND
; these three sorts are linked together by morphisms in the diagram.
The specification
ONE-SORT
is mapped into itself, not by the identity interpretation but via a mediator TWO-SORT
-SUBSORT
: spec TWO-SORT-SUBSORT is
sorts Y, Z
op p? : Z -> Boolean
sort-axiom Y = Z | p?
end-spec
X
in ONE-SORT
is mapped into the subsort Y
in the mediator. An interpretation morphism (See Section 5.4.2) will map p?
in this mediator into nonnegative?
in the mediator NAT-BASIC-AS-INTEGER
. The sorts Y
and Z
correspond to Nat
and Integer
respectively
The specification SEQ-EXTEND
is also mapped into itself, via a mediator SEQ
-EXTEND
-SUBSORT
, just as in refining bags of bags (Example 5.23, page 112) we mapped BAG
into itself via a mediator BAG-QUOTIENT
. The mediator imports the colimit of two copies of the sequence specification, over elements of sort C
and D
respectively. Sorts C
and D
are related in the mediator as follows:
op p? : D -> Boolean
sort-axiom C = D | p?
C
is the subsort of D
containing those elements that satisfy p?
.C
in the mediator) and the codomain sequences into the D-sequences. The C-sequences are related to the D-sequences as follows: sort-axiom C.Seq = D.Seq | all-p?
(all-p? ds)
is defined (constructively) to hold if every element of a D-sequence ds
satisfies the condition p?
. Thus, if p?
is the predicate nonnegative?
, (all-p? ds)
will hold if ds
is the sequence [1,2,3] but not the sequence [-1,2,3]. The C-sequences are a subsort of the D-sequences--those whose elements all satisfy the condition p?
.SEQ-EXTEND
in terms of the sequence operations in the target specification SEQ-EXTEND
; this means that we must define the operations of the C--sequences constructively in terms of the operations of the D--sequences. For instance, we say definition of C.empty-seq is
axiom (equal ((relax all-p?) C.empty-seq) D.empty-seq)
end-definition
(relax all-p?)
maps a C--sequence into the same sequence regarded as a D--sequence. The definition then means that the empty C--sequence is the sequence that, regarded as a D--sequence, is the empty D--sequence. This is a constructive definition only because of the special treatment of the relax
operator.first-seq
and rest-seq
into SEQ-EXTEND
, we must relate the C--version of these functions with the corresponding D--versions. For example, we have axiom (equal ((relax p?)
(C.first-seq cnes))
(D.first-seq
(d-of-c-ne-seq cnes)))
(d-of-c-ne-seq cnes)
is a function defined in the mediator to map a nonempty C--sequence cnes
into the same sequence viewed as a nonempty D--sequence.
Figure 28: Third Stage: Nonnegative Integers to Integers
Stage Four: Sequences into Lists. In the fourth stage, we refine SEQ-EXTEND
into LIST-PRIM
, the SlangLisp specification for a fragment of Lisp. The interpretation is via a mediator LIST-EXTEND
, which enriches LIST-PRIM
with constructive definitions of operations, such as no-dup-list?
, that are necessary for the representation of sets. In this representation, empty-seq
is represented by nil
, in-seq?
by member
, prepend
by cons
, and so forth.ONE-SORT
into TRIV
, which is actually identical to ONE-SORT
except that TRIV
is in SlangLisp and ONE-SORT
is not. We also refine INTEGER
into itself via the identity. These refinements can be performed in parallel, without causing incompatibilities. To see this, observe that the diagram in Figure 29 commutes--it illustrates just this last stage of the refinement process.
Figure 29: Stage Four: Sequences into Lists
Code Generation. We have constructed an interpretation from our initial specification for sets of nonnegative integers into a colimit of a diagram whose components are all SlangLisp specifications. Furthermore, all the operations of our initial specification have been mapped into constructive definitions based on SlangLisp primitives. Let us examine our final colimit diagram:SET-OF-NAT-BASIC
into EsLisp. The target of this es-morphism, an EsLisp specification, will contain Lisp definitions that implement all the set operations of SET
, as applied to elements that are nonnegative integers. It will also contain Lisp implementations of all the numerical operations in NAT-BASIC
.DEFUN INSERT-SET (X SB)
(IF (IN-BAG? X SB) SB
(IF (NOT (IN-BAG? X SB))
(INSERT-BAG X SB)
(CASE-ERROR))))
.
.
.
(DEFUN INSERT-BAG (E S)
(PREPEND E S))
Part III Appendices
A Names
Specifications, morphisms and diagrams can each be named, as can many of their components, such as nodes and arcs of diagrams. There is a consistent syntax for introducing names, illustrated as follows:NAMED NOT NAMED
spec <name> is spec
<development-element>* <development-element>*
end-spec end-spec
morphism m : <name> -> <name> { <sm-rules> }
is { <sm-rules> }
diagram <name> is diagram
<nodes-and-arcs> <nodes-and-arcs>
end-diagram end-diagram
is
may be replaced by the symbol =.
Names are used in the usual way to denote the objects to which they are bound. Thus, for example, in any syntactic context in which a specification is required, a name of a specification may be substituted.A.1 Naming and Scoping Rules
Specifications, diagrams, and morphisms each have their own individual, global namespace. Thus the same name may be used to denote, say, a specification and a morphism. Because these namespaces are global, two different specifications (respectively, morphisms, diagrams) must have different names--there is no context that can disambiguate which specification a name refers to. diagram FOO is
nodes X: spec Y is ... end-spec
end-diagram
X
cannot introduce the name Y
.A.2 Lexical Conventions
Valid names start with either an upper- or lower-case letter or an asterisk (*
), and are followed by any letter or digit or an asterisk (*
), exclamation point (!
), hyphen (-
), or question mark (?
). (Also, see Section B.2 in the BNF appendix.) Names are not case sensitive: all names are converted to uppercase internally.
( ) -> , | : = . < > { } [] / +
<slang-top-level>/core4/code/language/spec-grammar.re
.
typewriter
font. Syntax alternatives are separated by ``|''. Parentheses, ``(...)'', are used for grouping, e.g., for inline alternatives. Optional entities are enclosed in square brackets, ``[...]''. Writing a ``*
'' after a syntactic element indicates zero or more repetitions of that element; a ``+'' indicates one or more repetitions.
The top-level objects of Slang are specifications, morphisms, and diagrams. Each such object class appears twice in the grammar, once with the prefix ``global-'' and once with the prefix ``local-''. Global objects must be named; local objects must not be named. Global objects can appear only at the top-level; local objects can appear only within other expressions.
<top-level-slang-object> ->
<global-spec> | <global-sm-diagram>
Specifications
<global-spec> ->
spec
<symbol> (is
| = >[<import-declaration>]
<development-element>*
end-spec
|
spec
<symbol>(is |=>
<spec-operation>Import Declarations
<import-declarationÒ Æ
import
<spec-term> (,<spec-term>)* |
import
<diagram-term> Specification Elements
<development-element> ->
<sort-declaration> | <sort-axiom> \xbd <op-declaration> |
<constructor-set> | <theorem> | <definition>
<sort-declaration> -> (
sorts
| sort
) <spec-sort> (, <spec-sort> )*
<spec-sort> -> <symbol>
<sort-axiom> ->
sort-axiom
<spec-sort-ref> =
<spec-sort-term>
<op-declaration> -> (
op
| const
) <symbol> : <spec-sort-term>
<constructor-set> ->
constructors {
<spec-op-ref> (, <spec-op-ref>)*} construct
<spec-sort-term>
<theorem> -> (
axiom
| theorem
) [ <symbol> ( is
| =
)] <spec-op-term>
<definition> ->
definition
[ <symbol>[of
<spec-op-ref>] ( is
| = )] <definition-clause> +
end-definition
<definition-clause> -> <theorem>
Sort Terms
<spec-sort-term> ->
<spec-sort-ref> | <spec-sort-function> | <spec-sort-subsort> |
<spec-sort-quotient> | <spec-sort-coproduct> | <spec-sort-product>
<spec-sort-ref> -> <qualified-name>
<spec-sort-function> -> [<spec-sort-term>]
->
<spec-sort-term>
<spec-sort-subsort> -> <spec-sort-term> | <spec-op-term>
<spec-sort-quotient> -> <spec-sort-term>
/
<spec-op-term>
<spec-sort-coproduct> ->
[ ]
| <spec-sort-term> (+
<spec-sort-term>)+
<spec-sort-product> ->
( )
| <spec-sort-term> (,
<spec-sort-term>)+
Precedence and Associativity for Sort Terms. The different operators for constructing sort terms are listed as follows in order of increasing precedence. Precedence can be overridden with parentheses.
precedence for <spec-sort-term>
brackets ( matching )
same-level
->
associativity right same-level
,+
associativity none same-level
|/
Terms and Formulas
<spec-op-term> ->
<spec-op-ref> | <spec-op-operation> | <spec-op-binding-operation> | <spec-op-product>
<spec-op-ref> -> <qualified-name> [ : <spec-sort-term>]
<spec-op-operation> ->
(
<spec-op-term> <spec-op-term> * )
|
(
( project
| embed
) <positive-integer> )
<spec-op-binding-operation> ->
(
<spec-op-binding-rator> ( <bound-var * )
<spec-op-term> )
<spec-op-binding-rator> -> (
fa
| ex
|lambda
)
<bound-var> -> <symbol> [: <spec-sort-term>]
<spec-op-product> ->
<
<spec-op-term> * >
Specification Terms
Specification terms are terms that denote specifications. Generally terms are of three kinds: references to named objects, operations, and explicit terms for anonymous (or local) objects.
<spec-term> -> <spec-ref> | <local-spec> | <spec-operation>
<spec-ref> -> <symbol>
<local-spec> ->
spec
[<import-declaration>]
<development-element> *
end-spec
<spec-operation> -> <spec-translation> | <spec-colimit>
<spec-translation> ->
translate
<spec-term>by {
[ <sm-rules>] }
<spec-colimit> ->
colimit of
<diagram-term>Specification Morphisms
<global-signature-morphism> ->
morphism
<symbol>: <spec-term> ->
<spec-term> ( is
| =
)
{
[ <sm-rules>] }
<sm-rules> -> <sm-rule> (
,
<sm-rule>)*
<sm-rule> -> <sort-or-op-ref>
->
<sort-or-op-ref>
<sort-or-op-ref> -> <qualified-name> |
(
<qualified-name>: <spec-sort-term> )
Specification Morphism Terms
<sm-term> -> <sm-ref> | <local-signature-morphism> | <sm-operation>
<sm-ref> -> <symbol>
<local-signature-morphism> ->
[
morphism
<spec-term>->
<spec-term>] {
[<sm-rules>] }
<sm-operation> ->
identity-morphism
| translation-morphism
|
import-morphism
| cocone-morphism from
<symbol>
Diagrams
<global-sm-diagram> ->
diagram
<symbol> (is
| =
) [
nodes
<sm-node> (,
<sm-node>) *] [
arcs
<sm-arc> (,
<sm-arc> )*]
end-diagram
Diagram Terms
<diagram-term> -> <diagram-ref> | <local-sm-diagram>
<diagram-ref> -> <symbol>
<local-sm-diagram> ->
diagram
[
nodes
<sm-node> ( ,
<sm-node> )*] [
arcs
<sm-arc> ( ,
<sm-arc> )* ]
end-diagram
Diagram Elements
<sm-node> -> [ <symbol> : ] <spec-term>
<sm-arc> -> [ <symbol> : ] <sm-node-ref>
->
<sm-node-ref> : <sm-term>
<sm-node-ref> -> <symbol>
Qualified Names
<qualified-name> -> (<node-name> . )* s<sort-or-op-name>
<node-name> -> <symbol>
<sort-or-op-name> -> <symbol>
Simple Name
<symbol> -> <symbol-start-char> <symbol-continue-char> *
<symbol-start-char> \xce
*abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
<symbol-continue-char> \xce
-
*abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
1234567890?!
Comments
The character ``
%
'' indicates the start of a comment; everything which follows until the end of the line is ignored. Larger pieces of text can be commented out by enclosing them in ``#||...||#
''; these characters function as brackets and can be nested.
<top-level-slang-object> -> <global-ip-scheme> | <global-ips-morphism>
Interpretations and Interpretation Schemes
<global-ip-scheme> ->
(
interpretation
| ip-scheme
) <symbol> : <spec-term> =>
<spec-term> ( is
| =
)
mediator
<spec-term> (
dom-to-med
| domain-to-mediator
) <sm-term>(
cod-to-med
| codomain-to-mediator
) <sm-term>
Interpretation (Scheme) Terms
<ips-term> -> <ips-ref> | <local-ip-scheme>
<ips-ref> -> <symbol>
<local-ip-scheme> ->
(
interpretation
| ip-scheme
) [ <spec-term> = | <spec-term>]
mediator
<spec-term> (
dom-to-med
| domain-to-mediator
) <sm-term>(
cod-to-med
| codomain-to-mediator
) <sm-term> Interpretation (Scheme) Morphisms
<global-ips-morphism> ->
ip-scheme-morphism
<symbol>: <ips-term> ->
<ips-term> (is
| =
)
domain-sm
<sm-term>
mediator-sm
<sm-term>
codomain-sm
<sm-term> Interpretation (Scheme) Morphism Terms
<ipsm-term> -> <ipsm-ref> | <local-ips-morphism>
ipsm-ref> -> <symbol>
<local-ips-morphism> ->
ip-scheme-morphism
domain-sm
<sm-term>
mediator-sm
<sm-term>
codomain-sm
<sm-term>
NAT-BASIC
for the nonnegative integers. While that specification does describe the set of nonnegative integers, it does not provide definitions for many of the functions and relations we would expect in such a theory, such as addition, multiplication, and the ordering relations.
The following specification
NAT
, a definitional extension of NAT-BASIC
, introduces some of the operations we need, including a predecessor function, addition, and the less-than and less-than-or-equal-to relations. spec NAT is
import NAT-BASIC
op pred : Pos -> Nat
definition of pred is
axiom (equal (pred (succ x)) x)
end-definition
op plus : Nat, Nat -> Nat
definition of plus is
axiom (equal (plus zero y) y)
axiom (equal (plus (nat-of-pos (succ x)) y)
(nat-of-pos (succ (plus x y))))
end-definition
op leq : Nat, Nat -> Boolean
definition of leq is
axiom (iff (leq x zero) (equal x zero))
axiom (iff (leq x ((relax nonzero?) (succ y)))
(or (leq x y)
(equal x ((relax nonzero?) (succ y)))))
end-definition
op lt : Nat, Nat -> Boolean
definition of lt is
axiom (iff (lt x y)
(and (leq x y)
(not (equal x y))))
end-definition
theorem (equal (plus zero y) y)
theorem associativity-of-plus is
(equal (plus x (plus y z)) (plus (plus x y) z))
theorem commutativity-of-plus is
(equal (plus x y) (plus y x))
end-spec
pred
, the addition function plus
, and the ordering relations leq
and lt
. This is enough to participate in the specification for arrays, which appears in the following section. It still does not define such common operations as multiplication, exponentiation, the divides relation, or the constant one
, which are in the library version of the specification for the nonnegative integers.E Example: Sequences into Arrays
In this appendix we present full specifications for arrays and describe the refinement from basic sequences into arrays. These were discussed in Example 5.4, page 73. We build on the more complete specification NAT
from the previous appendix (Section D), rather than the basic specification NAT-BASIC
given in Section 1. This is because we need the less-than relation lt
, which is only defined in NAT
.
We distinguish between static and dynamic arrays.
E.1 Static Arrays
The specification for static arrays is as follows: spec ARRAY is
import NAT
sorts E, Array, Array-and-Interval
op make-array : Nat, E -> Array
op size-array : Array -> Nat
op in-bounds? : Array, Nat -> Boolean
definition of in-bounds? is
axiom (iff (in-bounds? a i) (lt i (size-array a)))
end-definition
sort-axiom Array-and-Interval = (Array, Nat) | in-bounds?
op access-array : Array-and-Interval -> E
axiom access-of-make-array is
(implies (and (equal a (make-array n e))
(equal ((relax in-bounds?) a-and-i) <a i>))
(equal (access-array a-and-i) e))
axiom size-of-make-array is
(equal (size-array (make-array n e)) n)
op update-array : Array-and-Interval, E -> Array
axiom access-of-update-same is
(implies
(and (equal ((relax in-bounds?) a-and-i) <a i>)
(equal ((relax in-bounds?) upi-and-i)
<(update-array a-and-i e) i>))
(equal (access-array upi-and-i) e))
axiom access-of-update-distinct is
(implies
(and (not (equal i j))
(and (equal ((relax in-bounds?) a-and-i) <a i>)
(and (equal ((relax in-bounds?) a-and-j) <a j>)
(equal ((relax in-bounds?) upi-and-j)
<(update-array a-and-i e) j>))))
(equal (access-array upi-and-j)
(access-array a-and-j)))
axiom size-of-update-array is
(implies
(equal ((relax in-bounds?) a-and-i) <a i>)
(equal (size-array (update-array a-and-i e))
(size-array a)))
axiom equal-array is
(iff (equal a1 a2)
(and (equal (size-array a1) (size-array a2))
(fa (i)
(implies
(and (equal ((relax in-bounds?) a1-and-i) <a1 i>)
(equal ((relax in-bounds?) a2-and-i) <a2 i>))
(equal (access-array a1-and-i)
(access-array a2-and-i))))))
constructors {make-array, update-array} construct Array
end-spec
access-array
, the function that returns the i
th element of the array a
, is not defined on all arrays and nonnegative integers, but only on a pair a-and-i
consisting of an array a
and a nonnegative index i
less than the size of a
. The domain of this operation is thus a subsort of the product sort (Array, Nat)
, those pairs that satisfy a predicate in-bounds?
. Applying the operator (relax in-bounds?)
to the subsort element a-and-i
yields the corresponding pair <a i>
. Therefore, a statement such as (equal ((relax in-bounds?) a-and-i) <a i>)
i
is a nonnegative index within the bounds of the array a
, and that a-and-i
is the element of the domain subsort corresponding to the pair <a i>
.(make-array n e)
constructs an initial array of size n
, each of whose elements is initialized to e
. According to the axiom access-of-make-array
, the i
th element of this array must be e
, for any index i
that is within bounds. According to the axiom size-of-make-array
, the size of this array is indeed n
.(update-array a-and-i e)
assigns the i
th element of array a
to be e
, where i
is within bounds and a-and-i
is the element of the domain subsort corresponding to a
and i
. The axiom access-of-update-same
says that the i
th element of the updated array will be e
. The axiom access-of-update-distinct
says that the j
th element of the updated array will be the same as the j
th element of the original array a
, if j
is within bounds and is distinct from i
.equal-array
asserts that two arrays are equal if they have the same size and their corresponding elements are equal. The constructor set, which corresponds to an induction axiom, says that any array can be constructed by first making an initial array (all of whose elements are the same) and then applying a series of update operations. E.2 Dynamic Arrays
Dynamic arrays are a definitional extension of static arrays that allow an array to be enlarged so that a new element can be introduced at the end.spec DYNAMIC-ARRAY is
import ARRAY
const empty-array : Array
definition of empty-array is
axiom (equal empty-array (make-array zero e))
end-definition
op extend-array : Array, E -> Array
definition of extend-array is
axiom access-of-extend-array-last is
(implies
(equal ((relax in-bounds?) exa-and-s)
<(extend-array a e) (size-array a)>)
(equal (access-array exa-and-s)
e))
axiom access-of-extend-array is
(implies
(and (equal ((relax in-bounds?) a-and-i) <a i>)
(equal ((relax in-bounds?) exa-and-i)
<(extend-array a e) i>))
(equal (access-array exa-and-i)
(access-array a-and-i)))
axiom size-of-extend-array is
(equal (size-array (extend-array a e))
((relax nonzero?) (succ (size-array a))))
end-definition
constructors {empty-array, extend-array} construct Array
end-spec
empty-array
is the array of size 0, with no elements. According to its definition, it is equal to the result of constructing an initial array of size 0; it doesn't matter what element e
the array elements are initialized to, since there are none. This constant could have been defined for the static arrays, but we didn't need it there; here it is part of the constructor set. It will also serve as the implementation for the empty sequence.(extend-array a e)
adds a new element e
to the end of the array a
. According to the axiom access-of-extend-array-last
, the last element of this extended array will be e
. According to the axiom access-of-extend-array
, the i
th element of the extended array will be the same as the i
th element of the original array a
, if i
is within the bounds of a
. Finally, according to the axiom size-of-extend-array
, the size of the extended array is one greater than the size of the original array.E.3 Sequences as Arrays
The specification SEQ-AS-ARRAY
is a definitional extension of DYNAMIC-ARRAY
that contains implementations for the basic sequence specification. It serves as the mediator for the interpretation of basic sequences as arrays.spec SEQ-AS-ARRAY is
import translate DYNAMIC-ARRAY
by {empty-array -> empty-s-as-a}
op prepend-s-as-a : E, Array -> Array
definition of prepend-s-as-a is
axiom (equal
(prepend-s-as-a e a)
(extend-array a e))
end-definition
constructors {empty-s-as-a, prepend-s-as-a} construct Array
end-spec
E.4 Sequences into Arrays
The interpretation from basic sequences into arrays is as follows:interpretation SEQ-BASIC-TO-ARRAY : SEQ-BASIC => ARRAY is
mediator SEQ-AS-ARRAY
dom-to-med {Seq -> Array,
empty-seq -> empty-s-as-a,
prepend -> prepend-s-as-a}
cod-to-med import-morphism
prepend
for sequences is defined in terms of the function extend-array
of dynamic arrays. F Example: Finite Sets into Fixed Bit Vectors
In this appendix we present the full specification for fixed bit vectors and describe the refinement of finite sets into fixed bit vectors. These were discussed in Example 5.20.
F.1 Bits, Bit Vectors, and Fixed Bit Vectors
Here is the specification for bits: spec BIT is
sort Bit
op zero : Bit
op one : Bit
axiom (not (equal zero one))
constructors {zero, one} construct Bit
end-spec
spec BIT-VECTOR is
colimit of
diagram
nodes ONE-SORT, ARRAY, BIT
arcs ONE-SORT -> ARRAY : {X -> E},
ONE-SORT -> BIT : {X -> Bit}
end-diagram
size-vector
. spec BIT-VECTOR-FIXED is
import BIT-VECTOR
const size-vector : Nat
sort Interval
sort-axiom Interval = Nat | in-interval?
op in-interval? : Nat -> Boolean
definition of in-interval? is
axiom (iff (in-interval? i)
(lt i size-vector))
end-definition
sort Bit-Vector-Fixed
sort-axiom Bit-Vector-Fixed = Array | of-given-size?
op of-given-size? : Array -> Boolean
definition of of-given-size? is
axiom (iff (of-given-size? a)
(equal (size-array a) size-vector))
end-definition
op make-bvf : Bit -> Bit-Vector-Fixed
definition of make-bvf is
axiom (equal ((relax of-given-size?) (make-bvf b))
(make-array size-vector b))
end-definition
op update-bvf : Bit-Vector-Fixed, Interval, Bit
-> Bit-Vector-Fixed
definition of update-bvf is
axiom (implies
(equal ((relax in-bounds?) v-and-i)
<((relax of-given-size?) v)
((relax in-interval?) i)>)
(equal
((relax of-given-size?) (update-bvf v i b))
(update-array v-and-i b)))
end-definition
op access-bvf : Bit-Vector-Fixed, Interval -> Bit
definition of access-bvf is
axiom (implies
(equal ((relax in-bounds?) v-and-i)
<((relax of-given-size?) v)
((relax in-interval?) i)>)
(equal
(access-bvf v i)
(access-array v-and-i)))
end-definition
end-spec
access-bvf
and update-bvf
. We introduce a subsort Interval
of the nonnegative integers, those less than size-vector
, to serve as the sort for the indices. The fixed bit vectors themselves are a subsort Bit-Vector-Fixed
of the arrays, those of size equal to size-vector
. Thus, access-bvf
is defined over the entire product (Bit-Vector-Fixed, Interval)
relax
operator is used to map objects in subsorts with their counterparts in the corresponding supersorts. F.2 Sets as Fixed Bit Vectors
This specification augments fixed bit vectors to mimic set operations. It serves as the mediator of the interpretation from finite sets into fixed bit vectors.spec SET-AS-BIT-VECTOR-FIXED is
import BIT-VECTOR-FIXED
const empty-s-as-bvf : Bit-Vector-Fixed
definition of empty-s-as-bvf is
axiom (equal empty-s-as-bvf (make-bvf BIT.zero))
end-definition
op insert-s-as-bvf : Interval, Bit-Vector-Fixed
-> Bit-Vector-Fixed
definition of insert-s-as-bvf is
axiom (equal (insert-s-as-bvf i v)
(update-bvf v i BIT.one))
end-definition
op in-s-as-bvf? : Interval, Bit-Vector-Fixed -> Boolean
definition of in-s-as-bvf? is
axiom (iff (in-s-as-bvf? i v)
(equal (access-bvf v i) BIT.one))
end-definition
constructors {empty-s-as-bvf, insert-s-as-bvf} construct
Bit-Vector-Fixed
end-spec
F.3 Finite Sets into Fixed Bit Vectors
Here is the interpretation of finite sets into fixed bit vectors. interpretation SET-TO-BIT-VECTOR-FIXED :
SET => BIT-VECTOR-FIXED is
mediator SET-AS-BIT-VECTOR-FIXED
dom-to-med
{E -> Interval,
Set -> Bit-Vector-Fixed,
empty-set -> empty-s-as-bvf,
insert-set -> insert-s-as-bvf,
in-set? -> in-s-as-bvf?}
cod-to-med import-morphism
G Example: Bags into Bags via a Quotient
In this appendix we present an interpretation scheme of bags into bags. This scheme is intended to be applied as one component of a parallel refinement. The sort of the elements of the bags in this component is identified with a sort in another component, and that sort is mapped into a quotient modulo an undefined equivalence relation. For instance, in the example Bags of Bags (Example 5.23), the elements of the bags in this component are identified with the inner bags in another component, and the inner bags are mapped into a quotient of sequences modulo the permutation relation.
The interpretation scheme that fulfills this role is as follows:
interpretation BAG-VIA-QUOTIENT : BAG => BAG is
mediator BAG-QUOTIENT
dom-to-med BAG-TO-Q-BAG
cod-to-med BAG-TO-B-BAG
Here the source morphism is
morphism BAG-TO-Q-BAG : BAG -> BAG-QUOTIENT is
{Bag -> Q.Bag,
E -> Q,
empty-bag -> Q.empty-bag,
insert-bag -> Q.insert-bag,
in-bag? -> Q.in-bag?}
BAG-QUOTIENT
has two copies of the theory of bags, the B
-bags and the Q
-bags, with elements of sorts B
and Q
respectively. The sort Q
is a quotient of B
modulo r?
, where r?
is an equivalence relation on B
.BAG-TO-Q-BAG
maps the element sort E
in the domain bag into the sort Q
in the mediator. The bag sorts and operations in the domain are mapped into sorts and operations on Q
-bags in the mediator. The target morphism BAG-TO-B-BAG
is analogous--it maps sorts and operations on bags in the codomain into sorts and operations on B
-bags in the mediator.r?
is not defined, the target morphism is not a definitional extension, and the ip-scheme fails to be a full-fledged interpretation. Definitions in the mediator express the other operations on Q
-bags in terms of operations on B
-bags.BAG-QUOTIENT
is as follows: spec BAG-QUOTIENT is
import
translate
colimit of
diagram
nodes B : BAG, Q : BAG
end-diagram
by {B.E -> B,
Q.E -> Q}
op r? : B, B -> Boolean
sort-axiom Q = B/r?
op subbag-mod-r? : B.Bag, B.Bag -> Boolean
definition of subbag-mod-r? is
axiom (subbag-mod-r? B.empty-bag bb2)
axiom (iff (subbag-mod-r? (B.insert-bag b1 bb1) b2-bb2)
(ex (b2 bb2)
(and (equal b2-bb2 (B.insert-bag b2 bb2))
(and (r? b1 b2)
(subbag-mod-r? bb1 bb2)))))
end-definition
op eq-bag-mod-r? : B.Bag, B.Bag -> Boolean
definition of eq-bag-mod-r? is
axiom (iff (eq-bag-mod-r? bb1 bb2)
(and (subbag-mod-r? bb1 bb2)
(subbag-mod-r? bb2 bb1)))
end-definition
sort-axiom Q.Bag = B.Bag/eq-bag-mod-r?
definition of Q.empty-bag is
axiom (equal Q.empty-bag ((quotient eq-bag-mod-r?) B.empty-bag))
end-definition
definition of Q.insert-bag is
axiom (equal (Q.insert-bag ((quotient r?) b)
(quotient eq-bag-mod-r?) bb))
((quotient eq-bag-mod-r?) (B.insert-bag b bb)))
end-definition
definition of Q.in-bag? is
axiom (iff (Q.in-bag? ((quotient r?) b)
((quotient eq-bag-mod-r?) bb))
(B.in-bag? b bb))
end-definition
constructors {B.empty-bag, B.insert-bag} construct B.Bag
constructors {Q.empty-bag, Q.insert-bag} construct Q.Bag
end-spec
Q
-bag operations in terms of the B
-bag operations. The predicate subbag-mod-r?(bb1,bb2)
tests whether the B
-bag bb1
is a subbag modulo r?
of the bag bb2
, i.e., whether there is a one-to-one mapping from bb1
into bb2
under which each element of bb1
corresponds to an equivalent element of bb2
, where the equivalence is under the equivalence relation r?
. For example, if B1
is equivalent to B2
modulo r?
, the bag {{B1, B1}} is a subbag modulo r
? of the bag {{B1, B2, B3}} but not of the bag {{B1, B3}}.subbag-mod-r?
is not constructive (see Section 6.1). Not only is its format unacceptable for Specware's code generation, but also the existential quantifier does not in general describe a finite computation. If we were intending to generate code, we would have to rewrite it.
The predicate
eq-bag-mod-r?(bb1,bb2}
tests whether two B
-bags are equal modulo r?
, i.e., whether there exists a one-to-one correspondence between the two bags such that corresponding elements are equivalent modulo r?
. For example, if B1
and B2
are equivalent modulo r?
, the bag {{B1, B1, B3}} is equal modulo r?
to the bag {{B1, B2, B3}} but not necessarily to the bag {{B1, B3, B3}}. In the definition, two B
-bags are said to be equal modulo r?
if each is a subbag of the other modulo r?
.Q
-bags, then, are defined to be the quotient of the B
-bags modulo the relation eq-bag-mod-r?
. The operations on Q
-bags can then be defined in terms of the operations on B
-bags, using the quotient function on the new relation eq-bag-mod-r?
. Only r?
is undefined.