The Definition of Extended ML

Stefan Kahrs^{∗} Donald Sannella^{∗}  Andrzej Tarlecki^{†}

— Version 1.21 — August 28, 1997

Abstract

This document formally defines the syntax and semantics of the Extended ML language. It is based directly on the published semantics of Standard ML in an attempt to ensure compatibility between the two languages.

Defects in This Document

This document contains the following (known) defects:

1. Behavioural equivalence. Mentioned as a defect in the introduction.

2. The way the meta-language deals with higher-order rules is not sufficient, since we can never show non-derivability, there are always “funny” models in which additional sentences are true. We probably need some kind of inductive semantics here (Andrzej).

3. In the dependency diagram there is an arrow missing, expressing the dependency between verification semantics for modules and static semantics for modules.

4. There are now some redundant existential quantifiers in several rules since the translation of rules has been changed. Similarly, the new function Tnames could be put to good use in the static semantics, getting rid of a couple of universal quantifiers.

5. Where exactly do Stephen Gilmore’s example of VDM-like specifications go wrong? They should be somehow, but it’s not clear that they do.

6. The defects section is not up-to-date.

∗LFCS, Department of Computer Science, University of Edinburgh, Edinburgh, Scotland.

†Institute of Informatics, Warsaw University, and Institute of Computer Science, Polish Academy of Sciences, Warsaw, Poland.

Changes from version 1.0

The page numbers and rule numbers refer to ECS-LFCS-94-300.

Page 5. The translation of rules has been changed, meta-variables occurring in the conclusion but not in the premise of a rule are now implicitly existentially quantified (rather than universally). This made a couple of paragraphs on pages 6 and 7 (special care for higher order rules) redundant as well as several existential quantifiers throughout the semantics.

Page 8. A new keyword iff has been introduced. There is also a corresponding new entry in the grammar for the full language and a new rule in the derived form semantics.

Page 11 and 17. Due to an error in a macro definition the figures for syntactic objects did not display the names of the object classes.

Page 17. The condition for guardedness of structure expressions has been further restricted.

Page 24. The simple traces have slightly changed. There is an according change in rule 20.

Page 26. A function Tnames has been introduced for selecting the type names defined in a type environment.

Page 30. There are new side-conditions for rules 11.1–11.3 imposing that explicit type variables are abstracted where they are scoped.

Page 31, added a comment about the uniqueness of U in rules 11.1–11.3.

Page 32, The side-condition for explicit type variables in rule 17 (from SML) has been re-inserted. It is now based on the trace rather than the resulting variable environment. Similar side-conditions have been added to rules 11.1 to 11.3.

Page 36, added a comment to rule 46.

Page 38, the structure of traces has been slightly changed. Traces of the form (C, t) have been added.

Page 40, the class TyRea is introduced. It is later used (page 83) for the definition of state in the verification semantics.

Page 45, a stronger freshness condition is imposed. The old was unsound (and already unsound in SML).

Pages 46f. The principality requirement has been moved from rule 57.1 to rule 61.2. The only noticable consequence of this move seems to be that overloading in axioms inside signatures has to be resolved. There is also a change in the actual principality requirement: the type of an axiomatic expression is now required to be always bool, ruling out expressions of type ∀α.α which would necessarily be non-terminating or exception-raising. A direct consequence of this change was the need of a slight modification of the corresponding two rules in the verification semantics for modules.

Page 47, rule 61.2. Instead of using C of B for the elaboration of the expression we now add the names of B. This is necessary for several technical reasons, e.g. to allow let-expressions over specified types and also to ensure the soundness of axiom verification.

Page 48ff. Specifications are now prohibited to overwrite other specifications. Also, local specifications are required to use other identifiers than global specifications.

Page 57, ~ had been forgotten amongst the basic values.

Page 64, the comment to rule 106 was obsolete.

Page 65, a space inserted in missing rule 114.

Page 86, a function Fresh is introduced to deal with the renaming of type names in the verification semantics. This required certain changes in rules 241 and 242.

Page 90, APPLY now operates on a dynamic value.

Page 91f. The meaning of existential quantification (the true-case for exists and the false-case for forall) has changed: we now require witnesses for all types rather than a witness for the most general type.

Page 94f. The equality has been completely rewritten, especially the comparison of values. It is not longer possible to use == as logical equivalence, it is reserved to compare SML values only. Values are now compared in the state they occur — this solves a local soundness problem in the old presentation of comparison, in which values were compared in a state with possibly too few exception names. Another problem that has been addressed is that s^{##} is now applied to the type τ from the guess.

Page 99. Exception bindings are not any longer needed to be deterministically chosen, because equality works differently now. Therefore, we had to drop the explanation why the choice is deterministic.

Page 104. The combination of interfaces is greatly simplified, thanks to the earlier mentioned new restrictions on specifications.

Page 107, the second m is now m′ (not strictly necessary, but conceptually cleaner).

Page 118. The phrase classes InfExp and InfPat have been exempted from the disambiguation principles.

The state has a new, fifth component l in the verification semantics. This component is initially set to ⊤. Whenever a “free” structure expression strexp^{•} is verificated, it is done so in a state where l is set to ⊥. The difference between both can be seen in rules 312 and 313: the latter (which is new) uses the implementing structure expressions to get the models of interest.

Related to the above change is that functor closures have an additional component, so-called ostrexp for optional structure expression. This is the body of the original functor declaration. The new component is ignored as long as l = ⊤, but for l = ⊥ it is activated — see rule 301. In words, the functor bodies can be used to create arbitrary well-formed structures.

Page 123, strdec second alternative: removed withtype (garbage).

Contents

Defects in This Document i

Changes from version 1.0 ii

1 Introduction 1 1.1 Behavioural equivalence . . . . . . . . . . . . . . . . . . . . . . . . 3 1.2 Metalanguage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2 Syntax of the Core 8 2.1 Reserved Words . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.2 Special constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.3 Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.4 Identifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.5 Lexical analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2.6 Infixed operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2.7 Derived Forms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.8 Grammar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.9 Syntactic Restrictions . . . . . . . . . . . . . . . . . . . . . . . . . . 15

3 Syntax of Modules 16 3.1 Reserved Words . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 3.2 Identifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 3.3 Infixed operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 3.4 Grammar for Modules . . . . . . . . . . . . . . . . . . . . . . . . . 16 3.5 Syntactic Restrictions . . . . . . . . . . . . . . . . . . . . . . . . . . 16 3.6 Closure Restrictions . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

4 Static Semantics for the Core 22 4.1 Simple Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 4.2 Compound Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 4.3 Projection, Injection and Modification . . . . . . . . . . . . . . . . 23 4.4 Types and Type functions . . . . . . . . . . . . . . . . . . . . . . . 25 4.5 Type Schemes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

Traces and Trace Schemes . . . . . . . . . . . . . . . . . . . . . . . 26 Names of a Type Environment . . . . . . . . . . . . . . . . . . . . . 27

4.6 Scope of Explicit Type Variables . . . . . . . . . . . . . . . . . . . 27 4.7 Non-expansive Expressions . . . . . . . . . . . . . . . . . . . . . . . 27 4.8 Closure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 4.9 Type Structures and Type Environments . . . . . . . . . . . . . . . 28 4.10 Inference Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 4.11 Further Restrictions . . . . . . . . . . . . . . . . . . . . . . . . . . 38 5 Static Semantics for Modules 39

5.1 Semantic Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 5.2 Consistency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 5.3 Well-formedness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 5.4 Cycle-freedom . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 5.5 Admissibility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 5.6 Type Realisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 5.7 Realisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

Traces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 Stripping Axioms . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

5.8 Type Explication . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 5.9 Signature Instantiation . . . . . . . . . . . . . . . . . . . . . . . . . 43 5.10 Functor Signature Instantiation . . . . . . . . . . . . . . . . . . . . 43 5.11 Enrichment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 5.12 Signature Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 5.13 Principal Signatures . . . . . . . . . . . . . . . . . . . . . . . . . . 44 5.14 Inference Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

6 Dynamic Semantics for the Core 56 6.1 Reduced Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 6.2 Simple Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 6.3 Compound Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 6.4 Basic Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 6.5 Basic Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 6.6 Closures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

States and Flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 Pure Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60

6.7 Inference Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

7 Dynamic Semantics for Modules 74 7.1 Reduced Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 7.2 Semantic Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 7.3 Inference Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

8 Verification Semantics for the Core 83 8.1 Semantic Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 8.2 Question Mark Interpretation . . . . . . . . . . . . . . . . . . . . . 83 8.3 State . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 8.4 Value Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 8.5 Type Interpretation . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 8.6 Fresh Type Names . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 8.7 Projections to Dynamic and Static Semantics . . . . . . . . . . . . 87 8.8 Relationship to Dynamic Semantics . . . . . . . . . . . . . . . . . . 88 8.9 Sentences of Static and Dynamic Semantics . . . . . . . . . . . . . 89

8.10 Inference Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89

9 Verification Semantics for Modules 103 9.1 Compound Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 9.2 Generalised Axioms . . . . . . . . . . . . . . . . . . . . . . . . . . . 104 9.3 Combining Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . 105 9.4 Extracting Objects of the Static Semantics . . . . . . . . . . . . . . 105 9.5 Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 9.6 Inference Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106

10 Programs 116

A Appendix: Full Grammar 118 A.1 Syntactic Restrictions . . . . . . . . . . . . . . . . . . . . . . . . . . 125

B Appendix: Derived Forms 126 B.1 Semantic Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 B.2 Identifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 B.3 Enrichment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 B.4 Inference Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127

C Appendix: The Initial Basis 144 C.1 The Initial State . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 C.2 The Initial Context for Derived Forms . . . . . . . . . . . . . . . . 144 C.3 The Initial Verification Basis . . . . . . . . . . . . . . . . . . . . . . 146 C.4 Predefined Functions . . . . . . . . . . . . . . . . . . . . . . . . . . 148

References 150

Preface

Extended ML (EML) is a framework for the formal development of programs in the Standard ML (SML) programming language from high-level specifications of their required behaviour. The Extended ML language is a “wide-spectrum” language which encompasses both specifications and executable programs in a single unified framework. This allows all stages in the development of a program to be expressed in the Extended ML language, from the initial high-level specification to the final code itself and including intermediate stages in which specification and code are intermingled.

The Extended ML language is an extension of a large subset of Standard ML. This subset excludes references, assignment, input/output and imperative polymorphism, requires structure declarations and functor declarations to include explicit signatures, and restricts structures and functors to behave as abstractions^{1} and parameterised abstractions respectively. Thus, Extended ML can only be used to specify/develop programs written in this subset of Standard ML. The Extended ML language extends this subset by permitting axioms in module interfaces (for specifying required properties of module components) and in place of code in module bodies (for describing functions in a non-algorithmic way prior to their implementation as Standard ML code).

The principles behind the design of the Extended ML language and development framework, details of its theoretical underpinnings and examples of its use may be found in [ST85], [ST86], [ST89], [San90] and [ST91]. The interested reader should consult these for background information. This document is a formal definition of the syntax and semantics of the Extended ML language; the other components of the Extended ML framework are disregarded here.

In order for Extended ML to serve its purpose as a framework for specifying and formally developing Standard ML programs, it is essential that the definition of the Extended ML language should appropriately “match” the published definition of Standard ML [MTH90]. Given the size of language definitions, such a match is practically impossible to achieve (let alone demonstrate in any convincing way) by post hoc comparison of two independent definitions. For this reason, the definition of Extended ML is based directly on the relevant parts of [MTH90], amended to correct errors and infelicities as described in Appendix D of [MT91] and as suggested in [Kah93] and [Kah94]. In order to make the relationship with Standard ML manifest, the structure of this document is as close as possible to that of [MTH90]. In places where the two languages are identical, the text of [MTH90] (with the indicated amendments) is used without change. For the most part, even the rule numbers and section numbers used in [MTH90] have been retained here. In detail:

1The term “abstraction” is taken from [MacQ86], the original description of the modules facilities of Standard ML. The idea is that only the information that is explicitly recorded in the signature(s) of a structure/functor is available to its clients.

• Sections 2–7 of this document correspond directly to Sections 2–7 of [MTH90]. Although there are a few more rules here than in [MTH90], corresponding rules appear with the same numbers for ease of comparison.

• Sections 8 and 9 are completely new.

• Section 10 here corresponds to Section 8 in [MTH90].

• Appendix A here corresponds directly to Appendix B there.

• Appendix B here is a reformulation of Appendix A there, which also takes care of identifier status (Appendix B of [MT91]) and infix directives.

• Appendix C here corresponds to Appendices C and D there.

The intention is that a “proof” that Extended ML is compatible with Standard ML, if such a thing could ever be constructed, would be based in large part on a simple textual comparison of the two definitions.

Because of the intimate relationship between [MTH90] and this document, familiarity with the former (for which study of [MT91] is strongly recommended!) is almost a prerequisite to achieving a deep understanding of the latter. The length and necessary formality of a definition such as this one makes it rather difficult to penetrate. For this reason an informal overview of the definition, which explains most of the main issues involved and justifies some of the choices taken, is provided in [KST94].

Acknowledgements

Thanks to Fabio da Silva for collaboration on an early version of the syntax and the static and dynamic semantics. Thanks to Thorsten Altenkirch, Mike Fourman, Stephen Gilmore, Robert Harley, Martin Hofmann, Marcin Jurdzinski, Ed Kazmierczak, Mikolaj Konarski, Robin Milner, Claudio Russo, Aleksy Schubert, Mads Tofte and Judith Underwood for helpful discussions, comments and criticisms.

This document contains most of the text of The Definition of Standard ML by Robin Milner, Mads Tofte and Robert Harper (MIT Press, 1990), which is reproduced by kind permission of the authors and MIT Press.

The research reported here was partly supported by SERC grants GR/E78463 (SK, DS, AT), GR/H73103 (SK), GR/H76739 (AT), GR/J07303 (SK, DS) and GR/J07693 (DS), a SERC Advanced Fellowship (DS), the COMPASS Basic Research working group (DS, AT) and KBN grant 2 P301 007 04 (AT).

1 Introduction

This document formally defines the Extended ML language. As explained in the Preface, its structure closely follows that of the definition of Standard ML [MTH90]. Thus, apart from the usual separation between the definition of syntax and semantics, the semantics is divided into several parts:

• The static semantics deals with types (defining when a phrase elaborates to a type or an assembly containing types). It checks that phrases are welltyped, that they do not make reference to unbound identifiers, etc. We claim that the relations defined here are decidable, which means that mechanical type inference is possible.

• The dynamic semantics deals with values (defining when a phrase evaluates to a value). In Extended ML, phrases may specify values without defining them in an executable fashion. The result of evaluation in Extended ML is the same as in Standard ML, provided that such “undefined” values are not used in computing the result; otherwise a special exception is raised. Axioms in signatures and in structure/functor bodies are treated as formal comments by the dynamic semantics. We claim that the relations defined here are semi-decidable, which means that evaluation is implementable although (of course) it may fail to terminate.

• The verification semantics deals with the constraints imposed by axioms (defining when a phrase verificates^{2} to a value or set of values). This includes checking that each structure and functor satisfies the axioms in its interface signature(s). Since axioms are not present in Standard ML, there is nothing in [MTH90] corresponding to the verification semantics. We claim that some of the relations defined here are not semi-decidable, which means that no complete proof system can exist for Extended ML.

Both syntax and semantics are further subdivided by treating the Core and Modules separately. The definition of syntax is also divided into the definition of the Bare language, which can be viewed as abstract syntax, and the definition of the Full language by (computable) translation of derived forms into the Bare language. The initial basis gives names and meanings to all the predefined identifiers in Extended ML. Finally, the semantics of “programs” completes the definition of the Extended ML language by combining the other parts of the definition. Figure 1 shows where all these parts appear in this document, and indicates the direct dependencies between the parts (A ⟶ B means that A directly depends on B, i.e. A explicitly “calls” B). There are further indirect dependencies which must be kept in mind when reading the definition. The dynamic semantics depends on the static semantics, since evaluation of phrases is only guaranteed to be well-defined for phrases that elaborate. The verification semantics depends on 2 1 INTRODUCTION

2A more obvious term is “verify”, but this carries connotations we would like to avoid.

Static semantics for the Core Section 4 Static semantics for Modules Section 5

Bare syntax for the Core Section 2 Dynamic semantics

for the Core Section 6 Dynamic semantics for Modules Section 7

Bare syntax for Modules Section 3

Verification semantics for the Core Section 8 Verification semantics for Modules Section 9

Full syntax Appendix A Derived forms Appendix B Programs Section 10

Initial basis Appendix C

Figure 1: Parts of the definition of Extended ML the static semantics in exactly the same fashion, with the difference that information is explicitly passed from the static semantics to the verification semantics via the program semantics. The initial basis depends on the dynamic semantics, the verification semantics and the derived forms in the sense that it contains semantic objects of classes defined in these sections. Since the metalanguage used for presenting the semantics is non-standard, it is presented later in this section.

1.1 Behavioural equivalence

The verification semantics defines what it means for a structure body to match its interface signature. Roughly speaking, this requires any model of the structure body to satisfy the axioms in the signature. Following ideas concerning the use of axioms to specify encapsulated abstractions, it is possible to relax this requirement by allowing the axioms to be satisfied not “literally”, but only “up to behavioural equivalence” with respect to an appropriate set of “observable types” [ST89]. Similar remarks apply to functor declarations.

The present definition requires literal satisfaction of axioms. We intend to eventually change this to permit satisfaction up to behavioural equivalence, but further study is required before this can be done. Unfortunately, the approach used in previous work on the foundations of formal development in Extended ML, via a definition of behavioural equivalence between models, will not achieve the desired effect because of our use of models incorporating a rather concrete representation of types and values. We believe that a small modification to the meaning of quantification (rules 211–214) and logical equality (rules 224–235) is all that will be required. Before making this change we hope to show that there is a satisfactory relationship between what this yields and the behavioural equivalence relation used for the foundations of formal development, following [BHW94].

1.2 Metalanguage

The semantics of Extended ML is presented in a style known as Natural Semantics [Kah88], or rather an extended version of it. The metalanguage for the presentation of the semantics has rules of the form

\frac{υ_{1} ··· υ_{k}}{ψ}

where the conclusion ψ is a sentence and each premise (or hypothesis) υ_{i} is either a sentence or a rule. In particular we allow for the use of higher-order rules (with rules as premises).

In the presentation of the rules, phrases within single angle brackets ⟨ ⟩ are called first options, and those within double angle brackets ⟨⟨ ⟩⟩ are called second options. To reduce the number of rules, we have adopted the following convention:

In each instance of a rule, the first options must be either all present or all absent; similarly the second options must be either all present or all absent.

Thus, a rule abbreviates four rules if both first and second options occur in its presentation.

Primitive sentences are defined in the various sections of the semantics and are mostly of the form B ⊢ P ⇒ M where B and M are (tuples of) semantic objects and P is a syntactic object. Such a primitive sentence can be read as “against background B, the phrase P may be given the meaning M”. The schema ⊢ ⇒ can be seen as a family of ternary predicate symbols, which are defined by the semantics. These predicate symbols are overloaded for various phrase classes, but the context always resolves this ambiguity: the predicate symbol in the conclusion of a rule is always introduced by a rule section header, e.g. (cf. Section 4.10)

Expressions  C ⊢ exp ⇒ τ, U, γ

introduces a predicate symbol ⊢_{exp} in the static semantics of the Core. The following rules (up to the next rule section, in this particular case rules 9 to 14) all use this predicate symbol in their conclusion. The premises on the other hand use the “closest-fitting” predicate symbol, which will always be uniquely determined. For instance, rule 9 on page 30 in the static semantics seems to have identical premise and conclusion, but ⊢ in the conclusion refers to ⊢_{exp} and ⊢ in the premise to ⊢_{atexp}. The meaning of “closest-fitting” is formalised by ordering the phrase classes of the syntax (languages generated by non-terminals of the grammar) by set inclusion, giving us a partial order on the mentioned predicate symbols: ⊢_{atexp} ≤ ⊢_{exp}, because each atomic expression is an expression as well.

We also allow several other forms of primitive sentences (e.g. x ∈ A) and combine primitive sentences using logical connectives and quantifiers to form nonprimitive sentences.

Metavariables within sentences range over syntactic and semantic objects. The name of a metavariable indicates the class of objects it ranges over. The name of a metavariable for a syntactic object is closely linked to the name of the corresponding phrase class, the language generated by the non-terminal. For example, the metavariable exp ranges over syntactic objects of the phrase class Exp, see Section 2.8. Concerning metavariables for semantic objects, the corresponding convention is introduced in the definition of the semantic objects, e.g. t ∈ TyName in Figure 11 on page 22 introduces t as a metavariable ranging over semantic objects from TyName. This convention extends to priming and subscripting of metavariables, e.g. t′_{1} is also a metavariable ranging over TyName. Finally, we write v/p for a metavariable which ranges over the (disjoint) union of the semantic object classes over which v and p range; they are called compound metavariables.

We interpret rules by translating them into formulae of many-sorted higherorder logic and then interpreting these formulae intuitionistically. Therefore, as a whole, the semantics can be understood as a specification in higher-order logic. Its meaning is the set of consequences of this specification (derivable sentences) in higher-order intuitionistic logic. This approach sidesteps problems with the usual interpretation of such rules as giving an inductive definition of the predicates ⊢ ⇒ , since our use of negated premises and higher-order rules renders this interpretation potentially meaningless. However, it appears that the hierarchical structure of the semantics and the particular way in which the offending constructs are used make it possible to show that such an “inductive” interpretation would be unproblematic and would coincide with the interpretation we formally use here.

For the sake of legibility, the rules do not contain explicit quantifiers on all variables, but we employ instead a number of principles for inserting these in the course of the translation into higher-order logic. Besides the usual binding constructs (quantifiers) in logic, we understand rules (and set comprehensions) as guarding variables. If a variable is guarded by a rule then this fact corresponds to an implicit universal quantifier, provided the variable does not occur unguarded outside the rule. Thus, in contrast to usual binding, guarding operates top-down rather than bottom-up. Unguarded variables are free variables in the usual sense, but guarded variables can also be free, provided they are unguarded in the context of the formula. For instance, if we take implication ⟹ as a guarding operator in first-order logic then the formula (P (x) ⟹ Q(x, y)) ⟹ R(y) is shorthand for ∀y. (∀x. (P (x) ⟹ Q(x, y)) ⟹ R(y)), i.e. the variable x is bound at the inner implication, because it is not unguarded in the context ⟹ R(y).

Let us make this precise. If υ is a rule or sentence and V a set of variables, then [[υ]]_{V} is a pair (V′, Υ), where V′ is a set of variables and Υ a formula in higher-order logic; we say that the variables in V′ occur unguarded in υ. The set V in [[υ]]_{V} serves here as the context of υ; it should be understood as the set of variables occurring unguarded outside υ. Similarly, if t is a term and V a set of variables, then [[t]]_{V} is a pair (t′, V′) where t′ is a term and V′ a set of variables.

We translate a top-level rule ϕ (i.e. one that is not being used as a rule premise) to a formula Φ as follows:

[[\frac{υ_{1}···υ_{n}}{ψ}]] = ∀x_{1}.···.∀x_{k}.(Υ_{1} ∧ ··· ∧ Υ_{n} ⟹ Ψ)

where \{ \begin{matrix}(V_{i}, Υ_{i}) & = & [[υ_{i}]]_{W} \\ (V′, Ψ) & = & [[ψ]]_{W} \\ W & = & V_{1} ∪ ··· ∪ V_{n} ∪ V′ ∪ V_{0} \\ \{x_{1}, …, x_{k}\} & = & W \ V_{0} \end{matrix}

Here, V_{0} are names for (the components of) the initial basis, see Appendix C. For rules not occurring on outermost level the following translation scheme applies:

[[\frac{υ_{1}···υ_{n}}{ψ}]]_{V} = (∅, ∀x_{1}.···.∀x_{k}.∃y_{1}.···.∃y_{l}.(Υ_{1} ∧ ··· ∧ Υ_{n} ⟹ Ψ))

where \{ \begin{matrix}(V_{i}, Υ_{i}) & = & [[υ_{i}]]_{W} \\ (V′, Ψ) & = & [[ψ]]_{W} \\ W & = & V_{1} ∪ ··· ∪ V_{n} ∪ V′ ∪ V \\ \{x_{1}, …, x_{k}\} & = & (V_{1} ∪ ··· ∪ V_{n}) \ V \\ \{y_{1}, …, y_{l}\} & = & V′ \ (V_{1} ∪ ··· ∪ V_{n} ∪ V) \end{matrix}

The properties maintained by the definition of [[υ]]_{V} are that for [[υ]]_{V} = (V′, ϕ), the free variables of ϕ are contained in V ∪V′, and if [[υ]]_{W} = (W′, ϕ′) then V′ = W′, i.e. the set of unguarded variables does not depend on the second argument.

The above definition uniquely determines [[\frac{υ_{1}···υ_{n}}{ψ}]]_{V} up to permutation of bound variables. The cyclic dependency present in the definition can be resolved by first computing the first component of the result for each υ_{i}, the set of unguarded variables — this does not depend on W. The symbol ⟹ in the definition refers to logical implication; it differs from ⇒ which is part of our notation for primitive sentences.

For any sentence ψ, we put [[ψ]]_{V} = (V′, Ψ), where Ψ is defined to be the same as ψ except that quantification in set comprehension is made explicit, see below; V′ are the unguarded variables in ψ (w.r.t. V), where quantification and set comprehension are the only connectives that may guard variables. For a quantified sentence like ∃x.ψ the unguarded variables w.r.t. V are V′ \ {x}, where V′ are the unguarded variables of ψ w.r.t. V. The unguarded variables of a primitive sentence p(A_{1}, …, A_{n}) w.r.t. V are the union of the unguarded variables of the A_{i} (w.r.t. the same V); the same principle applies to terms f(A_{1}, …, A_{n}). Each variable occurs unguarded in itself: [[x]]_{V} = ({x}, x), regardless of whether x is in V or not.

In contrast to the SML semantics, we allow rules as premises of rules. Based on the above translation scheme, such higher-order rules abbreviate formulae containing nested quantifiers, very much in the spirit of Hannan’s “Extended Natural Semantics” [Han93]. Satisfaction of such a premise requires the rule to be admissible. Higher-order rules can be used to express “principality” and other infinitary requirements, as in the following rule 57 of the static semantics for Modules. Principality was described in English in [MTH90].

\frac{C of B ⊢ dec ⇒ E, γ  N = names γ \ N of B  \frac{CofB⊢dec⇒E′,γ′}{(N)γ≻γ′}}{B ⊢ dec ⇒ E, γ}

Applying the translation [[ ]]_{V_{0}} to this rule, we obtain the following formula:

∀B. ∀dec. ∀E. ∀γ. ∀N.
(C of B ⊢ dec ⇒ E, γ ∧ N = names γ \ N of B ∧
∀E′. ∀γ′. (C of B ⊢ dec ⇒ E′, γ′ ⟹ (N)γ ≻ γ′)
⟹ B ⊢ dec ⇒ E, γ)

In expressions (of the metalanguage) such as C of B, C is not a variable but the name of a component of B-like objects. In the metalanguage, “Cof” is a function symbol, the corresponding projection; see Section 4.3.

The important thing to remember about the translation from the metalanguage into formulae is how variables are scoped. In the example, E′ and γ′ are scoped at the local rule because they do not occur unguarded in any of the other components of the top-level rule. On the other hand, B, γ and N have such unguarded occurrences and so no quantifier is introduced for them at the local rule. This scoping principle of the metalanguage corresponds very closely to the scoping principle of explicit type variables in the object language (EML), where value declarations guard type variable occurrences; see Section 4.6.

In the verification semantics for Modules, we use another form, having similar scoping principles as rules have, for describing certain semantic objects: set comprehension. A set comprehension denotes a semantic object (a possibly infinite set) and is of the form {A | ψ} where A denotes a semantic object and ψ is a sentence. It is translated as follows:

[[{A | ψ}]]_{V} = (∅, {y | ∃x_{1}.···.∃x_{k}.(y = A′ ∧ ψ′)})

where \{ \begin{matrix}(V′, ψ′) & = & [[ψ]]_{W} \\ (W′, A′) & = & [[A]]_{W} \\ W & = & V′ ∪ W′ ∪ V \\ \{x_{1}, …, x_{k}\} & = & W \ V \end{matrix}

where y is a fresh variable. Like rules, set comprehensions have no unguarded variables.

We can remove set comprehensions entirely from the translated formulae as follows: a set comprehension {y | ψ} is replaced by a fresh variable Y and the sentence in which it occurs is supplied with an additional premise ∀y.(y ∈ Y ⟺ ψ). As a second-order rewrite rule:

ϕ[{y | ψ}/x] ⟶ ∀Y.(∀y.(y ∈ Y ⟺ ψ) ⟹ ϕ[Y/x]).

As our underlying logic is intuitionistic, these “sets” should be interpreted in a topos, see for instance [Gol84]. The difference is subtle but it matters as we shall encounter “sets” the membership predicate of which is undecidable.

2 Syntax of the Core

2.1 Reserved Words

The reserved words of Extended ML can be divided into two groups, namely:

1. those that are necessary for presenting the grammar of the Core; and

2. those additional reserved words that are needed for presenting the grammar for Modules.

Below we list reserved words of the first group; the rest are listed in Section 3.1. Reserved words may not (except =) be used as identifiers.

    abstype   and   andalso   as    case   do
    datatype   else   end   eqtype   exception   exists
    forall   fn   fun   handle   if   iff  implies   in
    infix   infixr   let   local   nonfix   of   op   open
    orelse   proper   raise   raises   rec   terminates
    then   type   val   with   withtype   while
    (  )   [  ]   {  }  ,  :  ;  ...   _|  =   =>
    ->   #   *)   ?   ==   =/=

2.2 Special constants

An integer constant is any non-empty sequence of digits, possibly preceded by a negation symbol (~). A real constant is an integer constant, possibly followed by a point (.) and one or more digits, possibly followed by an exponent symbol E and an integer constant; at least one of the optional parts must occur, hence no integer constant is a real constant. Examples: 0.7 3.32E5 3E~7 . Non-examples:

23  .3  4.E5  1E2.0 .

We assume an underlying alphabet of 256 characters (numbered 0 to 255) such that the characters with numbers 0 to 127 coincide with the ASCII character set. A string constant is a sequence, between quotes ("), of zero or more printable characters (i.e., numbered 33–126), spaces or escape sequences. Each escape sequence starts with the escape character \ , and stands for a character sequence. The escape sequences are:

\n  A single character interpreted by the system as end-of-line.
\t  Tab.

\^c The control character c, where c may be any character with number 64–95. The number of \^c is 64 less than the number of c.

\ddd The single character with number ddd (3 decimal digits denoting an integer in the interval [0, 255]).

Var  (value variables)  long
Con  (value constructors)  long
ExCon (exception constructors) long
TyVar (type variables)
TyCon (type constructors)  long
Lab  (record labels)
StrId (structure identifiers)  long

Figure 2: Identifiers

   \"       "
   \\       \

\f···f\ This sequence is ignored, where f···f stands for a sequence of

one or more formatting characters.

The formatting characters are a subset of the non-printable characters including at least space, tab, newline, formfeed. The last form allows long strings to be written on more than one line, by writing \ at the end of one line and at the start of the next.

We denote by SCon the class of special constants, i.e., the integer, real, and string constants; we shall use scon to range over SCon.

2.3 Comments

A comment is any character sequence within comment brackets (* *) in which comment brackets are properly nested, i.e. the rules for forming lexical items do not apply within a comment. An unmatched comment bracket should be detected and rejected by the compiler.

No space is allowed between the two characters which make up a comment bracket (* or *). Even an unmatched *) should be detected by the compiler. Thus the expression (op *) is illegal. But (op * ) is legal; so is op* . Furthermore (op **) is legal because of the longest match principle for lexical analysis (see Section 2.5).

2.4 Identifiers

The classes of identifiers for the Core are shown in Figure 2. We use var, tyvar to range over Var, TyVar etc. For each class X marked “long” there is a class longX of long identifiers; if x ranges over X then longx ranges over longX. The syntax of these long identifiers is given by the following:

longx ::= x  identifier
strid_{1}.···.strid_{n}.x qualified identifier (n ≥ 1)

The qualified identifiers constitute a link between the Core and the Modules. Throughout this document, the term “identifier”, occurring without an adjective, refers to non-qualified identifiers only.

An identifier is either alphanumeric: any sequence of letters, digits, primes (') and underbars ( ) starting with a letter or prime, or symbolic: any non-empty sequence of the following symbols

     !  %  &  $  #  +  -  /  :  <  =  >  ?  @  \  ~  `  ^|  *

In either case, however, reserved words are excluded. This means that for example # and | are not identifiers, but ## and |=| are identifiers. The only exception to this rule is that the symbol = , which is a reserved word, is also allowed as an identifier to stand for the equality predicate. The identifier = may not be bound by the user; this precludes any syntactic ambiguity.

A type variable tyvar may be any alphanumeric identifier starting with a prime; the subclass EtyVar of TyVar, the equality type variables, consists of those which start with two or more primes. We exclude^{3} identifiers from TyVar that start with one or two primes followed by an underbar. The other six classes (Var, Con, ExCon, TyCon, Lab and StrId) are represented by identifiers not starting with a prime. However, * is excluded from TyCon, to avoid confusion with the derived form of tuple type (see Figure 22). The class Lab is extended to include the numeric labels 1 2 3 ···, i.e. any numeral not starting with 0.

Identifiers in the classes Var, Con, ExCon, TyCon and StrId all belong to the syntactic class Id. Within syntactic phrases (of the Bare Language), these subclasses are considered to be disjoint: for example, each var ∈ Var has the form idv, being an identifier id ∈ Id labelled with its status information — see Appendix B. Within other semantic objects, the labelling information has no significance. It is used, however, to disambiguate various overloaded forms of environment application: if an environment E contains a structure environment SE and a variable environment VE, then E(ids) is SE(id) and E(idv) is VE(id), etc.

2.5 Lexical analysis

Each item of lexical analysis is either a reserved word, a numeric label, a special constant or a long identifier. Comments and formatting characters separate items and are otherwise ignored. An exception from this rule are formatting characters within string constants; see Section 2.2. At each stage the longest next item is taken.

2.6 Infixed operators

An identifier may be given infix status by the infix or infixr directive, which may occur as a declaration. These declaration are not treated here, but see Appendices A and B.

3The reason for this exclusion is compatibility with Standard ML. The type variables in question are the imperative type variables of Standard ML.

AtExp  atomic expressions
ExpRow expression rows
Exp  expressions
Match  matches
Mrule  match rules
Dec  declarations
ValBind value bindings
TypBind type bindings
DatBind datatype bindings
ConBind constructor bindings
ExBind exception bindings
AtPat  atomic patterns
PatRow pattern rows
Pat  patterns
Ty  type expressions
TyRow  type-expression rows

Figure 3: Core Phrase Classes

2.7 Derived Forms

There are many standard syntactic forms in ML whose meaning can be expressed in terms of a smaller number of syntactic forms, called the Bare language. These derived forms, and their equivalent forms in the Bare language, are given in Appendix B. The rest of this document defines the syntax and semantics of the Bare language, with the exception of Appendices A (the full syntax) and B. The program semantics (Section 10) links the Full language with the semantics of the Bare language.

2.8 Grammar

The phrase classes for the Core are shown in Figure 3. We use the variable atexp to range over AtExp, etc.

The grammatical rules for the Core are shown in Figures 4, 5 and 6. The following conventions are adopted in presenting the grammatical rules,

and in their interpretation:

• The brackets ⟨ ⟩ enclose optional phrases.

• For any syntax class X (over which x ranges) we define the syntax class Xseq (over which xseq ranges) as follows:

xseq ::= x  (singleton sequence)

(empty sequence)

(x_{1},···,x_{n}) (sequence, n ≥ 1)

Note that the “···” used here, meaning syntactic iteration, must not be confused with “...” which is a reserved word of the language. To range over all three alternatives for sequences in semantic rules we write x_{1}···x_{n} (with n ≥ 0), which suppresses the syntactic commas and parentheses. The ambiguity for n = 1 will be harmless whenever we use this notation.

• Alternative forms for each phrase class are in order of decreasing precedence; this resolves ambiguity in parsing, as explained in Appendix A.

• Longest match: Suppose F_{1}F_{2} is an alternative form of a phrase class. A natural number i is called a split index w.r.t. F_{1}F_{2} for a lexical sequence L_{1}···L_{k} if 0 ≤ i ≤ k and L_{1}···L_{i} reduces to F_{1} and L_{i+1}···L_{k} reduces to F_{2}. If for a given lexical sequence L = L_{1}···L_{k} there are different split indices w.r.t. F_{1}F_{2}, then L reduces to F_{1}F_{2} by reducing L_{1}···L_{j} to F_{1}, where j is either the maximal split index, or — iff the alternative form is labelled (R), indicating a right associative infix construct — the minimal split index.

• For any syntax class X (over which x ranges) we define the syntax class X^{•} (over which x^{•} ranges) as the same as X, except that phrases of class X^{•} may not contain the lexical item ?.

Notice that there is a difference between question marks for values and types: question marks for types have to be named, using the second form of typbind, while question marks for values can be anonymous. But a declaration of the form val pat = ? is possible, because one form of expression exp is a question mark.

As a consequence of the refined disambiguation principle for precedence (see Appendix A) sequential declarations are given higher precedence than empty declarations. This is different from SML, but the definition of SML [MTH90] does not fully explain how parsing is affected by precedence.

atexp ::= scon  special constant
longvar  value variable
longcon  value constructor
longexcon  exception constructor
{ ⟨exprow⟩ }  record
let dec in exp end local declaration

( exp )

?  undefined value
exprow ::= lab = exp ⟨ , exprow⟩ expression row
exp  ::= atexp  atomic
exp atexp  application
exp : ty  typed
exp_{1}^{•} == exp_{2}^{•}  comparison (R)
exists match^{•}  existential quantifier
forall match^{•}  universal quantifier
exp^{•} terminates  convergence predicate
exp handle match  handle exception
raise exp  raise exception
fn match  function
match ::= mrule ⟨ | match⟩
mrule ::= pat => exp

dec  ::= val valbind  value declaration
type typbind  type declaration
eqtype typbind  equality type declaration
datatype datbind  datatype declaration
abstype datbind with dec end  abstype declaration
exception exbind  exception declaration
local dec_{1} in dec_{2} end  local declaration
open longstrid_{1} ··· longstrid_{n}  open declaration (n ≥ 1)
dec_{1} ⟨;⟩ dec_{2}  sequential declaration

empty declaration

valbind ::= pat = exp ⟨and valbind⟩

rec valbind

typbind ::= tyvarseq tycon = ty ⟨and typbind⟩ type binding
tyvarseq tycon = ? ⟨and typbind⟩ question mark type binding
datbind ::= tyvarseq tycon = conbind

⟨and datbind⟩

conbind ::= con ⟨of ty⟩ ⟨ | conbind⟩
exbind ::= excon ⟨of ty⟩ ⟨and exbind⟩

excon = longexcon ⟨and exbind⟩ Figure 5: Grammar: Declarations and Bindings

atpat ::=  wildcard
scon  special constant
var  variable
longcon  constant
longexcon  exception constant
{ ⟨patrow⟩ }  record

( pat )

patrow ::= ...  wildcard
lab = pat ⟨ , patrow⟩ pattern row
pat  ::= atpat  atomic
longcon atpat  value construction
longexcon atpat  exception construction
pat : ty  typed
var⟨: ty⟩ as pat  layered
ty  ::= tyvar  type variable
{ ⟨tyrow⟩ }  record type
tyseq longtycon  type construction
ty -> ty′  function type (R)

( ty )

tyrow ::= lab : ty ⟨ , tyrow⟩ type-expression row

Figure 6: Grammar: Patterns and Type Expressions

2.9 Syntactic Restrictions

• No pattern may contain the same var twice. No expression row, pattern row or type row may bind the same lab twice.

• No binding valbind, typbind, datbind or exbind may bind the same identifier twice; this applies also to value constructors within a datbind.

• In the left side tyvarseq tycon of any typbind or datbind, tyvarseq must not contain the same tyvar twice. Any tyvar occurring within the right side must occur in tyvarseq.

• For each value binding pat = exp within rec, exp must be of the form fn match^{4}. The derived form of function-value binding given in Appendix B, rule 380, necessarily obeys this restriction.

4The SML definition adds here “possibly constrained by one or more type expressions”. This is a void extension, because an expression fn pat => exp : ty parses as fn pat => (exp : ty).

3 Syntax of Modules

For Modules there are further reserved words, identifier classes and derived forms. There are no further special constants; comments and lexical analysis are as for the Core. The derived forms for modules concern mainly functors and appear in Appendix B.

3.1 Reserved Words

In addition to the reserved words listed in Section 2.1, Extended ML reserves the following words, which are used in the grammar for Modules:

     axiom    functor    include     sharing
     sig    signature     struct    structure

They may not be used as identifiers.

3.2 Identifiers

The additional identifier classes for Modules are SigId (signature identifiers) and FunId (functor identifiers); they may be either alphanumeric – not starting with a prime – or symbolic. Henceforth, we consider all identifier classes to be disjoint.

3.3 Infixed operators

Fixity directives and their scope are treated in Appendix B.

3.4 Grammar for Modules

The phrase classes for Modules are shown in Figure 7. We use the variable strexp to range over StrExp, etc. The conventions adopted in presenting the grammatical rules for Modules are the same as for the Core. The grammatical rules are shown in Figures 8, 9 and 10. Note that functor bindings and undefined structure bindings are required to include explicit (output) signatures.

Specification expressions specexp occur in axiom descriptions, i.e. in axioms within signatures. This is the only construct of the language in which structures can be declared as local to expressions. This is useful when one wants to express a property that depends on a functor instantiation.

3.5 Syntactic Restrictions

• No binding strbind, sigbind, or funbind may bind the same identifier twice.

• No description valdesc, typdesc, datdesc, exdesc or strdesc may describe the same identifier twice; this applies also to value constructors within a datdesc.

StrExp  structure expressions
StrDec  structure-level declarations
Ax  axioms
AxExp  axiomatic expressions
StrBind  structure bindings
SglStrBind single structure bindings
SigExp  signature expressions
PSigExp  (principal) signature expressions
SigDec  signature declarations
SigBind  signature bindings
Spec  specifications
ValDesc  value descriptions
TypDesc  type descriptions
DatDesc  datatype descriptions
ConDesc  constructor descriptions
ExDesc  exception descriptions
AxDesc  axiom descriptions
SpecExp  specification expressions
StrDesc  structure descriptions
SharEq  sharing equations
FunDec  functor declarations
FunBind  functor bindings
TopDec  top-level declarations

Figure 7: Modules Phrase Classes

• In the tyvarseq tycon in any typdesc or datdesc, tyvarseq must not contain the same tyvar twice. Any tyvar occurring on the right side of the datdesc must occur in tyvarseq.

• In a single structure binding of the form strid = strexp, strexp must be guarded. A structure expression is called guarded if it is of the form longstrid, funid ( strexp ) or let strdec in strexp end, provided (in the last two cases) that strexp is guarded.

The last restriction is for purely methodological reasons: we want each structure to come equipped with an explicit signature. The reason why we include a single structure binding of the form strid = strexp in the language at all is the need to provide a way of realising structure sharing specifications, see [KST94]. The semantic rules for structure bindings do not exploit the guarding requirement.

3.6 Closure Restrictions

The semantics presented in later sections requires no restriction on reference to non-local identifiers. For example, it allows a signature expression to refer to external signature identifiers and (via sharing or open) to external structure identifiers; it also allows a functor (or structure expression) to refer to external identifiers of any kind.

However, implementers who want to provide a simple facility for separate compilation may want to impose the following restrictions (ignoring references to identifiers bound in the initial basis B_{0}, which may occur anywhere):

1. In any signature binding sigid = psigexp , the only non-local references in psigexp are to signature identifiers.

2. In any functor binding funid ( strid : psigexp ) : psigexp′ = strexp , the only non-local references in psigexp, psigexp′ and strexp are to functor and signature identifiers, except that both psigexp′ and strexp may refer to strid and its components.

In the second case the final qualification allows, for example, sharing constraints to be specified between functor argument and result. (For a completely precise definition of these closure restrictions, see the comments to rules 66 (page 49) and 96 (page 54) in the static semantics of modules, Section 5.)

The significance of these restrictions is that they may ease separate compilation and verification; this may be seen as follows. If one takes a module to be a sequence of signature declarations and functor declarations satisfying the above restrictions then the elaboration of a module can be made to depend on the initial static basis alone (in particular, it will not rely on structures outside the module). Moreover, the elaboration of a module cannot create new free structure or type names, so consistency (as defined in Section 5.2, page 40) is automatically preserved across separately compiled modules. On the other hand, imposing these restrictions may force the programmer to write many more sharing equations than is needed if functors and signature expressions can refer to free structures.

strexp  ::= struct strdec end  generative
longstrid  structure identifier
funid ( strexp )  functor application
let strdec in strexp end  local declaration
strdec  ::= dec  declaration
axiom ax  axiom
structure strbind  structure
local strdec_{1} in strdec_{2} end local
strdec_{1} ⟨;⟩ strdec_{2}  sequential

empty

ax  ::= axexp ⟨and ax⟩  axiom
axexp  ::= exp^{•}  axiomatic expression
strbind  ::= sglstrbind ⟨and strbind⟩  structure binding
sglstrbind ::= strid : psigexp = strexp  single structure binding
strid : psigexp = ?  undefined structure binding
strid = strexp  unguarded structure binding
sigexp  ::= sig spec end  generative
sigid  signature identifier
psigexp ::= sigexp  principal signature
sigdec  ::= signature sigbind  single
sigdec_{1} ⟨;⟩ sigdec_{2}  sequential

empty

sigbind  ::= sigid = psigexp ⟨and sigbind⟩

spec  ::= val valdesc  value
type typdesc  type
eqtype typdesc  eqtype
datatype datdesc  datatype
exception exdesc  exception
axiom axdesc  axiom
structure strdesc  structure
sharing shareq  sharing
local spec_{1} in spec_{2} end  local
open longstrid_{1} ··· longstrid_{n}  open (n ≥ 1)
include sigid_{1} ··· sigid_{n}  include (n ≥ 1)
spec_{1} ⟨;⟩ spec_{2}  sequential

empty

valdesc ::= var : ty ⟨and valdesc⟩
typdesc ::= tyvarseq tycon ⟨and typdesc⟩
datdesc ::= tyvarseq tycon = condesc ⟨and datdesc⟩
condesc ::= con ⟨of ty⟩ ⟨ | condesc⟩
exdesc ::= excon ⟨of ty⟩ ⟨and exdesc⟩
axdesc ::= specexp ⟨and axdesc⟩
specexp ::= let strdec in axexp end
strdesc ::= strid : sigexp ⟨and strdesc⟩
shareq ::= longstrid_{1} = ··· = longstrid_{n}  structure sharing
(n ≥ 2)
type longtycon_{1} = ··· = longtycon_{n}  type sharing
(n ≥ 2)
shareq_{1} and shareq_{2}  multiple

fundec ::= functor funbind  single
fundec_{1} ⟨;⟩ fundec_{2}  sequence

empty

funbind ::= funid ( strid : psigexp ) : psigexp′
= strexp ⟨and funbind⟩  functor binding

funid ( strid : psigexp ) : psigexp′

= ? ⟨and funbind⟩  undefined functor binding
topdec ::= strdec  structure-level declaration
sigdec  signature declaration
fundec  functor declaration

Note: No topdec may contain, as an initial segment, a shorter toplevel declaration followed by a semicolon.

Figure 10: Grammar: Functors and Top-level Declarations

4 Static Semantics for the Core

Our first task in presenting the semantics – whether for Core or Modules, static or dynamic – is to define the objects concerned. In addition to the class of syntactic objects, which we have already defined, there are classes of so-called semantic objects used to describe the meaning of the syntactic objects. Some classes contain simple semantic objects; such objects are usually identifiers or names of some kind. Other classes contain compound semantic objects, such as types or environments, which are constructed from component objects.

4.1 Simple Objects

All semantic objects in the static semantics of the entire language are built from identifiers and two further kinds of simple objects: type constructor names and structure names. Type constructor names are the values taken by type constructors; we shall usually refer to them briefly as type names, but they are to be clearly distinguished from type variables and type constructors. Structure names play an active role only in the Modules semantics; they enter the Core semantics only because they appear in structure environments, which (in turn) are needed in the Core semantics only to determine the values of long identifiers. The simple object classes, and the variables ranging over them, are shown in Figure 11. We have included TyVar in the table to make visible the use of α in the semantics to range over TyVar.

α or tyvar ∈ TyVar  type variables
t ∈ TyName  type names
m ∈ StrName structure names

Figure 11: Simple Semantic Objects

The sets TyName and StrName are arbitrary infinite sets, except that TyName is a superset of T_{0} (type names of the initial basis), see Section C.3.

Each α ∈ TyVar possesses a boolean equality attribute, which determines whether or not it admits equality, i.e. whether it is a member of EtyVar (defined on page 10). There is a distinguished type variable num; it is in EtyVar, but it has no syntactic representation in EML.

Each t ∈ TyName has an arity k ≥ 0, and also possesses an equality attribute. We denote the class of type names with arity k by TyName^{(k)}.

With each special constant scon we associate a type name type(scon) which is either int, real or string as indicated by Section 2.2.

4.2 Compound Objects

When A and B are sets Fin A denotes the set of finite subsets of A, and A →^{fin} B denotes the set of finite maps (partial functions with finite domain) from A to B. The domain and range of a finite map, f, are denoted Dom f and Ran f. A finite map will often be written explicitly in the form {a_{1} ↦ b_{1}, ···, a_{k} ↦ b_{k}}, k ≥ 0; in particular the empty map is {}. We shall use the form {x ↦ e ; ϕ} — a form of set comprehension — to stand for the finite map f whose domain is the set of values x which satisfy the condition ϕ, and whose value on this domain is given by f(x) = e. This notation slightly differs from those set comprehensions denoting sets (see page 7), for which we use a | to separate the condition.

When f and g are finite maps the map f + g, called f modified by g, is the finite map with domain Dom f ∪ Dom g and values

(f + g)(a) = if a ∈ Dom g then g(a) else f(a).

For any semantic object class A, we define Tree(A) to be the finite binary trees of elements taken from A, i.e. Tree(A) is the smallest solution of the domain equation Tree(A) = {ϵ} ⊎ A ⊎ {x · y | x, y ∈ Tree(A)}. We take · to be leftassociative, i.e. x · y · z stands for (x · y) · z.

The compound objects for the static semantics of the Core Language are shown in Figure 12. We take ⊎ to mean disjoint union over semantic object classes. We also understand all the defined object classes to be disjoint.

Note that Λ and ∀ bind type variables. For any semantic or syntactic object A, tynames A and tyvars A denote respectively the set of type names and the set of type variables occurring free in A.

4.3 Projection, Injection and Modification

Projection: We often need to select components of tuples – for example, the variable-environment component of a context. In such cases we rely on variable names to indicate which component is selected. For instance “VE of E” means “the variable-environment component of E” and “m of S” means “the structure name of S”.

Moreover, when a tuple contains a finite map we shall “apply” the tuple to an argument, relying on the syntactic class of the argument to determine the relevant function. For instance C(tycon) means (TE of C)tycon.

A particular case needs mention: C(con) is taken to stand for (VE of C)con. The type scheme of a value constructor is held in VE as well as in TE (where it will be recorded within a CE). Thus the re-binding of a constructor is given proper effect by accessing it in VE, rather than in TE.

Finally, environments may be applied to long identifiers. For instance if longcon = strid_{1}.···.strid_{k}.con then E(longcon) means

(VE of (SE of ···(SE of (SE of E)strid_{1})strid_{2}···)strid_{k})con.

τ ∈ Type = TyVar ⊎ RecType ⊎ FunType ⊎ ConsType
(τ_{1}, ···, τ_{k}) or τ^{(k)} ∈ Type^{k}
(α_{1}, ···, α_{k}) or α^{(k)} ∈ TyVar^{k}
ϱ ∈ RecType = Lab →^{fin} Type
τ → τ′ ∈ FunType = Type × Type

ConsType = ⊎_{k≥0}ConsType^{(k)}

τ^{(k)}t ∈ ConsType^{(k)} = Type^{k} × TyName^{(k)}
θ or Λα^{(k)}.τ ∈ TypeFcn = ⊎_{k≥0}TyVar^{k} × Type
σ or ∀α^{(k)}.τ ∈ TypeScheme = ⊎_{k≥0}TyVar^{k} × Type
S or (m, E) ∈ Str = StrName × Env
(θ, CE) ∈ TyStr = TypeFcn × ConEnv
SE ∈ StrEnv = StrId →^{fin} Str
TE ∈ TyEnv = TyCon →^{fin} TyStr
CE ∈ ConEnv = Id →^{fin} TypeScheme
VE ∈ VarEnv = Id →^{fin} TypeScheme
E or (SE, TE, VE) ∈ Env = StrEnv × TyEnv × VarEnv
T ∈ TyNameSet = Fin(TyName)
U ∈ TyVarSet = Fin(TyVar)
C or T, U, E ∈ Context = TyNameSet × TyVarSet × Env
φ_{Ty} ∈ TyRea = TyName → TypeFcn
γ ∈ Trace = Tree(SimTrace ⊎ TraceScheme)

SimTrace = Type ⊎ Env ⊎ (Context × Type) ⊎ (Context × Env) ⊎ (Context × TyName) ⊎ TyEnv ⊎ (Env × TyRea)

TraceScheme = ⊎_{k≥0}TraceScheme^{(k)}

∀α^{(k)}.γ ∈ TraceScheme^{(k)} = TyVar^{k} × Trace

Figure 12: Compound Semantic Objects

Injection: Components may be injected into tuple classes; for example, “VE in Env” means the environment ({}, {}, VE). The default values for the missing components are always ∅, {}, or tuples of these. Injection into disjoint union classes is usually left implicit, with a few exceptions where we also use the “In” notation for it. For brevity, we often express the composition of injections by a single injection.

Modification: The modification of one map f by another map g, written f + g, has already been mentioned. It is commonly used for environment modification, for example E + E′. Often, empty components will be left implicit in a modification; for example E + VE means E + ({}, {}, VE). For set components, modification means union, so that C + (T, VE) means

( (T of C) ∪ T, U of C, (E of C) + VE )

We frequently need to modify a context C by an environment E (or a type environment TE say), at the same time extending T of C to include the type names of E (or of TE say). We therefore define C ⊕ TE, for example, to mean C + (tynames TE, TE).

4.4 Types and Type functions

A type τ is an equality type, or admits equality, if it is of one of the forms

• α, where α admits equality;

• {lab_{1} ↦ τ_{1}, ···, lab_{n} ↦ τ_{n}}, where each τ_{i} admits equality;

• τ^{(k)}t, where t and all members of τ^{(k)} admit equality.

A type function θ = Λα^{(k)}.τ has arity k; it must be closed – i.e. tyvars(τ) ⊆ α^{(k)} – and the bound variables must be distinct. Two type functions are considered equal if they only differ in their choice of bound variables (alpha-conversion). In particular, the equality attribute has no significance in a bound variable of a type function; for example, Λα.α → α and Λβ.β → β are equal type functions even if α admits equality but β does not. If t has arity k, then we write t to mean Λα^{(k)}.α^{(k)}t (eta-conversion); thus TyName ⊆ TypeFcn. θ = Λα^{(k)}.τ is an equality type function, or admits equality, if when the type variables α^{(k)} are chosen to admit equality then τ also admits equality.

We write the application of a type function θ to a vector τ^{(k)} of types as τ^{(k)}θ. If θ = Λα^{(k)}.τ we set τ^{(k)}θ = τ{τ^{(k)}/α^{(k)}} (beta-conversion).

We write τ{θ^{(k)}/t^{(k)}} for the result of substituting type functions θ^{(k)} for type names t^{(k)} in τ. Here and for other forms of substitution maps, we use the notation {t/x ; ϕ} instead of {x ↦ t ; ϕ}. We assume that all beta-conversions are carried out after substitution, so that for example

(τ^{(k)}t){Λα^{(k)}.τ/t} = τ{τ^{(k)}/α^{(k)}}.

4.5 Type Schemes

A type substitution is a finite map ϑ ∈ TyVar →^{fin} Type, where ϑ(α) admits equality if α does, and where ϑ(num) is either int or real (provided num is in the domain of ϑ). Type substitutions extend to functions on other semantic objects, e.g. to functions between types by mapping a type τ to τ{ϑ(α)/α ; α ∈ Dom ϑ}.

A type scheme σ = ∀α^{(k)}.τ generalises a type τ′, written σ ≻ τ′, if there exists a type substitution ϑ with domain α^{(k)} ∩ tyvars(τ) such that ϑ(τ) = τ′. We make the type substitution of a generalisation explicit by writing σ ≻_{ϑ} τ′. If σ′ = ∀β^{(l)}.τ′ then σ generalises σ′, written σ ≻ σ′, if σ ≻ τ′ and β^{(l)} contains no free type variable of σ. It can be shown that σ ≻ σ′ iff, for all τ′′, whenever σ′ ≻ τ′′ then also σ ≻ τ′′.

Two type schemes σ and σ′ are considered equal if they can be obtained from each other by renaming and reordering of bound type variables, and deleting type variables from the prefix which do not occur in the body. Here, in contrast to the case for type functions, the equality attribute must be preserved in renaming; for example ∀α.α → α and ∀β.β → β are only equal if either both α and β admit equality, or neither does. It can be shown that σ = σ′ iff σ ≻ σ′ and σ′ ≻ σ.

We consider a type τ to be a type scheme, identifying it with ∀().τ.

Traces and Trace Schemes

Traces record objects of the static semantics. The purpose of this recording is twofold: (i) it reifies choices that have been made during static analysis, making it possible to talk about all possible choices for the elaboration of a phrase; and (ii) semantic objects that are involved in the elaboration of a phrase become visible for verification purposes. One can informally view traces as information hung on the syntax tree by static analysis for use by the verification semantics.

Traces can contain bound type variables: in traces of the form ∀α^{(k)}.γ the type variables α^{(k)} bind occurrences of those variables in γ. The definition of equality of trace schemes is analogous to that of type schemes. The generalisation of traces ≻ is defined as follows:

γ  ≻ γ  ⟸ γ ∈ SimTrace
γ_{1} · γ_{2} ≻ γ′_{1} · γ′_{2} ⟸ γ_{1} ≻ γ′_{1} ∧ γ_{2} ≻ γ′_{2}
∀α^{(k)}.γ ≻ ϑ(γ) ⟸ Dom ϑ = α^{(k)}
γ_{1}  ≻ γ_{3}  ⟸ there exists γ_{2} such that γ_{1} ≻ γ_{2} ∧ γ_{2} ≻ γ_{3}
γ_{1}  ≻ γ_{2}  ⟸ for all γ_{3}, γ_{2} ≻ γ_{3} ⟹ γ_{1} ≻ γ_{3}

It can be shown that generalisation between type schemes is a special case of generalisation between traces.

Names of a Type Environment

We define an auxiliary function Tnames : TyEnv → TyNameSet as follows:

Tnames(TE) = {t | (t, CE) ∈ Ran TE}

The purpose of this function is to select all type names defined in a type environment.

4.6 Scope of Explicit Type Variables

In the Core language, a type or datatype binding can explicitly introduce type variables whose scope is that binding. In the modules, a description of a value, type, or datatype may contain explicit type variables whose scope is that description. However, we still have to account for the scope of an explicit type variable occurring in the “: ty” of a typed expression or pattern. For the rest of this section, we consider such occurrences of type variables only.

We call value declarations, axiom declarations and specifications, quantifier expressions and expressions of the form exp_{1}^{•} == exp_{2}^{•} guarding constructs. Every occurrence of a guarding construct is said to scope a set of explicit type variables determined as follows.

First, an occurrence of α in a guarding construct phrase is said to be unguarded if the occurrence is not part of a smaller guarding construct within phrase. In this case we say that α occurs unguarded in the guarding construct.

Then we say that α is scoped at a particular occurrence O of a guarding construct in a program if (1) α occurs unguarded in this construct, and (2) α does not occur unguarded in any larger guarding construct containing the occurrence O.

The inference rules in Section 4.10 make this explicit (in contrast to the SML static semantics in [MTH90]). If phrase is a guarding construct, then its sentences are typically derived with premises of the form C + U ⊢ phrase ⇒ A, U, γ for some metavariable A. The two occurrences of U mean that every type variable occurring unguarded in phrase cannot be locally bound within phrase.

4.7 Non-expansive Expressions

Deleted

4.8 Closure

Let τ be a type and A a semantic object. Then Clos_{A}(τ), the closure of τ with respect to A, is the type scheme ∀α^{(k)}.τ, where α^{(k)} = tyvars(τ) \ tyvars A. Commonly, A will be a context C. We abbreviate the total closure Clos_{{}}(τ) to Clos(τ). If the range of a variable environment VE contains only types (rather than arbitrary type schemes) we set

Clos_{A}VE = {id ↦ Clos_{A}(τ) ; VE(id) = τ}

with a similar definition for Clos_{A}CE.

There is also a similar closure operation for traces: Clos_{A}γ = ∀α^{(k)}.γ, where α^{(k)} = tyvars(γ) \ tyvars A.

4.9 Type Structures and Type Environments

A type structure (θ, CE) is well-formed if either CE = {}, or θ is a type name t. (The latter case arises, with CE ≠ {}, in datatype declarations.) All type structures occurring in elaborations are assumed to be well-formed.

A type structure (t, CE) is said to respect equality if, whenever t admits equality, then for each CE(con) of the form ∀α^{(k)}.(τ → α^{(k)}t), the type function Λα^{(k)}.τ also admits equality. (This ensures that the SML equality predicate = will be applicable to a constructed value (con, v) of type τ^{(k)}t only when it is applicable to the value v itself, whose type is τ{τ^{(k)}/α^{(k)}}.) A type environment TE respects equality if all its type structures do so.

Let TE be a type environment, and let T be the set of type names t such that (t, CE) occurs in TE for some CE ≠ {}. Then TE is said to maximise equality if (a) TE respects equality, and also (b) if any larger subset of T were to admit equality (without any change in the equality attribute of any type names not in T) then TE would cease to respect equality.

For any TE of the form

TE = {tycon_{i} ↦ (t_{i}, CE_{i}) ; 1 ≤ i ≤ k},

where no CE_{i} is the empty map, and for any E we define Abs_{C}(TE, E) to be the environment obtained from E and TE as follows. First, let Abs_{C}(TE) be the type environment {tycon_{i} ↦ (t_{i}, {}) ; 1 ≤ i ≤ k} in which all constructor environments CE_{i} have been replaced by the empty map. Let t′_{1}, …, t′_{k} be new distinct type names (“new” means that t′_{1}, …, t′_{k} are not in T ofC), none of which admit equality. Then Abs_{C}(TE, E) is the result of simultaneously substituting t′_{i} for t_{i}, 1 ≤ i ≤ k, throughout Abs_{C}(TE) + E. (The effect of the latter substitution is to ensure that the use of SML equality on an abstype is restricted to the with part.) Let φ_{Ty} be the type realisation with Supp(φ_{Ty}) ⊆ {t′_{1}, …, t′_{k}} and φ_{Ty}(t′_{i}) = t_{i}, 1 ≤ i ≤ k; we write Abs_{C}(TE, E) =_{φ_{Ty}} E′ to say that Abs_{C}(TE, E) = E′ via the type realisation φ_{Ty}. Type realisations are defined in Section 5.6.

4.10 Inference Rules

Each rule of the semantics allows inferences among sentences of the form

A ⊢ phrase ⇒ A′

where A is usually a context, phrase is a phrase of the Core, and A′ is a semantic object — usually a type or an environment or assembly of such objects, together with a trace. It may be pronounced “phrase elaborates to A′ in (context) A”.

Some rules have extra hypotheses not of this form; these hypotheses are called side conditions.

Atomic Expressions  C ⊢ atexp ⇒ τ, U, γ
C ⊢ scon ⇒ type(scon), ∅, ϵ

(1)

\frac{C(longvar) ≻ τ}{C ⊢ longvar ⇒ τ, ∅, τ}  (2)

\frac{C(longcon) ≻ τ}{C ⊢ longcon ⇒ τ, ∅, τ}  (3)

\frac{C(longexcon) = τ}{C ⊢ longexcon ⇒ τ, ∅, ϵ}  (4)

\frac{⟨C ⊢ exprow ⇒ ϱ, U, γ⟩}{C ⊢ \{ ⟨exprow⟩ \} ⇒ \{\}⟨+ ϱ⟩ in Type, ∅⟨ ∪ U⟩, ϵ⟨·γ⟩}  (5)

\frac{C ⊢ dec ⇒ E, γ  C ⊕ E ⊢ exp ⇒ τ, U, γ′ tynames τ ⊆ T of C}{C ⊢ let dec in exp end ⇒ τ, U, γ · γ′}  (6)

\frac{C ⊢ exp ⇒ τ, U, γ}{C ⊢ ( exp ) ⇒ τ, U, γ}  (7)

\overline{C ⊢ ? ⇒ τ, ∅, (C, τ)}  (7.1)

Comments:

(2),(3) The instantiation of type schemes allows different occurrences of a single longvar or longcon to assume different types.

(6) The use of ⊕, here and elsewhere, ensures that type names generated by the first sub-phrase are different from type names generated by the second sub-phrase.

The third premise is not present in the SML definition. Simply omitting it would compromise the soundness of type inference, because type names introduced by different let expressions could become equal. This was an oversight in the definition of SML [MTH90] which was not fixed in [MT91]; see also [Kah93]. Some Standard ML implementations have a less restrictive method for type-checking let-expressions which is still sound but allows local datatypes to escape from the scope of the let.

Notice that there are no unguarded occurrences of explicit type variables in declarations, as the form of sentences for declarations indicates. This differs from SML, which permits (unguarded) imperative type variables in exception declarations.

(7.1) A ? can have any type. The context C is stored in the trace to enable verification to type-check the chosen replacement for ? in a given model, see rule 201.

Expression Rows  C ⊢ exprow ⇒ ϱ, U, γ
\frac{C ⊢ exp ⇒ τ, U, γ  ⟨C ⊢ exprow ⇒ ϱ, U′, γ′⟩}{C ⊢ lab = exp ⟨ , exprow⟩ ⇒ \{lab ↦ τ\}⟨+ ϱ⟩, U⟨ ∪ U′⟩, γ⟨·γ′⟩}  (8)

Expressions  C ⊢ exp ⇒ τ, U, γ
\frac{C ⊢ atexp ⇒ τ, U, γ}{C ⊢ atexp ⇒ τ, U, γ}  (9)

\frac{C ⊢ exp ⇒ τ′ → τ, U, γ  C ⊢ atexp ⇒ τ′, U′, γ′}{C ⊢ exp atexp ⇒ τ, U ∪ U′, γ · γ′}  (10)

\frac{C ⊢ exp ⇒ τ, U, γ  C ⊢ ty ⇒ τ  U′ = tyvars ty}{C ⊢ exp : ty ⇒ τ, U ∪ U′, γ}  (11)

\frac{C + U ⊢ exp_{1}^{•} ⇒ τ, U_{1}, γ_{1} C + U ⊢ exp_{2}^{•} ⇒ τ, U_{2}, γ_{2} U = U_{1} ∪ U_{2} γ′ = Clos_{C}((C, τ) · γ_{1} · γ_{2})  tyvars γ′ ∩ U ⊆ U of C}{C ⊢ exp_{1}^{•} == exp_{2}^{•} ⇒ bool, ∅, γ′} (11.1)

\frac{C + U ⊢ match^{•} ⇒ τ → bool, U, γ γ′ = Clos_{C}((C, τ) · γ) U ∩ tyvars γ′ ⊆ U of C}{C ⊢ exists match^{•} ⇒ bool, ∅, γ′}  (11.2)

\frac{C + U ⊢ match^{•} ⇒ τ → bool, U, γ γ′ = Clos_{C}((C, τ) · γ) U ∩ tyvars γ′ ⊆ U of C}{C ⊢ forall match^{•} ⇒ bool, ∅, γ′}  (11.3)

\frac{C ⊢ exp^{•} ⇒ τ, U, γ}{C ⊢ exp^{•} terminates ⇒ bool, U, ϵ}  (11.4)

\frac{C ⊢ exp ⇒ τ, U, γ  C ⊢ match ⇒ exn → τ, U′, γ′}{C ⊢ exp handle match ⇒ τ, U ∪ U′, γ · γ′}  (12)
\frac{C ⊢ exp ⇒ exn, U, γ}{C ⊢ raise exp ⇒ τ, U, τ · γ}  (13)
\frac{C ⊢ match ⇒ τ, U, γ}{C ⊢ fn match ⇒ τ, U, (C, τ) · γ}  (14)

Comments:

(9) The relation symbol ⊢ is overloaded for all syntactic classes (here atomic expressions and expressions). Thus, the relational symbol ⊢ refers in the premise to the predicate for atomic expressions as defined in rules 1 to 7.1.

(11) Here τ is determined by C and ty. Notice that type variables in ty cannot be instantiated in obtaining τ; thus the expression 1:'a will not elaborate successfully, nor will the expression (fn x=>x):'a->'b. The effect of type variables in an explicitly typed expression is to indicate exactly the degree of polymorphism present in the expression.

(11.1)–(11.3) Equality and quantification are guarding constructs, i.e. any type variable occurring in them is guarded. Any type variable occuring unguarded within a guarding construct is scoped at that construct, provided it is not already scoped in the context: this is expressed by extending the context with +U which prohibits these type variables from being bound locally by the closure operator.

Superficially the set of unguarded variables is defined to be an arbitrary fixpoint, because U occurs left from “⊢” and right from “⇒”. However, this fixpoint is unique: the unguarded variables of a syntactic object are independent from its context.

Storing C and τ in the trace is necessary for the verification semantics, to select appropriate witnesses for the quantifiers, and to compare values. We require quantification and comparison in the verification semantics to behave uniformly: abstracting type variables via Clos_{C} here allows the verification semantics to instantiate the traces arbitrarily.

(11.4) The expression exp^{•} will not be subject to verification; only its termination behaviour in the dynamic semantics is of interest. The dynamic semantics does not need any type information, thus the empty trace ϵ in the result.

(13) Note that τ does not occur in the premise; thus a raise expression has “arbitrary” type. For the same reason, its type has to be recorded in the trace.

(14) The context C is part of the result trace so that match can be type-checked after replacing all its question marks with the corresponding choices of a given model.

Matches  C ⊢ match ⇒ τ, U, γ
\frac{C ⊢ mrule ⇒ τ, U, γ  ⟨C ⊢ match ⇒ τ, U′, γ′⟩}{C ⊢ mrule ⟨ | match⟩ ⇒ τ, U⟨ ∪ U′⟩, γ⟨·γ′⟩}  (15)

Match Rules  C ⊢ mrule ⇒ τ, U, γ
\frac{C ⊢ pat ⇒ (VE, τ), U, γ  C ⊕ VE ⊢ exp ⇒ τ′, U′, γ′}{C ⊢ pat => exp ⇒ τ → τ′, U ∪ U′, γ · γ′}  (16)

Comment: This rule allows new free type variables to enter the context. These new type variables will be chosen, in effect, during the elaboration of pat (i.e., in the inference of the first hypothesis). In particular, their choice may have to be made to agree with type variables present in any explicit type expression occurring within exp (see rule 11).

Notice that rule 16 uses C ⊕ VE in contrast to the SML definition, which uses C + VE here. The reason for this change is another soundness problem, similar to the one mentioned for rule 6, but a bit more involved. This problem was not mentioned in [MT91] or [Kah93], see [Kah94].

Declarations  C ⊢ dec ⇒ E, γ

\frac{C + U ⊢ valbind ⇒ VE, U, γ VE′ = Clos_{C}VE  γ′ = Clos_{C}γ  U ∩ tyvars γ′ ⊆ U of C}{C ⊢ val valbind ⇒ VE′ in Env, γ′}  (17)

\frac{C ⊢ typbind ⇒ TE, γ}{C ⊢ type typbind ⇒ TE in Env, TE · γ}  (18)

\frac{C ⊢ typbind ⇒ TE, γ  ∀(θ, CE) ∈ Ran TE, θ admits equality}{C ⊢ eqtype typbind ⇒ TE in Env, TE · γ}  (18.1)

\frac{C ⊕ TE ⊢ datbind ⇒ VE, TE, γ  ∀(t, CE) ∈ Ran TE, t ∉ (T of C) E = (VE, TE) in Env TE maximises equality}{C ⊢ datatype datbind ⇒ E, E · γ} (19)

\frac{C ⊕ TE ⊢ datbind ⇒ VE, TE, γ  ∀(t, CE) ∈ Ran TE, t ∉ (T of C) C ⊕ (VE, TE) ⊢ dec ⇒ E, γ′ TE maximises equality E′′ = (VE, TE) in Env  Abs_{C}(TE, E) =_{φ_{Ty}} E′}{C ⊢ abstype datbind with dec end ⇒ E′, (E′′, φ_{Ty}) · γ · γ′} (20)

\frac{C ⊢ exbind ⇒ VE, γ}{C ⊢ exception exbind ⇒ VE in Env, γ}  (21)

\frac{C ⊢ dec_{1} ⇒ E_{1}, γ_{1} C ⊕ E_{1} ⊢ dec_{2} ⇒ E_{2}, γ_{2}}{C ⊢ local dec_{1} in dec_{2} end ⇒ E_{2}, γ_{1} · γ_{2}}  (22)

\frac{C(longstrid_{1}) = (m_{1}, E_{1}) ··· C(longstrid_{n}) = (m_{n}, E_{n})}{C ⊢ open longstrid_{1} ··· longstrid_{n} ⇒ E_{1} + ··· + E_{n}, ϵ}  (23)

\overline{C ⊢  ⇒ \{\} in Env, ϵ}  (24)

\frac{C ⊢ dec_{1} ⇒ E_{1}, γ_{1} C ⊕ E_{1} ⊢ dec_{2} ⇒ E_{2}, γ_{2}}{C ⊢ dec_{1} ⟨;⟩ dec_{2} ⇒ E_{1} + E_{2}, γ_{1} · γ_{2}}  (25)

Comments:

(17) Here VE will contain types rather than general type schemes. The closure of VE is exactly what allows variables to be used polymorphically, via rule 2.

The side-condition on U ensures compatibility with SML, which requires that type variables are abstracted at their scoping construct.

(18) Within typbind there might be ?-types, i.e. there might be newly introduced type names. Notice that their equality attributes are not affected by this rule, but that principality of environments can affect it later (rule 57) — a type with equality attribute is more specific.

(18),(18.1) The verification semantics exploits type information; storing the type environment TE in the trace is one way to make the needed information accessible for later verification purposes.

(19),(20) The side conditions express that the elaboration of each datatype binding generates new type names and that as many of these new names as possible admit equality. Adding TE to the context on the left of the ⊢ in the first premise captures the recursive nature of the binding.

To see why an environment E etc. is stored in the trace, one has to look at these rules in connection with the corresponding rules of the verification semantics, here 244 and 245.

(20) The Abs_{C} operation was defined in Section 4.9, page 28.

(21) No closure operation is used here, since exception bindings do not contain type variables.

Value Bindings  C ⊢ valbind ⇒ VE, U, γ

\frac{C ⊢ pat ⇒ (VE, τ), U, γ  C ⊢ exp ⇒ τ, U′, γ′ ⟨C ⊢ valbind ⇒ VE′, U′′, γ′′⟩}{C ⊢ pat = exp ⟨and valbind⟩ ⇒ VE ⟨+ VE′⟩, U ∪ U′⟨ ∪ U′′⟩, γ · γ′⟨·γ′′⟩} (26)

\frac{C + VE ⊢ valbind ⇒ VE, U, γ}{C ⊢ rec valbind ⇒ VE, U, γ}  (27)

Comments:

(26) When the option is present we have Dom VE ∩Dom VE′ = ∅ by the syntactic restrictions.

(27) Modifying C by VE on the left of the premise captures the recursive nature of the binding. From rule 26 we see that any type scheme occurring in VE will have to be a type. Thus each use of a recursive function in its own body must be ascribed the same type.

Type Bindings  C ⊢ typbind ⇒ TE, γ

\frac{tyvarseq = α^{(k)} C ⊢ ty ⇒ τ  ⟨C ⊢ typbind ⇒ TE, γ⟩}{C ⊢ tyvarseq tycon = ty ⟨and typbind⟩ ⇒ \{tycon ↦ (Λα^{(k)}.τ, \{\})\} ⟨+ TE⟩, ϵ⟨·γ⟩}  (28)

\frac{tyvarseq = α^{(k)} t ∉ (T of C), arity t = k ⟨C + \{t\} ⊢ typbind ⇒ TE, γ⟩}{C ⊢ tyvarseq tycon = ? ⟨and typbind⟩ ⇒ \{tycon ↦ (t, \{\})\} ⟨+ TE⟩, (C, t)⟨·γ⟩}  (28.1)

Comments:

(28) The syntactic restrictions ensure that the type function Λα^{(k)}.τ satisfies the well-formedness constraints of Section 4.4 and that tycon ∉ Dom TE.

(28.1) Question mark types are treated as new types for the purposes of static analysis (premise t ∉ (T of C)). In a given model (verification semantics), the type name t will be replaced by an appropriate type function, see rule 255; C and t are stored in the trace for the purposes of that replacement.

Data Type Bindings  C ⊢ datbind ⇒ VE, TE, γ

tyvarseq = α^{(k)} C, α^{(k)}t ⊢ conbind ⇒ CE, γ

⟨C ⊢ datbind ⇒ VE, TE, γ′ ∀(t′, CE) ∈ Ran TE, t ≠ t′⟩

C ⊢ tyvarseq tycon = conbind ⟨and datbind⟩ ⇒ ClosCE ⟨+ VE⟩, {tycon ↦ (t, ClosCE)} ⟨+ TE⟩, γ⟨·γ′⟩

(29)

Comment: The syntactic restrictions ensure Dom VE ∩ Dom CE = ∅ and tycon ∉ Dom TE.

Constructor Bindings  C, τ ⊢ conbind ⇒ CE, γ

\frac{con = idc ⟨C, τ ⊢ conbind ⇒ CE, γ⟩}{C, τ ⊢ con ⟨ | conbind⟩ ⇒ \{id ↦ τ\} ⟨+ CE⟩, τ⟨·γ⟩}  (30)

\frac{con = idc C ⊢ ty ⇒ τ′ τ′′ = τ′ → τ ⟨C, τ ⊢ conbind ⇒ CE, γ⟩}{C, τ ⊢ con of ty ⟨ | conbind⟩ ⇒ \{id ↦ τ′′\} ⟨+ CE⟩, τ′′⟨·γ⟩}  (30.1)

Comments:

(30),(30.1) By the syntactic restrictions con ∉ Dom CE.

Exception Bindings  C ⊢ exbind ⇒ VE, γ

\frac{excon = ide ⟨C ⊢ exbind ⇒ VE, γ⟩}{C ⊢ excon ⟨and exbind⟩ ⇒ \{id ↦ exn\} ⟨+ VE⟩, ϵ⟨·γ⟩}  (31)

\frac{excon = ide C ⊢ ty ⇒ τ  tyvars(ty) = ∅ ⟨C ⊢ exbind ⇒ VE, γ⟩}{C ⊢ excon of ty ⟨and exbind⟩ ⇒ \{id ↦ τ → exn\} ⟨+ VE⟩, τ⟨·γ⟩}  (31.1)

\frac{excon = ide C(longexcon) = τ  ⟨C ⊢ exbind ⇒ VE, γ⟩}{C ⊢ excon = longexcon ⟨and exbind⟩ ⇒ \{id ↦ τ\} ⟨+ VE⟩, ϵ⟨·γ⟩} (32)

Comments:

(31.1) Notice that ty must not contain any type variables. This is slightly stricter than to require tyvars τ = ∅, as the corresponding rule in [MTH90] does, and it rules out some pathological cases. Type variables occurring in exception bindings are unguarded (in SML) and affect the scoping mechanism even if they do not occur in the type obtained from that binding. In Extended ML, declarations never have unguarded type variables; the restriction makes sure that there is no difference in type variable scoping between Standard ML and Extended ML.

(31),(31.1),(32) There are unique VE and γ, for each C and exbind, such that C ⊢ exbind ⇒ VE, γ.

Atomic Patterns  C ⊢ atpat ⇒ (VE, τ), U, γ
\overline{C ⊢ ⇒ (\{\}, τ), ∅, τ}  (33)
C ⊢ scon ⇒ ({}, type(scon)), ∅, ϵ

(34)

\frac{var = idv}{C ⊢ var ⇒ (\{id ↦ τ\}, τ), ∅, τ}  (35)
\frac{C(longcon) ≻ τ^{(k)}t}{C ⊢ longcon ⇒ (\{\}, τ^{(k)}t), ∅, τ^{(k)}t}  (36)
\frac{C(longexcon) = exn}{C ⊢ longexcon ⇒ (\{\}, exn), ∅, ϵ}  (37)
\frac{⟨C ⊢ patrow ⇒ (VE, ϱ), U, γ⟩}{C ⊢ \{ ⟨patrow⟩ \} ⇒ ( \{\}⟨+ VE⟩, \{\}⟨+ ϱ⟩ in Type), ∅⟨ ∪ U⟩, ϵ⟨·γ⟩}  (38)
\frac{C ⊢ pat ⇒ (VE, τ), U, γ}{C ⊢ ( pat ) ⇒ (VE, τ), U, γ}  (39)

Comments:

(35) Note that var can assume a type, not a general type scheme.

Pattern Rows  C ⊢ patrow ⇒ (VE, ϱ), U, γ
\overline{C ⊢ ... ⇒ (\{\}, ϱ), ∅, ϱ in Trace}  (40)

\frac{C ⊢ pat ⇒ (VE, τ), U, γ ⟨C ⊢ patrow ⇒ (VE′, ϱ), U′, γ′ lab ∉ Dom ϱ⟩}{C ⊢ lab = pat ⟨ , patrow⟩ ⇒ (VE⟨+ VE′⟩, \{lab ↦ τ\}⟨+ ϱ⟩), U⟨ ∪ U′⟩, γ⟨·γ′⟩}  (41)

Comments:

(41) By the syntactic restrictions, Dom VE ∩ Dom VE′ = ∅.

Patterns  C ⊢ pat ⇒ (VE, τ), U, γ
\frac{C ⊢ atpat ⇒ (VE, τ), U, γ}{C ⊢ atpat ⇒ (VE, τ), U, γ}  (42)

\frac{C(longcon) ≻ τ′′ = τ′ → τ  C ⊢ atpat ⇒ (VE, τ′), U, γ}{C ⊢ longcon atpat ⇒ (VE, τ), U, τ′′ · γ}  (43)

\frac{C(longexcon) = τ → exn C ⊢ atpat ⇒ (VE, τ), U, γ}{C ⊢ longexcon atpat ⇒ (VE, exn), U, γ}  (44)

\frac{C ⊢ pat ⇒ (VE, τ), U, γ  C ⊢ ty ⇒ τ  U′ = tyvars ty}{C ⊢ pat : ty ⇒ (VE, τ), U ∪ U′, γ}  (45)

\frac{C ⊢ var ⇒ (VE, τ), U, γ  C ⊢ pat ⇒ (VE′, τ), U′, γ′ ⟨C ⊢ ty ⇒ τ  U′′ = tyvars ty⟩}{C ⊢ var⟨: ty⟩ as pat ⇒ (VE + VE′, τ), U ∪ U′⟨ ∪ U′′⟩, γ · γ′}  (46)

Comments:

(46) By the syntactic restrictions, Dom VE ∩ Dom VE′ = ∅. In the first premise, var is viewed as an atomic pattern. Note that U will always be the empty set.

Type Expressions  C ⊢ ty ⇒ τ
\frac{tyvar = α}{C ⊢ tyvar ⇒ α}  (47)

\frac{⟨C ⊢ tyrow ⇒ ϱ⟩}{C ⊢ \{ ⟨tyrow⟩ \} ⇒ \{\}⟨+ ϱ⟩ in Type}  (48)

\frac{tyseq = ty_{1}···ty_{k}  C ⊢ ty_{i} ⇒ τ_{i} (1 ≤ i ≤ k) C(longtycon) = (θ, CE) arity θ = k}{C ⊢ tyseq longtycon ⇒ τ^{(k)}θ}  (49)

\frac{C ⊢ ty ⇒ τ  C ⊢ ty′ ⇒ τ′}{C ⊢ ty -> ty′ ⇒ τ → τ′}  (50)

\frac{C ⊢ ty ⇒ τ}{C ⊢ ( ty ) ⇒ τ}  (51)

Type-expression Rows  C ⊢ tyrow ⇒ ϱ
\frac{C ⊢ ty ⇒ τ  ⟨C ⊢ tyrow ⇒ ϱ⟩}{C ⊢ lab : ty ⟨ , tyrow⟩ ⇒ \{lab ↦ τ\}⟨+ ϱ⟩}  (52)

Comment: The syntactic constraints ensure lab ∉ Dom ϱ.

4.11 Further Restrictions

In a match of the form pat_{1} => exp_{1} | ··· | pat_{n} => exp_{n} the pattern sequence pat_{1}, …, pat_{n} should be irredundant; that is, each pat_{j} must match some value (of the right type) which is not matched by pat_{i} for any i < j. In the context fn match, the match must also be exhaustive; that is, every value (of the right type) must be matched by some pat_{i}. The compiler must give warning on violation of these restrictions, but should still compile the match. The restrictions are inherited by derived forms; in particular, this means that in the function binding var atpat_{1} ··· atpat_{n}⟨: ty⟩ = exp (consisting of one clause only), each separate atpat_{i} should be exhaustive by itself.

This text originates from [MTH90]. In the context of Extended ML, this (and other references to compilers below) should be taken as referring to an Extended ML parser/typechecker, which of course is not a compiler in the usual sense.

5 Static Semantics for Modules

5.1 Semantic Objects

The simple objects for Modules static semantics are exactly as for the Core. The compound objects are those for the Core, augmented by those in Figure 13.

M ∈ StrNameSet = Fin(StrName)
N or (M, T) ∈ NameSet = StrNameSet × TyNameSet
Σ or (N)S ∈ Sig = NameSet × Str
Φ or (N)(S, (N′)S′) ∈ FunSig = NameSet × (Str × Sig)
G ∈ SigEnv = SigId →^{fin} Sig
F ∈ FunEnv = FunId →^{fin} FunSig
B or N, F, G, E ∈ Basis = NameSet × FunEnv × SigEnv × Env
φ_{Str} ∈ StrRea = StrName → StrName
φ or (φ_{Ty}, φ_{Str}) ∈ Rea = TyRea × StrRea
γ ∈ Trace = Tree(Trace_{COR} ⊎ SimTrace ⊎ BoundTrace)
(N)γ ∈ BoundTrace = NameSet × Trace

SimTrace = StrName ⊎ Rea ⊎ VarEnv ⊎ TyEnv ⊎ Env

Figure 13: Further Compound Semantic Objects

The prefix (N), in signatures and functor signatures, binds both type names and structure names. We shall always consider a set N of names as partitioned into a pair (M, T) of sets of the two kinds of name.

It is sometimes convenient to work with an arbitrary semantic object A, or assembly A of such objects. As with the function tynames, strnames(A) and names(A) denote respectively the set of structure names and the set of names occurring free in A.

Certain operations require a change of bound names in semantic objects; see for example Section 5.7. When bound type names are changed, we demand that all of their attributes (i.e. equality and arity) are preserved.

For any structure S = (m, (SE, TE, VE)) we call m the structure name or name of S; also, the proper substructures of S are the members of Ran SE and their proper substructures. The substructures of S are S itself and its proper substructures. The structures occurring in an object or assembly A are the structures and substructures from which it is built. The type structures of S are all members of Ran TE and all type structures of substructures of S.

The operations of projection, injection and modification are as for the Core. Moreover, we define C of B to be the context (T of B, ∅, E of B), i.e. with an empty set of explicit type variables. Also, we frequently need to modify a basis B by an environment E (or a structure environment SE say), at the same time extending N of B to include the type names and structure names of E (or of SE say). We therefore define B ⊕ SE, for example, to mean B + (names SE, SE).

For the purposes of the module semantics, we extend the notion of simple trace and introduce another form of trace, the bound trace. SimTrace_{COR} refers to SimTrace as defined in Figure 12 on page 24, i.e. the simple traces of the Core.

In traces of the form (N)γ, the names N are bound. Type substitution and realisations have to respect variable binding when applied to a trace, i.e. their application may involve renaming of bound names and bound type variables. When applying a realisation φ to a trace consisting of a realisation φ′, then φ affects the results of φ′, i.e. φ(φ′)(x) = φ(φ′(x)).

5.2 Consistency

A set of type structures is said to be consistent if, for all (θ_{1}, CE_{1}) and (θ_{2}, CE_{2}) in the set, if θ_{1} = θ_{2} then

CE_{1} = {} or CE_{2} = {} or Dom CE_{1} = Dom CE_{2}

A semantic object A or assembly A of objects is said to be consistent if (after changing bound names to make all nameset prefixes in A disjoint) for all S_{1} and S_{2} occurring in A and for every longstrid and every longtycon

1. If m of S_{1} = m of S_{2}, and both S_{1}(longstrid) and S_{2}(longstrid) exist, then

m of S_{1}(longstrid) = m of S_{2}(longstrid)

2. If m of S_{1} = m of S_{2}, and both S_{1}(longtycon) and S_{2}(longtycon) exist, then

θ of S_{1}(longtycon) = θ of S_{2}(longtycon)

3. The set of all type structures in A is consistent

As an example, a functor signature (N)(S, (N′)S′) is consistent if, assuming first that N ∩ N′ = ∅, the assembly A = {S, S′} is consistent.

We may loosely say that two structures S_{1} and S_{2} are consistent if {S_{1}, S_{2}} is consistent, but must remember that this is stronger than the assertion that S_{1} is consistent and S_{2} is consistent.

Note that if A is a consistent assembly and A′ ⊂ A then A′ is also a consistent assembly.

5.3 Well-formedness

A signature (N)S is well-formed if N ⊆ names S, and also, whenever (m, E) is a substructure of S and m ∉ N, then N ∩ (names E) = ∅, and whenever (t, CE) is a type structure of S and t ∉ N, then N ∩ (names CE) = ∅. A functor signature (N)(S, (N′)S′) is well-formed if (N)S and (N′)S′ are well-formed, and also, whenever (m′, E′) is a substructure of S′ and m′ ∉ N ∪ N′, then (N ∪ N′) ∩ (names E′) = ∅, and whenever (t′, CE′) is a type structure of S′ and t′ ∉ N ∪ N′, then (N ∪ N′) ∩ (names CE′) = ∅.

An object or assembly A is well-formed if every signature and functor signature occurring in A is well-formed.

5.4 Cycle-freedom

An object or assembly A is cycle-free if it contains no cycle of structure names; that is, there is no sequence

m_{0}, ···, m_{k−1}, m_{k} = m_{0} (k > 0)

of structure names such that, for each i (0 ≤ i < k) some structure with name m_{i} occurring in A has a proper substructure with name m_{i+1}.

5.5 Admissibility

An object or assembly A is admissible if it is consistent, well-formed and cyclefree. Henceforth it is assumed that all objects mentioned are admissible. We also require that

1. In every sentence A ⊢ phrase ⇒ A′ inferred by the rules given in Section 5.14, the assembly {A, A′} is admissible.

2. In the special case of a sentence B ⊢ sigexp ⇒ S, γ, we further require that the assembly consisting of all semantic objects occurring in the entire inference of this sentence be admissible. This is important for the definition of principal signatures in Section 5.13.

In our semantic definition we have not undertaken to indicate how admissibility should be checked in an implementation.

5.6 Type Realisation

A type realisation is a function φ_{Ty} : TyName → TypeFcn such that t and φ_{Ty}(t) have the same arity, and if t admits equality then so does φ_{Ty}(t).

The support Supp φ_{Ty} of a type realisation φ_{Ty} is the set of type names t for which φ_{Ty}(t) ≠ t.

The semantic class of type realisations is called TyRea.

5.7 Realisation

A realisation is a function φ of names, partitioned into a type realisation φ_{Ty} : TyName → TypeFcn and a function φ_{Str} : StrName → StrName. The support Supp φ of a realisation φ is the set of names n for which φ(n) ≠ n. The yield Yield φ of a realisation φ is the set of names which occur in some φ(n) for which n ∈ Supp φ.

Realisations φ are extended to apply to all semantic objects; their effect is to replace each name n by φ(n). In applying φ to an object with bound names, such as a signature (N)S, first bound names must be changed so that, for each binding prefix (N),

N ∩ (Supp φ ∪ Yield φ) = ∅ .

We assume realisations to have finite support, i.e. the last sentence does not affect the applicability of realisations.

The semantic class of realisations is called Rea.

Traces

We extend the definition of generalisation to traces. The relation ≻ is the smallest binary relation on traces extending the relation ≻_{COR} on Core traces in the following way:

γ  ≻ γ  ⟸ γ ∈ SimTrace
γ_{1} · γ_{2} ≻ γ′_{1} · γ′_{2} ⟸ γ_{1} ≻ γ′_{1} ∧ γ_{2} ≻ γ′_{2}
(N)γ ≻ φ(γ) ⟸ Supp φ ⊆ N
γ_{1}  ≻ γ_{3}  ⟸ there exists γ_{2} such that γ_{1} ≻ γ_{2} ∧ γ_{2} ≻ γ_{3}
γ_{1}  ≻ γ_{2}  ⟸ for all γ_{3}, γ_{2} ≻ γ_{3} ⟹ γ_{1} ≻ γ_{3}

Stripping Axioms

Axioms should not influence elaboration; in particular, the successful elaboration of a phrase should not depend on the presence of axioms. For this purpose, we define a family of partial functions

strip : \{ \begin{matrix}(SigExp × Trace) → (SigExp × Trace) \\ (StrDesc × Trace) → (StrDesc × Trace) \\ (Spec × Trace) → (Spec × Trace) \end{matrix}

which “strip” axioms from signature expressions and perform the corresponding removal in the trace. These functions are partial because e.g. the trace γ in an argument (spec, γ) of strip is expected to be an elaboration result of spec. More precisely, strip is defined as follows:

strip : (SigExp × Trace) → (SigExp × Trace)

strip(sig spec end, m · γ) = (sig spec′ end, m · γ′)

where strip(spec, γ) = (spec′, γ′) strip(sigid, γ) = (sigid, γ) strip : (StrDesc × Trace) → (StrDesc × Trace) strip(strid : sigexp ⟨and strdesc⟩, γ_{1}⟨·γ_{2}⟩) =

(strid : sigexp′ ⟨and strdesc′⟩, γ′_{1}⟨·γ′_{2}⟩)

where \{ \begin{matrix}strip(sigexp, γ_{1}) = (sigexp′, γ′_{1}) \\ ⟨strip(strdesc, γ_{2}) = (strdesc′, γ′_{2})⟩ \end{matrix}

strip : (Spec × Trace) → (Spec × Trace)

strip(axiom axdesc, γ) = ( , ϵ)

strip(structure strdesc, γ) = (structure strdesc′, γ′)

where strip(strdesc, γ) = (strdesc′, γ′) strip(local spec_{1} in spec_{2} end, γ_{1} · γ_{2}) = (local spec′_{1} in spec′_{2} end, γ′_{1} · γ′_{2})

where strip(spec_{i}, γ_{i}) = (spec′_{i}, γ′_{i}), i ∈ {1, 2} strip(spec_{1} ⟨;⟩ spec_{2}, γ_{1} · γ_{2}) = (spec′_{1} ⟨;⟩ spec′_{2}, γ′_{1} · γ′_{2})

where strip(spec_{i}, γ_{i}) = (spec′_{i}, γ′_{i}), i ∈ {1, 2} strip(spec, γ) = (spec, γ) otherwise

5.8 Type Explication

A signature (N)S is type-explicit if, whenever t ∈ N and t occurs free in S, then some substructure of S contains a type environment TE such that TE(tycon) = (t, CE) for some tycon and some CE.

5.9 Signature Instantiation

A structure S_{2} is an instance of a signature Σ_{1} = (N_{1})S_{1}, written Σ_{1}≥S_{2}, if there exists a realisation φ such that φ(S_{1}) = S_{2} and Supp φ ⊆ N_{1}. We write Σ_{1}≥_{φ}S_{2} if we want to make φ explicit. (Note that if Σ_{1} is type-explicit then there is at most one such φ.) A signature Σ_{2} = (N_{2})S_{2} is an instance of Σ_{1} = (N_{1})S_{1}, written Σ_{1}≥Σ_{2}, if Σ_{1}≥S_{2} and N_{2} ∩ (names Σ_{1}) = ∅. It can be shown that Σ_{1}≥Σ_{2} iff, for all S, whenever Σ_{2}≥S then Σ_{1}≥S.

5.10 Functor Signature Instantiation

A pair (S, (N′)S′) is called a functor instance. Given Φ = (N_{1})(S_{1}, (N′_{1})S′_{1}), a functor instance (S_{2}, (N′_{2})S′_{2}) is an instance of Φ, written Φ≥(S_{2}, (N′_{2})S′_{2}), if there exists a realisation φ such that φ(S_{1}, (N′_{1})S′_{1}) = (S_{2}, (N′_{2})S′_{2}) and Supp φ ⊆ N_{1}. Again we write Φ≥_{φ}(S_{2}, (N′_{2})S′_{2}) to make φ explicit.

5.11 Enrichment

In matching a structure to a signature, the structure will be allowed both to have more components, and to be more polymorphic, than (an instance of) the signature. Precisely, we define enrichment of structures, environments and type structures by mutual recursion as follows.

A structure S_{1} = (m_{1}, E_{1}) enriches another structure S_{2} = (m_{2}, E_{2}), written S_{1} ≻ S_{2}, if

1. m_{1} = m_{2}

2. E_{1} ≻ E_{2}

An environment E_{1} enriches another environment E_{2}, E_{i} = (SE_{i}, TE_{i}, VE_{i}), written E_{1} ≻ E_{2}, if

1. Dom SE_{1} ⊇ Dom SE_{2}, and ∀strid ∈ Dom SE_{2}. SE_{1}(strid) ≻ SE_{2}(strid)

2. Dom TE_{1} ⊇ Dom TE_{2}, and ∀tycon ∈ Dom TE_{2}. TE_{1}(tycon) ≻ TE_{2}(tycon)

3. Dom VE_{1} ⊇ Dom VE_{2}, and ∀id ∈ Dom VE_{2}. VE_{1}(id) ≻ VE_{2}(id)

Finally, a type structure (θ_{1}, CE_{1}) enriches another type structure (θ_{2}, CE_{2}), written (θ_{1}, CE_{1}) ≻ (θ_{2}, CE_{2}), if

1. θ_{1} = θ_{2}

2. Either CE_{1} = CE_{2} or CE_{2} = {}

5.12 Signature Matching

A structure S matches a signature Σ_{1} if there exists a structure S^{−} such that Σ_{1} ≥ S^{−} ≺ S. Thus matching is a combination of instantiation and enrichment. There is at most one such S^{−}, given Σ_{1} and S. Moreover, writing Σ_{1} = (N_{1})S_{1}, if Σ_{1} ≥ S^{−} then there exists a realisation φ with Supp φ ⊆ N_{1} and φ(S_{1}) = S^{−}. We shall then say that S matches Σ_{1} via φ. (Note that if Σ_{1} is type-explicit then φ is uniquely determined by Σ_{1} and S.)

A signature Σ_{2} matches a signature Σ_{1} if for all structures S, if S matches Σ_{2} then S matches Σ_{1}. It can be shown that Σ_{2} = (N_{2})S_{2} matches Σ_{1} = (N_{1})S_{1} if and only if there exists a realisation φ with Supp φ ⊆ N_{1} and φ(S_{1}) ≺ S_{2} and N_{2} ∩ names Σ_{1} = ∅.

5.13 Principal Signatures

The definitions in this section concern the elaboration of signature expressions; more precisely they concern inferences of sentences of the form B ⊢ sigexp ⇒ S, γ, where S is a structure and B is a basis. Recall, from Section 5.5, that the assembly of all semantic objects in such an inference must be admissible.

For any basis B and any structure S, we say that B covers S if for every substructure (m, E) of S such that m ∈ N of B:

1. For every structure identifier strid ∈ Dom E, B contains a substructure (m, E′) with m free and strid ∈ Dom E′

2. For every type constructor tycon ∈ Dom E, B contains a substructure (m, E′) with m free and tycon ∈ Dom E′

(This condition is not a consequence of consistency of {B, S}; informally, it states that if S shares a substructure with B, then S mentions no more components of the substructure than B does.)

We say that a signature (N)S with a trace γ is principal for sigexp in B if, choosing N so that (N of B) ∩ N = ∅,

1. B covers S

2. B ⊢ sigexp ⇒ S, γ

3. Whenever B ⊢ sigexp ⇒ S′, γ′, then (N)S≥_{φ}S′ and φ′(γ) ≻ γ′, for some realisations φ and φ′ such that Supp φ′ ∩ (N of B) = ∅ and such that φ′ restricted to N is the same as φ.

We claim that if sigexp elaborates in B to some structure covered by B, then it possesses a principal signature in B (with some trace).^{5}

Analogous to the definition given for type environments in Section 4.9, we say that a semantic object A respects equality if every type environment occurring in A respects equality.

Now let us assume that sigexp possesses a principal signature Σ_{0} = (N_{0})S_{0} with γ_{0} in B. We wish to define, in terms of Σ_{0}, another signature Σ with γ which provides more information about the equality attributes of structures which will match Σ_{0}. To this end, let T_{0} be the set of type names t ∈ N_{0} which do not admit equality, and such that (t, CE) occurs in S_{0} for some CE ≠ {}. Then we say Σ with γ is equality-principal for sigexp in B if

1. Σ respects equality

2. Σ and γ are obtained from Σ_{0} and γ_{0} just by making as many members of T_{0} admit equality as possible, subject to 1. above.

It is easy to show that, if any such a pair (Σ, γ) exists, it is determined uniquely by (Σ_{0}, γ_{0}); moreover, Σ exists if Σ_{0} itself respects equality.

We do not express equality-principality of signature elaboration by higher-order rules, in spite of comments in Section 1.2 which suggest this. The problem is that the obvious higher-order rule is on the one hand (slightly) incompatible with SML and on the other hand makes signature elaboration undecidable. One can repair the undecidability flaw by making a few rather innocent-looking changes to the semantics, but this would widen the gap between SML and EML.

5This claim must be slightly qualified, since it may be ill-formed in a mild sense. This is discussed at the end of Section 11.3 of [MT91].

5.14 Inference Rules

As for the Core, the rules of the Modules static semantics allow sentences of the form

A ⊢ phrase ⇒ A′

to be inferred, where in this case A is usually either a basis or a context and A′ is a semantic object or an assembly of such objects.

Structure Expressions  B ⊢ strexp ⇒ S, γ
\frac{B ⊢ strdec ⇒ E, γ  m ∉ (N of B) ∪ names E}{B ⊢ struct strdec end ⇒ (m, E), m · γ}  (53)

\frac{B(longstrid) = S}{B ⊢ longstrid ⇒ S, ϵ}  (54)

\frac{B ⊢ strexp ⇒ S, γ B(funid)≥_{φ}(S′′, (N′)S′) , S ≻ S′′ (N of B ∪ names S) ∩ N′ = ∅}{B ⊢ funid ( strexp ) ⇒ S′, φ · γ}  (55)

\frac{B ⊢ strdec ⇒ E, γ  B ⊕ E ⊢ strexp ⇒ S, γ′}{B ⊢ let strdec in strexp end ⇒ S, γ · γ′}  (56)

Comments:

(53) The side condition ensures that each generative structure expression receives a new name. If the expression occurs in a functor body the structure name will be bound by (N′) in rule 99; this will ensure that for each application of the functor, by rule 55, a new distinct name will be chosen for the structure generated.

(55) The side condition (N of B ∪ names S) ∩ N′ = ∅ can always be satisfied by renaming bound names in (N′)S′ thus ensuring that the generated structures receive new names. The corresponding side condition in rule 55 of the SML semantics [MTH90] is weaker, but this weakness makes the rule unsound. Let B(funid) = (N)(S_{f}, (N′)S′_{f}). Assuming that (N)S_{f} is type-explicit, the realisation φ for which φ(S_{f}, (N′)S′_{f}) = (S′′, (N′)S′) is uniquely determined by S, since S ≻ S′′ can only hold if the type names and structure names in S and S′′ agree. Recall that enrichment ≻ allows more components and more polymorphism, while instantiation ≥ does not. Sharing between argument and result specified in the declaration of the functor funid is represented by the occurrence of the same name in both S_{f} and S′_{f}, and this repeated occurrence is preserved by φ, yielding sharing between the argument structure S and the result structure S′ of this functor application.

(56) The use of ⊕, here and elsewhere, ensures that structure and type names generated by the first sub-phrase are distinct from names generated by the second sub-phrase.

Structure-level Declarations  B ⊢ strdec ⇒ E, γ

\frac{C of B ⊢ dec ⇒ E, γ  N = names γ \ N of B  \frac{C of B ⊢ dec ⇒ E′, γ′}{(N)γ ≻ γ′}}{B ⊢ dec ⇒ E, γ} (57)

\frac{B ⊢ ax ⇒ γ}{B ⊢ axiom ax ⇒ \{\} in Env, γ}  (57.1)

\frac{B ⊢ strbind ⇒ SE, γ}{B ⊢ structure strbind ⇒ SE in Env, γ}  (58)

\frac{B ⊢ strdec_{1} ⇒ E_{1}, γ_{1} B ⊕ E_{1} ⊢ strdec_{2} ⇒ E_{2}, γ_{2}}{B ⊢ local strdec_{1} in strdec_{2} end ⇒ E_{2}, γ_{1} · γ_{2}}  (59)

\overline{B ⊢ ⇒ \{\} in Env, ϵ}  (60)

\frac{B ⊢ strdec_{1} ⇒ E_{1}, γ_{1} B ⊕ E_{1} ⊢ strdec_{2} ⇒ E_{2}, γ_{2}}{B ⊢ strdec_{1} ⟨;⟩ strdec_{2} ⇒ E_{1} + E_{2}, γ_{1} · γ_{2}}  (61)

Comments:

(57) The last premise can be seen as requiring principality of the trace γ (for dec in B), which implies principality of the environment E in the sense of the SML definition; it is a stronger condition, as γ may also include types which are not in E.

Axioms  B ⊢ ax ⇒ γ

\frac{B ⊢ axexp ⇒ γ  ⟨B ⊢ ax ⇒ γ′⟩}{B ⊢ axexp ⟨and ax⟩ ⇒ γ⟨·γ′⟩}  (61.1)

Comment: Axioms are not implicitly universally quantified over all their free variables. Such implicit quantification is convenient for presenting small examples, but the redundancy introduced by requiring variables to be explicitly quantified is helpful in detecting typographical errors in larger examples.

Axiomatic Expressions  B ⊢ axexp ⇒ γ

\frac{C of B + names B ⊢ exp^{•} ⇒ bool, ∅, γ \frac{C of B + names B ⊢ exp^{•} ⇒ τ, ∅, γ′}{Closγ ≻ γ′ ∧ τ = bool}}{B ⊢ exp^{•} ⇒ Closγ}

(61.2)

Comment: This rule gives us the principal trace for an expression in an axiom or axiom description; principality is given by the second premise. Axiomatic expressions must be of type bool and are not allowed to contain unguarded explicit type variables.

Structure Bindings  B ⊢ strbind ⇒ SE, γ
\frac{B ⊢ sglstrbind ⇒ SE, γ  ⟨B + names SE ⊢ strbind ⇒ SE′, γ′⟩}{B ⊢ sglstrbind ⟨and strbind⟩ ⇒ SE ⟨+SE′⟩, γ⟨·γ′⟩} (62)

Single Structure Bindings  B ⊢ sglstrbind ⇒ SE, γ

\frac{B ⊢ psigexp ⇒ (N)S, γ  B ⊢ strexp ⇒ S′, γ′ N ∩ N of B = ∅ (N)S ≥ S′′ ≺ S′}{B ⊢ strid : psigexp = strexp ⇒ \{strid ↦ S\}, γ · γ′}  (62.1)

\frac{B ⊢ psigexp ⇒ (N)S, γ  N ∩ N of B = ∅}{B ⊢ strid : psigexp = ? ⇒ \{strid ↦ S\}, γ}  (62.2)

\frac{B ⊢ strexp ⇒ S, γ}{B ⊢ strid = strexp ⇒ \{strid ↦ S\}, γ}  (62.3)

Comments:

(62.1) In EML, structures are like abstractions [MacQ86]: the signature of a structure is taken to be exactly the explicit signature. Any additional sharing present in the structure body is invisible outside the body. The type/structure names in S′ are not accessible outside the body and so they may be safely reused (in contrast to SML, where strid is bound to S′′).

(62.1),(62.2) The only difference between these two rules is that in the case where a body is present, it is required to elaborate and to fit the signature given. However, this does not effect the overall result of elaboration, which depends only on the signature given.

The side-condition N ∩N of B = ∅ can always be satisfied by an appropriate α-conversion of (N)S.

Signature Expressions  B ⊢ sigexp ⇒ S, γ
\frac{B, E ⊢ spec ⇒ E, γ}{B ⊢ sig spec end ⇒ (m, E), m · γ}  (63)

\frac{B(sigid)≥_{φ}S}{B ⊢ sigid ⇒ S, φ}  (64)

Comments:

(63) In contrast to rule 53, m is not here required to be new. The name m may be chosen to achieve the sharing required in rule 88, or to achieve the enrichment side conditions of rule 62.1 or 99. The choice of m must result in an admissible object.

The purpose of the recursive occurrence of E is to ensure that the bindings present in the final result of a signature expression are never overwritten during its elaboration.

(64) The instance S of B(sigid) is not determined by this rule, but — as in rule 63 — the instance may be chosen to achieve sharing properties or enrichment conditions.

Principal Signatures  B ⊢ psigexp ⇒ Σ, γ

\frac{(N)S with γ equality-principal for sigexp in B  (N)S type-explicit strip(sigexp, γ) = (sigexp′, γ′) (N)S with γ′ equality-principal for sigexp′ in B}{B ⊢ sigexp ⇒ (N)S, (N)γ} (65)

Comment: B ⊢ sigexp ⇒ S, γ follows from the definition of equality-principality of (N)S with γ for sigexp in B. The purpose of the second equality-principality requirement is to ensure that dropping axioms from sigexp does not change the result of elaboration. We also need principality of the second elaboration to get a unique trace γ. In an implementation, the two equality-principality requirements will probably correspond to two passes of static analysis: the first pass elaborates the signature expression stripped of its axioms; the second pass then includes the axioms and checks that no further identification of type names is required for elaboration to succeed.

Signature Declarations  B ⊢ sigdec ⇒ G, γ
\frac{B ⊢ sigbind ⇒ G, γ}{B ⊢ signature sigbind ⇒ G, γ}  (66)
\overline{B ⊢ ⇒ \{\}, ϵ}  (67)

\frac{B ⊢ sigdec_{1} ⇒ G_{1}, γ_{1} B + G_{1} ⊢ sigdec_{2} ⇒ G_{2}, γ_{2}}{B ⊢ sigdec_{1} ⟨;⟩ sigdec_{2} ⇒ G_{1} + G_{2}, γ_{1} · γ_{2}}  (68)

Comments:

(66) The first closure restriction of Section 3.6 can be enforced by replacing the B in the premise by (B ∩ B_{0}) + G of B.

(68) A signature declaration does not create any new structures or types; hence the use of + instead of ⊕.

Signature Bindings  B ⊢ sigbind ⇒ G, γ
\frac{B ⊢ psigexp ⇒ Σ, γ  ⟨B ⊢ sigbind ⇒ G, γ′⟩}{B ⊢ sigid = psigexp ⟨and sigbind⟩ ⇒ \{sigid ↦ Σ\} ⟨+ G⟩, γ⟨·γ′⟩}  (69)

Comment: The condition that Σ be equality-principal, implicit in the first premise, ensures that the signature found is as general as possible given the sharing constraints present in psigexp.

Specifications  B, E ⊢ spec ⇒ E′, γ
\frac{C of B ⊢ valdesc ⇒ VE}{B, E ⊢ val valdesc ⇒ ClosVE in Env, ClosVE in Trace}  (70)

\frac{C of B ⊢ typdesc ⇒ TE}{B, E ⊢ type typdesc ⇒ TE in Env, TE in Trace}  (71)

\frac{C of B ⊢ typdesc ⇒ TE  ∀(θ, CE) ∈ Ran TE, θ admits equality}{B, E ⊢ eqtype typdesc ⇒ TE in Env, TE in Trace}  (72)

\frac{C of B + TE ⊢ datdesc ⇒ VE, TE  E = (\{\}, TE, VE)}{B, E′ ⊢ datatype datdesc ⇒ E, E in Trace}  (73)

\frac{C of B ⊢ exdesc ⇒ VE  E = (\{\}, \{\}, VE)}{B, E′ ⊢ exception exdesc ⇒ E, E in Trace}  (74)

\frac{B ⊢ axdesc ⇒ γ}{B, E ⊢ axiom axdesc ⇒ \{\} in Env, γ}  (74.1)

\frac{B ⊢ strdesc ⇒ SE, γ}{B, E ⊢ structure strdesc ⇒ SE in Env, γ}  (75)

\frac{B ⊢ shareq ⇒ \{\}}{B, E ⊢ sharing shareq ⇒ \{\} in Env, ϵ}  (76)

\frac{Dom E_{1} ∩ Dom E = ∅  Dom E_{1} ∩ Dom E_{2} = ∅ B, E ⊢ spec_{1} ⇒ E_{1}, γ_{1} B + E_{1}, E ⊢ spec_{2} ⇒ E_{2}, γ_{2}}{B, E ⊢ local spec_{1} in spec_{2} end ⇒ E_{2}, γ_{1} · γ_{2}}  (77)

\frac{∀1 ≤ i < j ≤ n. Dom E_{i} ∩ Dom E_{j} = ∅ B(longstrid_{1}) = (m_{1}, E_{1}) ··· B(longstrid_{n}) = (m_{n}, E_{n})}{B, E ⊢ open longstrid_{1} ··· longstrid_{n} ⇒ E_{1} + ··· + E_{n}, ϵ}  (78)

\frac{∀1 ≤ i < j ≤ n. Dom E_{i} ∩ Dom E_{j} = ∅ B(sigid_{1})≥_{φ_{1}}(m_{1}, E_{1}) ··· B(sigid_{n})≥_{φ_{n}}(m_{n}, E_{n})}{B, E ⊢ include sigid_{1} ··· sigid_{n} ⇒ E_{1} + ··· + E_{n}, φ_{1} · . . . · φ_{n}}  (79)

\overline{B, E ⊢ ⇒ \{\} in Env, ϵ}  (80)

\frac{Dom E_{1} ∩ Dom E_{2} = ∅ B, E ⊢ spec_{1} ⇒ E_{1}, γ_{1} B + E_{1}, E ⊢ spec_{2} ⇒ E_{2}, γ_{2}}{B, E ⊢ spec_{1} ⟨;⟩ spec_{2} ⇒ E_{1} + E_{2}, γ_{1} · γ_{2}}  (81)

Comments:

(70) VE is determined by B and valdesc.

(71)–(73) The type functions in TE may be chosen to achieve the sharing hypothesis of rule 89 or the enrichment conditions of rules 62.1 and 99. In particular, the type names in TE in rule 73 need not be new. Also, in rule 71 the type functions in TE may admit equality.

(74) VE is determined by B and exdesc and contains monotypes only.

(77)–(79),(81) The intersection of the domains is to be understood as a pointwise intersection, the name spaces of e.g. structure identifiers and type constructors do not interfere. The reason for the restriction is to simplify the verification of structures against signatures.

(79) The names m_{i} in the instances may be chosen to achieve sharing or enrichment conditions.

Value Descriptions  C ⊢ valdesc ⇒ VE
\frac{var = idv C ⊢ ty ⇒ τ  ⟨C ⊢ valdesc ⇒ VE⟩}{C ⊢ var : ty ⟨and valdesc⟩ ⇒ \{id ↦ τ\} ⟨+ VE⟩}  (82)

Type Descriptions  C ⊢ typdesc ⇒ TE
\frac{tyvarseq = α^{(k)} ⟨C ⊢ typdesc ⇒ TE⟩  arity θ = k}{C ⊢ tyvarseq tycon ⟨and typdesc⟩ ⇒ \{tycon ↦ (θ, \{\})\} ⟨+ TE⟩}  (83)

Comment: Note that any θ of arity k may be chosen but that the constructor environment in the resulting type structure must be empty. For example,

    datatype s=c
    type t
    sharing type s=t

is a legal specification, but the type structure bound to t does not bind any value constructors.

Datatype Descriptions  C ⊢ datdesc ⇒ VE, TE
\frac{tyvarseq = α^{(k)} C, α^{(k)}t ⊢ condesc ⇒ CE  ⟨C ⊢ datdesc ⇒ VE, TE⟩}{C ⊢ tyvarseq tycon = condesc ⟨and datdesc⟩ ⇒ ClosCE⟨+ VE⟩, \{tycon ↦ (t, ClosCE)\} ⟨+ TE⟩} (84)

Constructor Descriptions  C, τ ⊢ condesc ⇒ CE
\frac{con = idc ⟨C, τ ⊢ condesc ⇒ CE⟩}{C, τ ⊢ con ⟨ | condesc⟩ ⇒ \{id ↦ τ\} ⟨+ CE⟩}  (85)

\frac{con = idc C ⊢ ty ⇒ τ′ ⟨C, τ ⊢ condesc ⇒ CE⟩}{C, τ ⊢ con of ty ⟨ | condesc⟩ ⇒ \{id ↦ τ′ → τ\} ⟨+ CE⟩}  (85.1)

Exception Descriptions  C ⊢ exdesc ⇒ VE
\frac{excon = ide ⟨C ⊢ exdesc ⇒ VE⟩}{C ⊢ excon ⟨and exdesc⟩ ⇒ \{id ↦ exn\} ⟨+ VE⟩}  (86)

\frac{C ⊢ ty ⇒ τ  tyvars(ty) = ∅ excon = ide ⟨C ⊢ exdesc ⇒ VE⟩}{C ⊢ excon of ty ⟨and exdesc⟩ ⇒ \{id ↦ τ → exn\}⟨+ VE⟩}  (86.1)

Comments:

(86.1) The requirement that there are no type variables in ty (rather than in τ, as in rule 31.1 or in rule 86 of [MTH90]) was suggested in Appendix D in [MT91]. The problem with the requirement in [MTH90] is that principality is lost because of the existence of type functions like Λα.int; see [MT91]. Here is an example:

        type 'a t
        exception e of 'a t

This specification does not elaborate because of the side-condition in 86.1. The weaker side-condition tyvars(τ) = ∅ would still allow successful elaborations with e.g. t ↦ Λα.int.

Axiom Descriptions  B ⊢ axdesc ⇒ γ

Axiom descriptions, specification expressions, etc. do not add components to the basis, hence the only outcome of elaboration is the trace.

\frac{B ⊢ specexp ⇒ γ  ⟨B ⊢ axdesc ⇒ γ′⟩}{B ⊢ specexp ⟨and axdesc⟩ ⇒ γ⟨·γ′⟩}  (86.2)

Specification Expressions  B ⊢ specexp ⇒ γ
\frac{B ⊢ strdec ⇒ E, γ  B ⊕ E ⊢ axexp ⇒ γ′}{B ⊢ let strdec in axexp end ⇒ γ · γ′}  (86.3)

Structure Descriptions  B ⊢ strdesc ⇒ SE, γ
\frac{B ⊢ sigexp ⇒ S, γ  ⟨B ⊢ strdesc ⇒ SE, γ′⟩}{B ⊢ strid : sigexp ⟨and strdesc⟩ ⇒ \{strid ↦ S\} ⟨+ SE⟩, γ⟨·γ′⟩}  (87)

Sharing Equations  B ⊢ shareq ⇒ {}
\frac{m of B(longstrid_{1}) = ··· = m of B(longstrid_{n})}{B ⊢ longstrid_{1} = ··· = longstrid_{n} ⇒ \{\}}  (88)

\frac{θ of B(longtycon_{1}) = ··· = θ of B(longtycon_{n})}{B ⊢ type longtycon_{1} = ··· = longtycon_{n} ⇒ \{\}}  (89)

\frac{B ⊢ shareq_{1} ⇒ \{\} B ⊢ shareq_{2} ⇒ \{\}}{B ⊢ shareq_{1} and shareq_{2} ⇒ \{\}}  (90)

Comments:

(88) The premise is weaker than B(longstrid_{1}) = ··· = B(longstrid_{n}). Two different structures with the same name may be thought of as representing different views. The requirement that B is consistent forces different views to be consistent.

(89) The premise is weaker than B(longtycon_{1}) = ··· = B(longtycon_{n}). A type structure with empty constructor environment may have the same type name as one with a non-empty constructor environment; the former could arise from a type description, and the latter from a datatype description. However, the requirement that B is consistent will prevent two type structures with constructor environments which have different non-empty domains from sharing the same type name.

Functor Specifications etc.

Several rules have been removed here, because EML does not support functor specifications, functor descriptions or functor signature expressions. In SML these constructs are assigned semantics although they cannot appear in programs.

Deleted  (91)

Deleted  (92)

Deleted  (93)

Deleted  (94)

Deleted  (95)

Functor Declarations  B ⊢ fundec ⇒ F, γ
\frac{B ⊢ funbind ⇒ F, γ}{B ⊢ functor funbind ⇒ F, γ}  (96)

\overline{B ⊢ ⇒ \{\}, ϵ}  (97)

\frac{B ⊢ fundec_{1} ⇒ F_{1}, γ_{1} B + F_{1} ⊢ fundec_{2} ⇒ F_{2}, γ_{2}}{B ⊢ fundec_{1} ⟨;⟩ fundec_{2} ⇒ F_{1} + F_{2}, γ_{1} · γ_{2}}  (98)

Comments:

(96) The second closure restriction of Section 3.6 can be enforced by replacing the B in the premise by (B ∩ B_{0}) + (G of B) + (F of B).

Functor Bindings  B ⊢ funbind ⇒ F, γ

\frac{B ⊢ psigexp ⇒ (N)S, γ_{1} N ∩ N of B = ∅ B′ = B ⊕ \{strid ↦ S\} B′ ⊢ psigexp′ ⇒ Σ, γ_{2} B′ ⊢ strexp ⇒ S′, γ_{3} Σ ≥ S′′ ≺ S′ ⟨B ⊢ funbind ⇒ F, γ_{4}⟩}{B ⊢ funid ( strid : psigexp ) : psigexp′ = strexp ⟨and funbind⟩ ⇒ \{funid ↦ (N)(S, Σ)\} ⟨+ F ⟩, γ_{1} · γ_{2} · γ_{3}⟨·γ_{4}⟩} (99)

\frac{B ⊢ psigexp ⇒ (N)S, γ_{1} B ⊕ \{strid ↦ S\} ⊢ psigexp′ ⇒ Σ, γ_{2} N ∩ N of B = ∅ ⟨B ⊢ funbind ⇒ F, γ_{3}⟩}{B ⊢ funid ( strid : psigexp ) : psigexp′ = ? ⟨and funbind⟩ ⇒ \{funid ↦ (N)(S, Σ)\} ⟨+ F ⟩, γ_{1} · γ_{2}⟨·γ_{3}⟩}  (99.1)

Comments:

(99) In EML, functors are like parameterised abstractions [MacQ86]: the output signature of a functor is taken to be exactly the explicit output signature. Any additional sharing present in the functor body is invisible outside the body. Compare rule 99 of [MTH90].

(99),(99.1) The requirement that (N)S be equality-principal, implicit in the first premise, forces (N)S to be as general as possible given the sharing constraints in psigexp. The requirement that (N)S be type-explicit ensures that there is at most one realisation via which an actual argument can match (N)S. Since ⊕ is used, any structure name m and type name t in S acts like a constant in the functor body and in the functor result signature; in particular, it ensures that further names generated during elaboration of the body are distinct from m and t. The only difference between these two rules is that in the case where a body is present, it is required to elaborate and to fit the output signature. This does not affect the overall result of elaboration, which depends only on the input and output signatures.

Top-level Declarations  B ⊢ topdec ⇒ B′, γ
\frac{B ⊢ strdec ⇒ E, γ}{B ⊢ strdec ⇒ (names E, E) in Basis, γ}  (100)

\frac{B ⊢ sigdec ⇒ G, γ}{B ⊢ sigdec ⇒ (names G, G) in Basis, γ}  (101)

\frac{B ⊢ fundec ⇒ F, γ}{B ⊢ fundec ⇒ (names F, F) in Basis, γ}  (102)

6 Dynamic Semantics for the Core

6.1 Reduced Syntax

Since types are fully dealt with in the static semantics, the dynamic semantics ignores them. The Core syntax is therefore reduced by the following transformations, for the purpose of the dynamic semantics:

• All explicit type ascriptions “: ty” are omitted, and qualifications “of ty” are omitted from constructor and exception bindings.

• Any declaration of the form “type typbind ”or “eqtype typbind ” is replaced by the empty declaration.

• The Core phrase classes TypBind, Ty and TyRow are omitted.

6.2 Simple Objects

All objects in the dynamic semantics are built from identifier classes together with the simple object classes shown (with the variables which range over them) in Figure 14.

en ∈ ExName  exception names
b ∈ BasVal  basic values
sv ∈ SVal  special values
sp ∈ Bit = {⊥, ⊤}  flags
{FAIL}  failure

Figure 14: Simple Semantic Objects

ExName is an infinite set; it is totally ordered, i.e. every subset A of ExName has a smallest element min A. BasVal is described below in Section 6.4. SVal is the class of values denoted by the special constants SCon. Each integer or real constant denotes a value according to usual conventions for decimal numbers with limited precision; each string constant denotes a sequence of characters as explained in Section 2.2. The value denoted by scon is written val(scon). The values ⊥ and ⊤ are only used as Boolean flags. If a semantic object x contains a Bit component, we write x_{⊥} to denote the same object, but with the Bit component set to ⊥. On Bit, we define the operation ∧ as the greatest lower bound of the order ⊥ ≤ ⊤; its generalisation to finite index sets I is written ⋀_{i∈I}.

FAIL is the result of a failing attempt to match a value and a pattern. Thus FAIL is neither a value nor an exception, but simply a semantic object used in the rules to express operationally how matching proceeds.

v ∈ Val = SVal ⊎ BasVal ⊎ Con

⊎ (Con × Val) ⊎ ExVal

⊎ Record ⊎ Closure ⊎ {Incomplete}

r ∈ Record = Lab →^{fin} Val
e ∈ ExVal = ExName ⊎ (ExName × Val)
[e] or p ∈ Pack = ExVal
(match, E, VE) ∈ Closure = Match × Env × VarEnv
ens ∈ ExNameSet = Fin(ExName)
(sp, ens) or s ∈ State = Bit × ExNameSet
(SE, VE) or E ∈ Env = StrEnv × VarEnv
SE ∈ StrEnv = StrId →^{fin} Env
VE ∈ VarEnv = Id →^{fin} Val

Figure 15: Compound Semantic Objects

Exception constructors evaluate to exception names, unlike value constructors which simply evaluate to themselves. This is to accommodate the generative nature of exception bindings; each evaluation of a declaration of an exception constructor binds it to a new unique name.

6.3 Compound Objects

The compound objects for the dynamic semantics are shown in Figure 15. Many conventions and notations are adopted as in the static semantics; in particular projection, injection and modification all retain their meaning. The value Incomplete is used to represent the “value” associated with a variable having an undefined value (e.g. because it was bound using “?”).

We take ⊎ to mean disjoint union over semantic object classes. We also understand all the defined object classes to be disjoint. A particular case deserves mention; ExVal and Pack (exception values and packets) are isomorphic classes, but the latter class corresponds to exceptions which have been raised, and therefore has different semantic significance from the former, which is just a subclass of values.

Although the same names, e.g. E for an environment, are used as in the static semantics, the objects denoted are different. This need cause no confusion since the static and dynamic semantics are presented separately. An important point is that structure names m have no significance at all in the dynamic semantics; this explains why the object class Str = StrName × Env is absent here – for the dynamic semantics the concepts structure and environment coincide.

6.4 Basic Values

The basic values in BasVal are the values bound to predefined variables. These values are denoted by the identifiers to which they are bound in the initial basis (see Appendix C), and are as follows:

             abs floor real sqrt sin cos arctan exp ln
               size chr ord explode implode div mod
                      ~/ * + - = <> < > <= >=

The meaning of basic values (all of which are functions) is represented by the function

APPLY : BasVal × Val → Val ⊎ Pack

which is detailed in Appendix C.

6.5 Basic Exceptions

A subset BasExName ⊂ ExName of the exception names are bound to predefined exception constructors. These names are denoted by the identifiers to which all but the last are bound in the initial basis (see Appendix C), and are as follows:

    Abs  Ord  Chr   Div  Mod  Quot  Prod
    Neg  Sum  Diff  Floor  Sqrt  Exp  Ln
    Match  Bind  Interrupt  NoCode  Abuse

The exceptions on the first two lines are raised by corresponding basic functions, where ~/*+- correspond respectively to NegQuotProdSumDiff. The details are given in Appendix C. The exceptions Match and Bind are raised upon failure of pattern-matching in evaluating a function fn match or a valbind, as detailed in the rules to follow. Interrupt is raised by external intervention. The exception NoCode is raised to signal an attempt to evaluate a specification construct, see below. Finally, Abuse is raised in the verification semantics only, to signal abuse of the convergence predicate (rule 216).

Recall from Section 4.11 that in the context fn match, the match must be irredundant and exhaustive and that the compiler should flag the match if it violates these restrictions. The exception Match can only be raised for a match which is not exhaustive, and has therefore been flagged by the compiler.

For each value binding pat = exp the compiler must issue a report (but still compile) if either pat is not exhaustive or pat contains no variable. This will (on both counts) detect a mistaken declaration like val nil = exp in which the user expects to declare a new variable nil (whereas the language dictates that nil is here a constant pattern, so no variable gets declared). However, these warnings should not be given when the binding is a component of a top-level declaration val valbind; e.g. val x::l = exp_{1} and y = exp_{2} is not faulted by the compiler at top level, but may of course generate a Bind exception.

The exception NoCode is raised when evaluation encounters an expression having an undefined value (i.e. an atomic expression of the form ?, an expression of the form “exists match^{•}”, “forall match^{•}”, “exp^{•} terminates”, “exp_{1}^{•} == exp_{2}^{•}”, or accessing a variable which has been bound to Incomplete). This exception is not bound in the initial basis (but NoCode, Abuse ∈ BasExName to avoid erroneous reuse of these names for user-declared exceptions). Rule 121.1 and premises on rules 120 and 121 guarantee that the exception NoCode cannot be caught by an explicit handler in the program. This is required to ensure that replacing “?” by code will not change the result of an evaluation, except from [NoCode] to something else, provided the evaluation of the new code yields a value. The exception NoCode is handled as a special case in one of the rules for value binding (rule 135.1) — if evaluation of the expression on the right-hand side of a value binding raises NoCode, then the binding is done with the value Incomplete.

6.6 Closures

The informal understanding of a closure (match, E, VE) is as follows: when the closure is applied to a value v, match will be evaluated against v, in the environment E modified in a special sense by VE. The domain Dom VE of this third component contains those function identifiers to be treated recursively in the evaluation. To achieve this effect, the evaluation of match will take place not in E+VE but in E + Rec VE, where

Rec : VarEnv → VarEnv

is defined as follows:

• Dom(Rec VE) = Dom VE

• If VE(id) ∉ Closure, then (Rec VE)(id) = VE(id)

• If VE(id) = (match′, E′, VE′) then (Rec VE)(id) = (match′, E′, VE)

The effect is that, before application of (match, E, VE) to v, the closure values in Ran VE are “unrolled” once, to prepare for their possible recursive application during the evaluation of match upon v.

This device is adopted to ensure that all semantic objects are finite (by controlling the unrolling of recursion). The operator Rec is invoked in just two places in the semantic rules: in the rule for recursive value bindings of the form “rec valbind”, and in the rule for evaluating an application expression “exp atexp” in the case that exp evaluates to a closure.

States and Flags

A state consists of a set of exception names and a flag. The set of exception names records the exceptions introduced so far. The flag indicates whether or not a specification construct (e.g. a quantified expression) has been encountered during the evaluation so far; this includes specification constructs within values, see the next section. Initially, this component is ⊤ and each specification construct makes it ⊥. The meaning of specification constructs in dynamic and verification semantics differs in a significant way. The purpose of the flag is to relate dynamic and verification semantics, see Section 8.8 and the rules for the convergence predicate in the verification semantics, rules 215 to 217. It is also used in the definition of the meaning of quantification in the verification semantics (rules 211–214) where we want to quantify over ML-definable values only.

Let s = (sp, ens). We define the notation s ∧ sp′ as abbreviation for the state (sp ∧ sp′, ens).

In contrast to SML, states do not contain a map from “addresses” to values.

Pure Values

We define a function AI : Val → Bit to indicate whether or not a value is pure, meaning that it does not depend on specification constructs. For example, the expression (fn y=>y terminates) evaluates to an impure value. Impure values can only arise if functional types are involved, since specification constructs in values can occur only within closures. Therefore, the function AI is used directly only in rules 123 (where closures are formed) and 104 (where closures may be extracted from an environment).

AI(v) = ⊤ means that the value v neither directly nor indirectly depends on specification constructs, AI(v) = ⊥ means that there may be such a dependency. Because values include closures, we need corresponding auxiliary functions for various syntactic phrases; for simplicity, we call them all AI as well. The connection is (for expressions): if s, E ⊢ exp ⇒ v, s′ is a derivable sentence in the dynamic semantics then AI(E, exp) ∧ sp of s ≤ AI(v) ∧ sp of s′. The functions AI can be seen as an abstract interpretation, very much in the style of abstract interpretation for strictness analysis.

Another auxiliary function for AI is R̂ec : VarEnv → VarEnv, defined as follows:

• Dom(R̂ec VE) = Dom VE

• If VE(id) ∉ Closure, then (R̂ec VE)(id) = VE(id)

• If VE(id) = (match′, E′, VE′) then

(R̂ec VE)(id) = (match′, E′, VE + {id ↦ 1}).

The operation R̂ec is very similar to Rec except that each identifier id in the variable environment of a closure will be “unrolled” at most once, which is achieved by binding id after one unrolling to the value 1, disregarding its type.

On values, we have AI(v) = ⊥ if v either contains Incomplete or is a closure that contains specification constructs or refers to incompletely defined identifiers:

AI : Val → Bit

     AI(Incomplete) = ⊥

AI(v)  = ⊤ if v ∈ SVal ⊎ BasVal ⊎ Con ⊎ ExName
AI(con, v)  = AI(v)
AI(en, v)  = AI(v)
AI(r)  = ⋀_{lab∈Dom r} AI(r(lab))
AI(match, E, VE) = AI(E + R̂ec VE, match)

The function AI on the right-hand side of the last equation has the form AI : Env × Match → Bit. Similarly, we have a function AI : Env × Exp → Bit for the phrase class Exp, etc. We adopt the notation of options in syntactic phrases for the definition of functions by equations: the option is either present in both sides of an equation or in neither.

AI : Env × Match → Bit

AI(E, mrule ⟨ | match⟩) = AI(E, mrule) ⟨ ∧ AI(E, match)⟩

AI : Env × Mrule → Bit

AI(E, pat => exp)  = AI(E + AI(pat), exp)

The abstract interpretation of a pattern (defined further below) is a variable environment that maps each var in pat to the dummy value 1. It does not depend on the environment because identifiers in patterns of the Bare language already come equipped with their status, i.e. a dynamic environment is neither necessary nor helpful to distinguish value variables from value constructors and exception constructors.

AI : Env × Exp → Bit

AI(E, atexp)  = AI(E, atexp)
AI(E, exp atexp)  = AI(E, exp) ∧ AI(E, atexp)
AI(E, exp_{1}^{•} == exp_{2}^{•})  = ⊥
AI(E, exists match^{•})  = ⊥
AI(E, forall match^{•})  = ⊥
AI(E, exp^{•} terminates) = ⊥
AI(E, exp handle match) = AI(E, exp) ∧ AI(E, match)
AI(E, raise exp)  = AI(E, exp)
AI(E, fn match)  = AI(E, match)

In the first equation, the AI on the right-hand side refers to the corresponding function for atomic expressions. Equality, quantification, and the convergence predicate are considered specification constructs.

AI : Env × AtExp → Bit

AI(E, scon)  = ⊤
AI(E, longvar)  = AI(E(longvar))
AI(E, longcon)  = AI(E(longcon))
AI(E, longexcon)  = AI(E(longexcon))
AI(E, { ⟨exprow⟩ })  = ⊤ ⟨ ∧ AI(E, exprow)⟩
AI(E, let dec in exp end) = sp ∧ AI(E + E′, exp)

where (sp, E′) = AI(E, dec)

AI(E, ( exp ))  = AI(E, exp)
AI(E,?)  = ⊥

The abstract interpretation of a let-expression let dec in exp end is ⊥ if dec depends on specification constructs, even if the corresponding identifier is not used in exp. This reflects the call-by-value nature of evaluation.

Question marks are considered specification constructs when they are used as expressions.

AI : Env × ExpRow → Bit

AI(E, lab = exp ⟨ , exprow⟩) = AI(E, exp) ⟨ ∧ AI(E, exprow)⟩

The abstract interpretation of an (atomic) pattern is a variable environment mapping each value variable that occurs in the pattern to 1, regardless of its type. The value 1 is an arbitrary choice here; any value v with AI(v) = ⊤ would do.

AI : Pat → VarEnv

AI(atpat)  = AI(atpat)
AI(longcon atpat)  = AI(atpat)
AI(longexcon atpat)  = AI(atpat)
AI(var as pat)  = {id ↦ 1} + AI(pat), where var = idv

AI : AtPat → VarEnv

AI( )  = {}
AI(scon)  = {}
AI(var)  = {id ↦ 1}, where var = idv
AI(longcon)  = {}
AI(longexcon)  = {}
AI({ ⟨patrow⟩ })  = {} ⟨ + AI(patrow)⟩
AI(( pat ))  = AI(pat)

AI : PatRow → VarEnv

AI(...)  = {}
AI(lab = pat ⟨ , patrow⟩) = AI(pat) ⟨ + AI(patrow)⟩

For declarations, AI has the form Env×Dec → Bit×Env. The first component of the result indicates whether the declaration depends on specification constructs.

AI : Env × Dec → Bit × Env

AI(E, val valbind)  = (sp, VE in Env)

where (sp, VE) = AI(E, valbind)

AI(E, datatype datbind)  = (⊤, AI(datbind) in Env)
AI(E, abstype datbind with dec end) = (sp, (VE in Env) + E′)
where \{ \begin{matrix}VE & = & AI(datbind) \\ (sp, E′) & = & AI(E + VE, dec) \end{matrix}
AI(E, exception exbind)  = (⊤, AI(exbind) in Env)
AI(E, local dec_{1} in dec_{2} end)  = (sp_{1} ∧ sp_{2}, E_{2})
where \{ \begin{matrix}(sp_{1}, E_{1}) & = & AI(E, dec_{1}) \\ (sp_{2}, E_{2}) & = & AI(E + E_{1}, dec_{2}) \end{matrix}

AI(E, open longstrid_{1} ··· longstrid_{n}) = (⊤, E_{1} + ··· + E_{n})

where E_{i} = E(longstrid_{i}), 1 ≤ i ≤ n

AI(E, dec_{1} ⟨;⟩ dec_{2})  = (sp_{1} ∧ sp_{2}, E_{1} + E_{2})
where \{ \begin{matrix}(sp_{1}, E_{1}) & = & AI(E, dec_{1}) \\ (sp_{2}, E_{2}) & = & AI(E + E_{1}, dec_{2}) \end{matrix}
AI(E,  )  = (⊤, {})

AI : E × ValBind → Bit × VarEnv

AI(E, pat = exp ⟨and valbind⟩)  = (AI(E, exp) ⟨ ∧ sp⟩, AI(pat) ⟨ + VE⟩)

where (sp, VE) = AI(E, valbind)

AI(E, rec valbind)  = (sp, VE)

where (sp, VE) = AI(E + VE, valbind)

The cyclic dependency of VE in the definition of AI(E, rec valbind) is unproblematic: we have VE(id) = 1 for all identifiers id defined in valbind.

AI : DatBind → VarEnv

AI(tyvarseq tycon = conbind ⟨and datbind⟩) = AI(conbind) ⟨ + AI(datbind)⟩

AI : ConBind → VarEnv

AI(con ⟨|conbind⟩)  = {id ↦ 1} ⟨ + AI(conbind)⟩

where con = idv

AI : ExBind → VarEnv

AI(excon ⟨and exbind⟩)  = {id ↦ 1} ⟨ + AI(exbind)⟩

where excon = ide

AI(excon = longexcon ⟨and exbind⟩)  = {id ↦ 1} ⟨ + AI(exbind)⟩

where excon = ide

6.7 Inference Rules

The semantic rules allow sentences of the form

s, A ⊢ phrase ⇒ A′, s′

to be inferred, where A is usually an environment, A′ is some semantic object and s,s′ are the states before and after the evaluation represented by the sentence. Some hypotheses in rules are not of this form; they are called side-conditions.

In most rules the states s and s′ are omitted from sentences; they are only included for those rules which are directly concerned with the state — either referring to its contents or changing it. When omitted, the convention for restoring them is as follows. If the rule is presented in the form

\frac{A_{1} ⊢ phrase_{1} ⇒ A′_{1} A_{2} ⊢ phrase_{2} ⇒ A′_{2} ··· ··· A_{n} ⊢ phrase_{n} ⇒ A′_{n}}{A ⊢ phrase ⇒ A′}

then the full form is intended to be

\frac{s_{0}, A_{1} ⊢ phrase_{1} ⇒ A′_{1}, s_{1} s_{1}, A_{2} ⊢ phrase_{2} ⇒ A′_{2}, s_{2} ··· ··· s_{n−1}, A_{n} ⊢ phrase_{n} ⇒ A′_{n}, s_{n}}{s_{0}, A ⊢ phrase ⇒ A′, s_{n}}

(Any side-conditions are left unaltered). Thus the left-to-right order of the hypotheses indicates the order of evaluation. Note that in the case n = 0, when there are no hypotheses (except possibly side-conditions), we have s_{n} = s_{0}; this implies that the rule causes no side effect. The convention is called the state convention, and must be applied to each version of a rule obtained by inclusion or omission of its options.

A second convention, the exception convention, is adopted to deal with the propagation of exception packets p. For each rule whose full form (ignoring sideconditions) is

\frac{s_{1}, A_{1} ⊢ phrase_{1} ⇒ A′_{1}, s′_{1} ··· s_{n}, A_{n} ⊢ phrase_{n} ⇒ A′_{n}, s′_{n}}{s, A ⊢ phrase ⇒ A′, s′}

and for each k, 1 ≤ k ≤ n, for which the result A′_{k} is not a packet p, an extra rule is added of the form

\frac{s_{1}, A_{1} ⊢ phrase_{1} ⇒ A′_{1}, s′_{1} ··· s_{k}, A_{k} ⊢ phrase_{k} ⇒ p′, s′}{s, A ⊢ phrase ⇒ p′, s′}

where p′ does not occur in the original rule.^{6} This indicates that evaluation of phrases in the hypothesis terminates with the first whose result is a packet (other than one already treated in the rule), and this packet is the result of the phrase in the conclusion.

6There is one exception to the exception convention in the definition of SML; no extra rule is added for rule 119 which deals with handlers, since a handler is the only means by which propagation of an exception can be arrested. For EML, rules 135 and 136 are also exempted from the exception convention — this is required so that a NoCode exception raised during the evaluation of exp in a ValBind of the form “pat = exp ⟨and valbind⟩” can be converted to the value Incomplete.

Recall from Section 1.2 that we support compound metavariables such as v/p. We also allow x/FAIL to range over X ⊎ {FAIL} where x ranges over X (and analogously for x/Incomplete); furthermore, we extend environment modification to allow for failure as follows:

VE + FAIL = FAIL.

Atomic Expressions  E ⊢ atexp ⇒ v/p

E ⊢ scon ⇒ val(scon)

(103)

\frac{E(longvar) = v AI(v) = sp v ≠ Incomplete}{s, E ⊢ longvar ⇒ v, s ∧ sp}  (104)

\frac{E(longvar) = Incomplete}{s, E ⊢ longvar ⇒ [NoCode], s_{⊥}}  (104.1)

\frac{E(longcon) = con}{E ⊢ longcon ⇒ con}  (105)

\frac{E(longexcon) = en}{E ⊢ longexcon ⇒ en}  (106)

\frac{⟨E ⊢ exprow ⇒ r⟩}{E ⊢ \{ ⟨exprow⟩ \} ⇒ \{\}⟨+ r⟩ in Val}  (107)

\frac{E ⊢ dec ⇒ E′ E + E′ ⊢ exp ⇒ v}{E ⊢ let dec in exp end ⇒ v}  (108)

\frac{E ⊢ exp ⇒ v}{E ⊢ ( exp ) ⇒ v}  (109)

\overline{s, E ⊢ ? ⇒ [NoCode], s_{⊥}}  (109.1)

Comments:

(104.1) When a variable’s value is Incomplete, the variable evaluates to the packet [NoCode], indicating that no code exists for that binding.

(105) Value constructors denote themselves.

Expression Rows  E ⊢ exprow ⇒ r/p
\frac{E ⊢ exp ⇒ v ⟨E ⊢ exprow ⇒ r⟩}{E ⊢ lab = exp ⟨ , exprow⟩ ⇒ \{lab ↦ v\}⟨+ r⟩}  (110)

Comment: We may think of components as being evaluated from left to right, because of the state and exception conventions.

Expressions  E ⊢ exp ⇒ v/p
\frac{E ⊢ atexp ⇒ v}{E ⊢ atexp ⇒ v}  (111)

\frac{E ⊢ exp ⇒ con  E ⊢ atexp ⇒ v}{E ⊢ exp atexp ⇒ (con, v)}  (112)

\frac{E ⊢ exp ⇒ en E ⊢ atexp ⇒ v}{E ⊢ exp atexp ⇒ (en, v)}  (113)

Deleted (ref application rule)  (114)

Deleted (:= application rule)  (115)

\frac{E ⊢ exp ⇒ b E ⊢ atexp ⇒ v APPLY(b, v) = v′/p}{E ⊢ exp atexp ⇒ v′/p}  (116)

\frac{E ⊢ exp ⇒ (match, E′, VE) E ⊢ atexp ⇒ v E′ + Rec VE, v ⊢ match ⇒ v′}{E ⊢ exp atexp ⇒ v′}  (117)

\frac{E ⊢ exp ⇒ (match, E′, VE) E ⊢ atexp ⇒ v E′ + Rec VE, v ⊢ match ⇒ FAIL}{E ⊢ exp atexp ⇒ [Match]}  (118)

s, E ⊢ exp_{1}^{•} == exp_{2}^{•} ⇒ [NoCode], s_{⊥}

(118.1)

s, E ⊢ exists match^{•} ⇒ [NoCode], s_{⊥}

(118.2)

s, E ⊢ forall match^{•} ⇒ [NoCode], s_{⊥}

(118.3)

            s, E ⊢ exp^{•} terminates ⇒ [NoCode], s_{⊥}

(118.4)

\frac{E ⊢ exp ⇒ v}{E ⊢ exp handle match ⇒ v}  (119)

\frac{E ⊢ exp ⇒ [e] e ≠ NoCode E, e ⊢ match ⇒ v}{E ⊢ exp handle match ⇒ v}  (120)

\frac{E ⊢ exp ⇒ [e] e ≠ NoCode E, e ⊢ match ⇒ FAIL}{E ⊢ exp handle match ⇒ [e]}  (121)

\frac{E ⊢ exp ⇒ [NoCode]}{E ⊢ exp handle match ⇒ [NoCode]}  (121.1)

\frac{E ⊢ exp ⇒ e}{E ⊢ raise exp ⇒ [e]}  (122)

\frac{v = (match, E, \{\}) AI(v) = sp}{s, E ⊢ fn match ⇒ v, s ∧ sp}  (123)

Comments:

(112)–(118) Note that none of the rules for function application has a premise in which the operator evaluates to a constructed value or a record. This is because we are interested in the evaluation of well-typed programs only, and in such programs exp will always have a functional type.

(116) The semantics of SML [MTH90] does not treat the case where an APPLY result is a packet. This is an oversight, probably caused by the fact that the exception convention does not apply to side-conditions.

Notice that the application of a basic value never raises the exception NoCode — in that case we would have to set the state flag to ⊥ here.

(118.1)–(118.4) Remember that s_{⊥} is shorthand for (⊥, ens of s).

(119) The exception convention does not apply to this rule. If the operator evaluates to a packet then rule 120 or rule 121 or rule 121.1 must be used.

(121) Packets that are not handled by the match propagate.

(120),(121),(121.1) The packet [NoCode] cannot be handled.

(123) The third component of the closure is empty because the match does not introduce new recursively defined values.

Matches  E, v ⊢ match ⇒ v′/p/FAIL
\frac{E, v ⊢ mrule ⇒ v′}{E, v ⊢ mrule ⟨ | match⟩ ⇒ v′}  (124)

\frac{E, v ⊢ mrule ⇒ FAIL}{E, v ⊢ mrule ⇒ FAIL}  (125)

\frac{E, v ⊢ mrule ⇒ FAIL E, v ⊢ match ⇒ v′/FAIL}{E, v ⊢ mrule | match ⇒ v′/FAIL}  (126)

Comment: A value v occurs on the left of the turnstile, in evaluating a match. We may think of a match as being evaluated against a value; similarly, we may think of a pattern as being evaluated against a value. Alternative match rules are tried from left to right.

Match Rules  E, v ⊢ mrule ⇒ v′/p/FAIL
\frac{E, v ⊢ pat ⇒ VE  E + VE ⊢ exp ⇒ v′}{E, v ⊢ pat => exp ⇒ v′}  (127)

\frac{E, v ⊢ pat ⇒ FAIL}{E, v ⊢ pat => exp ⇒ FAIL}  (128)

Declarations  E ⊢ dec ⇒ E′/p
\frac{E ⊢ valbind ⇒ VE}{E ⊢ val valbind ⇒ VE in Env}  (129)

\frac{⊢ datbind ⇒ VE}{E ⊢ datatype datbind ⇒ VE in Env}  (129.5)

\frac{⊢ datbind ⇒ VE  E + VE ⊢ dec ⇒ E′}{E ⊢ abstype datbind with dec end ⇒ E′}  (129.6)

\frac{E ⊢ exbind ⇒ VE}{E ⊢ exception exbind ⇒ VE in Env}  (130)

\frac{E ⊢ dec_{1} ⇒ E_{1} E + E_{1} ⊢ dec_{2} ⇒ E_{2}}{E ⊢ local dec_{1} in dec_{2} end ⇒ E_{2}}  (131)

\frac{E(longstrid_{1}) = E_{1} ··· E(longstrid_{n}) = E_{n}}{E ⊢ open longstrid_{1} ··· longstrid_{n} ⇒ E_{1} + ··· + E_{n}}  (132)

\overline{E ⊢  ⇒ \{\} in Env}  (133)

\frac{E ⊢ dec_{1} ⇒ E_{1} E + E_{1} ⊢ dec_{2} ⇒ E_{2}}{E ⊢ dec_{1} ⟨;⟩ dec_{2} ⇒ E_{1} + E_{2}}  (134)

Value Bindings  E ⊢ valbind ⇒ VE/p
\frac{E ⊢ exp ⇒ v E, v ⊢ pat ⇒ VE  ⟨E ⊢ valbind ⇒ VE′⟩}{E ⊢ pat = exp ⟨and valbind⟩ ⇒ VE ⟨+ VE′⟩}  (135)

\frac{E ⊢ exp ⇒ [NoCode] E, Incomplete ⊢ pat ⇒ VE ⟨E ⊢ valbind ⇒ VE′⟩}{E ⊢ pat = exp ⟨and valbind⟩ ⇒ VE ⟨+ VE′⟩}  (135.1)

\frac{E ⊢ exp ⇒ [e], e ≠ NoCode}{E ⊢ pat = exp ⟨and valbind⟩ ⇒ [e]}  (135.2)

\frac{E ⊢ exp ⇒ v E, v ⊢ pat ⇒ FAIL}{E ⊢ pat = exp ⟨and valbind⟩ ⇒ [Bind]}  (136)

\frac{E ⊢ exp ⇒ [NoCode] E, Incomplete ⊢ pat ⇒ FAIL}{E ⊢ pat = exp ⟨and valbind⟩ ⇒ [NoCode]}  (136.1)

\frac{E ⊢ valbind ⇒ VE}{E ⊢ rec valbind ⇒ Rec VE}  (137)

Comments:

(135),(136) The exception convention does not apply to these rules. If the expression evaluates to a packet then rule 135.1 or 135.2 (in the case of rule 135) or rule 136.1 (in the case of rule 136) must be used.

(135.1),(136.1) If the exception NoCode is raised while evaluating the expression (e.g. because it contains quantifiers), the exception is caught before doing the binding. Then the binding is done with the value Incomplete.

(135.2) Any exception other than NoCode is propagated as usual.

Data Type Bindings  ⊢ datbind ⇒ VE
\frac{⊢ conbind ⇒ VE  ⟨ ⊢ datbind ⇒ VE′⟩}{⊢ tyvarseq tycon = conbind ⟨and datbind⟩ ⇒ VE ⟨+ VE′⟩}  (137.1)

Constructor Bindings  ⊢ conbind ⇒ VE
\frac{con = idc ⟨ ⊢ conbind ⇒ VE⟩}{⊢ con ⟨ | conbind⟩ ⇒ \{id ↦ con\} ⟨+ VE⟩}  (137.2)

Exception Bindings  E ⊢ exbind ⇒ VE

In the SML definition, sentences for exception bindings have the more general form E ⊢ exbind ⇒ EE/p. But the /p is redundant, since packets can never arise here. VE now incorporates the information that was formerly in VE and EE because exception environments are not quite up to the task they were originally designed for, see [Kah93]. The distinction between exception constructors and other identifiers is handled in EML by the semantics of derived forms.

\frac{en = min(ExName \ (ens of s)) s′ = s + \{en\} excon = ide ⟨s′, E ⊢ exbind ⇒ VE, s′′⟩}{s, E ⊢ excon ⟨and exbind⟩ ⇒ \{id ↦ en\}⟨+ VE⟩, s′⟨′⟩}  (138)

\frac{E(longexcon) = en excon = ide ⟨E ⊢ exbind ⇒ VE⟩}{E ⊢ excon = longexcon ⟨and exbind⟩ ⇒ \{id ↦ en\}⟨+ VE⟩}  (139)

Comments:

(138) The two side conditions ensure that a new exception name is generated and recorded as “used” in subsequent states. In contrast to Standard ML, the fresh exception name is chosen deterministically to conform with the verification semantics, see rules 259 and 260.

Atomic Patterns  E, v ⊢ atpat ⇒ VE/FAIL
\overline{E, v ⊢ ⇒ \{\}}  (140)

\frac{v = val(scon)}{E, v ⊢ scon ⇒ \{\}}  (141)

\frac{v ≠ val(scon)}{E, v ⊢ scon ⇒ FAIL}  (142)

\frac{var = idv}{E, v ⊢ var ⇒ \{id ↦ v\}}  (143)

\frac{E(longcon) = con  con = v}{E, v ⊢ longcon ⇒ \{\}}  (144)

\frac{E(longcon) ≠ v}{E, v ⊢ longcon ⇒ FAIL}  (145)

\frac{E(longexcon) = en en = v}{E, v ⊢ longexcon ⇒ \{\}}  (146)

\frac{E(longexcon) ≠ v}{E, v ⊢ longexcon ⇒ FAIL}  (147)

\frac{v = \{\}⟨+r⟩ in Val ⟨E, r ⊢ patrow ⇒ VE/FAIL⟩}{E, v ⊢ \{ ⟨patrow⟩ \} ⇒ \{\}⟨+VE/FAIL⟩}  (148)

\frac{v = Incomplete ⟨E, Incomplete ⊢ patrow ⇒ VE/FAIL⟩}{E, v ⊢ \{ ⟨patrow⟩ \} ⇒ \{\}⟨+VE/FAIL⟩}  (148.1)

\frac{E, v ⊢ pat ⇒ VE/FAIL}{E, v ⊢ ( pat ) ⇒ VE/FAIL}  (149)

Comments:

(142),(145),(147) Any evaluation resulting in FAIL must do so because rule 142, rule 145, rule 147, rule 155, or rule 157 has been applied.

(148.1) The intention here (cf. rules 150.1, 151.1, 152.1) is that in a value binding of the form pat = ? ⟨and valbind⟩ (or pat = exp ⟨and valbind⟩ where exp evaluates to [NoCode]), the undefined value decomposes arbitrarily as long as the type of pat ensures that any value of that type decomposes (disregarding the case of datatypes with only one constructor). So for example,

    val (x,y) = ?

will successfully bind both x and y to Incomplete (recall that (x,y) expands

to {1=x,2=y}), while
    val [x] = ?

will fail (by the eventual use of rule 155) and consequently raise [NoCode].

Pattern Rows  E, r/Incomplete ⊢ patrow ⇒ VE/FAIL
\overline{E, r ⊢ ... ⇒ \{\}}  (150)

                      E, Incomplete ⊢ ... ⇒ {}

(150.1)
\frac{E, r(lab) ⊢ pat ⇒ FAIL}{E, r ⊢ lab = pat ⟨ , patrow⟩ ⇒ FAIL}  (151)
\frac{E, Incomplete ⊢ pat ⇒ FAIL}{E, Incomplete ⊢ lab = pat ⟨ , patrow⟩ ⇒ FAIL}  (151.1)
\frac{E, r(lab) ⊢ pat ⇒ VE  ⟨E, r ⊢ patrow ⇒ VE′/FAIL⟩}{E, r ⊢ lab = pat ⟨ , patrow⟩ ⇒ VE⟨+ VE′/FAIL⟩}  (152)

\frac{E, Incomplete ⊢ pat ⇒ VE ⟨E, Incomplete ⊢ patrow ⇒ VE′/FAIL⟩}{E, Incomplete ⊢ lab = pat ⟨ , patrow⟩ ⇒ VE⟨+ VE′/FAIL⟩}  (152.1)

Comments: (151),(152) For well-typed programs lab will be in the domain of r.

Patterns  E, v ⊢ pat ⇒ VE/FAIL
\frac{E, v ⊢ atpat ⇒ VE/FAIL}{E, v ⊢ atpat ⇒ VE/FAIL}  (153)

\frac{E(longcon) = con  v = (con, v′) E, v′ ⊢ atpat ⇒ VE/FAIL}{E, v ⊢ longcon atpat ⇒ VE/FAIL}  (154)
\frac{E(longcon) = con  v ∉ \{con\} × Val}{E, v ⊢ longcon atpat ⇒ FAIL}  (155)

\frac{E(longexcon) = en v = (en, v′) E, v′ ⊢ atpat ⇒ VE/FAIL}{E, v ⊢ longexcon atpat ⇒ VE/FAIL}  (156)
\frac{E(longexcon) = en v ∉ \{en\} × Val}{E, v ⊢ longexcon atpat ⇒ FAIL}  (157)

Deleted (ref application rule)  (158)

\frac{var = idv E, v ⊢ pat ⇒ VE/FAIL}{E, v ⊢ var as pat ⇒ \{id ↦ v\} + VE/FAIL}  (159)

7 Dynamic Semantics for Modules

The semantics of EML programs (see Section 10) does not depend on the dynamic semantics for Modules. The purpose of this section is (together with the dynamic semantics for the Core) to define computation with incomplete programs.

7.1 Reduced Syntax

Since signature expressions are mostly dealt with in the static semantics, the dynamic semantics need only take limited account of them. Unlike types, it cannot ignore them completely; the reason is that an explicit signature ascription plays the role of restricting the “view” of a structure — that is, restricting the domains of its component environments. However, the types and the sharing properties of structures and signatures are irrelevant to dynamic evaluation; the syntax is therefore reduced by the following transformations (in addition to those for the Core), for the purpose of the dynamic semantics of Modules:

• Qualifications “of ty” are omitted from constructor descriptions and exception descriptions.

• We remove specifications without computational content, i.e. any specification of the form “axiom axdesc”, “type typdesc”, “eqtype typdesc” or “sharing shareq” is replaced by the empty specification. Descriptions of datatypes cannot be replaced by the empty specification, as they also give rise to a variable environment in the static semantics. This was not correctly treated in the definition of SML [MTH90] or corrected in [MT91].

• The Modules phrase classes TypDesc, AxDesc, SpecExp and SharEq are omitted.

7.2 Semantic Objects

The semantic objects for the Modules dynamic semantics, extra to those for the Core dynamic semantics, are shown in Figure 16. An interface I ∈ Int represents a “view” of a structure. An interface in the dynamic semantics of SML includes a set of value variables and a set of exception constructors; they are replaced here by a status environment. Specifications and signature expressions will evaluate to interfaces; moreover, during the evaluation of a specification or signature expression, structures (to which a specification or signature expression may refer via “open”) are represented only by their interfaces. To extract an interface from a dynamic environment we define two operations

Inter : \{ \begin{matrix}Env → Int \\ VarEnv → StatEnv \end{matrix}

(strid : I, strexp : I′, B) ∈ FunctorClosure

= (StrId × Int) × (StrExp × Int) × Basis

(IE, StE) or I ∈ Int = IntEnv × StatEnv
IE ∈ IntEnv = StrId →^{fin} Int
st ∈ Status = {v, c, e}
StE ∈ StatEnv = Id →^{fin} Status
G ∈ SigEnv = SigId →^{fin} Int
F ∈ FunEnv = FunId →^{fin} FunctorClosure
(F, G, E) or B ∈ Basis = FunEnv × SigEnv × Env
(G, IE) or IB ∈ IntBasis = SigEnv × IntEnv

Figure 16: Further Semantic Objects

as follows:

Inter(SE, VE) = (IE, Inter VE)

where

IE = {strid ↦ Inter E ; SE(strid) = E}
Inter VE = {id ↦ v ; id ∈ Dom VE}

Notice that all identifiers are assigned status v in Inter VE. This is so, because dynamic environments do not keep track of identifier status.

An interface basis IB = (G, IE) is that part of a basis needed to evaluate signature expressions and specifications. The function Inter is extended to create an interface basis from a basis B as follows:

Inter(F, G, E) = (G, IE of (Inter E))

A further operation ↓ : Env × Int → Env

is required, to cut down an environment E to a given interface I, representing the effect of an explicit signature ascription. It is defined as follows:

(SE, VE) ↓ (IE, StE) = (SE′, VE′)

where

SE′ = {strid ↦ E ↓ I ; SE(strid) = E and IE(strid) = I}
VE′ = {id ↦ v ; VE(id) = v and id ∈ Dom StE}

It is important to note that interfaces are statically known — they can be obtained by appropriate projections from the static value Σ of a principle signature and the environment E_{DER} produced by the semantics for derived forms, see Appendix B.

As in the dynamic semantics of the core language, the use of “?” in structure and functor bindings does not cause an exception to be raised until computation occurs which makes use of undefined components. Consider the following example:

      structure A : SIG = ? ;
      functor F(X : SIG) : SIG' = ? ;
      structure B : SIG' = F(A)

This will successfully evaluate without raising an exception. Any later attempt to perform a computation using any component of A or B will raise an exception, however.

To generate a “trivial” dynamic environment from an interface (with respect to a given exception name set) we define the operation

TrivEnv : Int × ExNameSet → Env × ExNameSet

as follows:

TrivEnv((IE, StE), ens) = (SE, VE), ens′

where

SE = {strid_{1} ↦ E_{1}, …, strid_{n} ↦ E_{n}}
VE = {id ↦ Incomplete ; StE(id) = v}+

{id ↦ idc ; StE(id) = c}+

{id_{1} ↦ en_{1}, ···, id_{k} ↦ en_{k} ; StE(id_{j}) = e, 1 ≤ j ≤ k}

ens′ = ens_{n} ∪ {en_{1}, …, en_{k}}

where

{strid_{1}, …, strid_{n}} = Dom IE
VE(id) = en ∧ VE(id′) = en ⇒ id = id′
{en_{1}, …, en_{k}} ∩ ens_{n} = ∅
(E_{1}, ens_{1}) = TrivEnv(IE(strid_{1}), ens)
(E_{2}, ens_{2}) = TrivEnv(IE(strid_{2}), ens_{1})
··· ···
(E_{n}, ens_{n}) = TrivEnv(IE(strid_{n}), ens_{n−1})

This binds Incomplete to each variable in the interface and a fresh exception name to each exception constructor. This operation is used to produce the dynamic environment needed in a structure binding of the form

strid : psigexp = ? ⟨and strbind⟩.

Note that the result is independent (modulo the choice of exception names) of the particular enumeration of the domains of IE and StE.

To generate a “trivial” structure expression from an interface we define the operation

TrivStrExp : Int → StrExp as follows:

TrivStrExp(IE, StE) = struct structure strid_{1} = TrivStrExp(IE(strid_{1})) ··· ··· and strid_{n} = TrivStrExp(IE(strid_{n})) val var_{1} = ? and … and var_{p} = ? exception excon_{1} and … and excon_{m} datatype dummy = con_{1} | … | con_{r} end

where:

{strid_{1}, …, strid_{n}} = Dom IE
{var_{1}, …, var_{p}} = {idv | id ∈ Dom StE ; StE(id) = v}
{excon_{1}, …, excon_{m}} = {ide | id ∈ Dom StE ; StE(id) = e}
{con_{1}, …, con_{r}} = {idc | id ∈ Dom StE ; StE(id) = c}

This operation is used to produce the structure expression in the functor closure produced by a functor binding “funid ( strid : psigexp ) : psigexp′ = ?”.

7.3 Inference Rules

The semantic rules allow sentences of the form

s, A ⊢ phrase ⇒ A′, s′

to be inferred, where A is either a basis or an interface basis or empty, A′ is some semantic object and s,s′ are the states before and after the evaluation represented by the sentence. Some hypotheses in rules are not of this form; they are called side-conditions.

The state and exception conventions are adopted as in the Core dynamic semantics. However, it may be shown that the only Modules phrases whose evaluation may cause a side-effect or generate an exception packet are of the form strexp, strdec, strbind, sglstrbind or topdec.

Structure Expressions  B ⊢ strexp ⇒ E/p
\frac{B ⊢ strdec ⇒ E}{B ⊢ struct strdec end ⇒ E}  (160)

\frac{B(longstrid) = E}{B ⊢ longstrid ⇒ E}  (161)

\frac{B(funid) = (strid : I, strexp′ : I′, B′) B ⊢ strexp ⇒ E  B′ + \{strid ↦ E ↓ I\} ⊢ strexp′ ⇒ E′}{B ⊢ funid ( strexp ) ⇒ E′ ↓ I′}  (162)

\frac{B ⊢ strdec ⇒ E  B + E ⊢ strexp ⇒ E′}{B ⊢ let strdec in strexp end ⇒ E′}  (163)

Comments:

(162) Before the evaluation of the functor body strexp′, the actual argument E is cut down by the formal parameter interface I, so that any opening of strid resulting from the evaluation of strexp′ will produce no more components than anticipated during the static elaboration.

Structure-level Declarations  B ⊢ strdec ⇒ E/p
\frac{E of B ⊢ dec ⇒ E′}{B ⊢ dec ⇒ E′}  (164)

s, B ⊢ axiom ax ⇒ {} in Env, s

(164.1)

\frac{B ⊢ strbind ⇒ SE}{B ⊢ structure strbind ⇒ SE in Env}  (165)

\frac{B ⊢ strdec_{1} ⇒ E_{1} B + E_{1} ⊢ strdec_{2} ⇒ E_{2}}{B ⊢ local strdec_{1} in strdec_{2} end ⇒ E_{2}}  (166)

\overline{B ⊢ ⇒ \{\} in Env}  (167)

\frac{B ⊢ strdec_{1} ⇒ E_{1} B + E_{1} ⊢ strdec_{2} ⇒ E_{2}}{B ⊢ strdec_{1} ⟨;⟩ strdec_{2} ⇒ E_{1} + E_{2}}  (168)

Structure Bindings  B ⊢ strbind ⇒ SE/p
\frac{B ⊢ sglstrbind ⇒ SE  ⟨B ⊢ strbind ⇒ SE′⟩}{B ⊢ sglstrbind ⟨and strbind⟩ ⇒ SE ⟨+SE′⟩}  (169)

Single Structure Bindings  B ⊢ sglstrbind ⇒ SE/p
\frac{B ⊢ strexp ⇒ E  Inter B ⊢ psigexp ⇒ I}{B ⊢ strid : psigexp = strexp ⇒ \{strid ↦ E ↓ I\}}  (169.1)

\frac{s, Inter B ⊢ psigexp ⇒ I, s′ (E, ens′) = TrivEnv(I, ens of s′)}{s, B ⊢ strid : psigexp = ? ⇒ \{strid ↦ E\}, (sp of s′, ens′)}  (169.2)

\frac{B ⊢ strexp ⇒ E}{B ⊢ strid = strexp ⇒ \{strid ↦ E\}}  (169.3)

Comments:

(169.1),(169.2) As in the static semantics, psigexp constrains the “view” of the structure. The restriction must be done in the dynamic semantics to ensure that any dynamic opening of the structure produces no more components than anticipated during the static elaboration.

(169.2) The state has been made explicit here because the side condition accesses the state.

Signature Expressions  IB ⊢ sigexp ⇒ I
\frac{IB ⊢ spec ⇒ I}{IB ⊢ sig spec end ⇒ I}  (170)

\frac{IB(sigid) = I}{IB ⊢ sigid ⇒ I}  (171)

Principal Signatures  IB ⊢ psigexp ⇒ I
\frac{IB ⊢ sigexp ⇒ I}{IB ⊢ sigexp ⇒ I}  (171.1)

Signature Declarations  IB ⊢ sigdec ⇒ G
\frac{IB ⊢ sigbind ⇒ G}{IB ⊢ signature sigbind ⇒ G}  (172)

\overline{IB ⊢ ⇒ \{\}}  (173)

\frac{IB ⊢ sigdec_{1} ⇒ G_{1} IB + G_{1} ⊢ sigdec_{2} ⇒ G_{2}}{IB ⊢ sigdec_{1} ⟨;⟩ sigdec_{2} ⇒ G_{1} + G_{2}}  (174)

Signature Bindings  IB ⊢ sigbind ⇒ G
\frac{IB ⊢ sigexp ⇒ I  ⟨IB ⊢ sigbind ⇒ G⟩}{IB ⊢ sigid = psigexp ⟨and sigbind⟩ ⇒ \{sigid ↦ I\} ⟨+ G⟩}  (175)

Specifications  IB ⊢ spec ⇒ I
\frac{⊢ valdesc ⇒ StE}{IB ⊢ val valdesc ⇒ StE in Int}  (176)

\frac{⊢ datdesc ⇒ StE}{IB ⊢ datatype datdesc ⇒ StE in Int}  (176.1)

\frac{⊢ exdesc ⇒ StE}{IB ⊢ exception exdesc ⇒ StE in Int}  (177)

\frac{IB ⊢ strdesc ⇒ IE}{IB ⊢ structure strdesc ⇒ IE in Int}  (178)

\frac{IB ⊢ spec_{1} ⇒ I_{1} IB + IE of I_{1} ⊢ spec_{2} ⇒ I_{2}}{IB ⊢ local spec_{1} in spec_{2} end ⇒ I_{2}}  (179)

\frac{IB(longstrid_{1}) = I_{1} ··· IB(longstrid_{n}) = I_{n}}{IB ⊢ open longstrid_{1} ··· longstrid_{n} ⇒ I_{1} + ··· + I_{n}}  (180)

\frac{IB(sigid_{1}) = I_{1} ··· IB(sigid_{n}) = I_{n}}{IB ⊢ include sigid_{1} ··· sigid_{n} ⇒ I_{1} + ··· + I_{n}}  (181)

\overline{IB ⊢ ⇒ \{\} in Int}  (182)

\frac{IB ⊢ spec_{1} ⇒ I_{1} IB + IE of I_{1} ⊢ spec_{2} ⇒ I_{2}}{IB ⊢ spec_{1} ⟨;⟩ spec_{2} ⇒ I_{1} + I_{2}}  (183)

Comments:

(176.1) In the definition of SML, datatype descriptions are treated as empty specifications. This is a bug since they elaborate to non-empty variable environments in the static semantics.

(179),(183) Note that StE of I_{1} is not needed for the evaluation of spec_{2}.

Value Descriptions  ⊢ valdesc ⇒ StE
\frac{var = idv ⟨ ⊢ valdesc ⇒ StE⟩}{⊢ var ⟨and valdesc⟩ ⇒ \{id ↦ v\} ⟨+StE⟩}  (184)

Datatype Descriptions  ⊢ datdesc ⇒ StE
\frac{⊢ condesc ⇒ StE  ⟨ ⊢ datdesc ⇒ StE′⟩}{⊢ tyvarseq tycon = condesc ⟨and datdesc⟩ ⇒ StE ⟨+StE′⟩}  (184.1)

Constructor Descriptions  ⊢ condesc ⇒ StE
\frac{con = idc ⟨ ⊢ condesc ⇒ StE⟩}{⊢ con ⟨ | condesc⟩ ⇒ \{id ↦ c\} ⟨+StE⟩}  (184.2)

Exception Descriptions  ⊢ exdesc ⇒ StE
\frac{excon = ide ⟨⊢ exdesc ⇒ StE⟩}{⊢ excon ⟨and exdesc⟩ ⇒ \{id ↦ e\} ⟨+StE⟩}  (185)

Structure Descriptions  IB ⊢ strdesc ⇒ IE
\frac{IB ⊢ sigexp ⇒ I  ⟨IB ⊢ strdesc ⇒ IE⟩}{IB ⊢ strid : sigexp ⟨and strdesc⟩ ⇒ \{strid ↦ I\} ⟨+ IE⟩}  (186)

Functor Bindings  B ⊢ funbind ⇒ F

\frac{Inter B ⊢ psigexp ⇒ I  Inter B + \{strid ↦ I\} ⊢ psigexp′ ⇒ I′ ⟨B ⊢ funbind ⇒ F ⟩}{B ⊢ funid ( strid : psigexp ) : psigexp′ = strexp ⟨and funbind⟩ ⇒ \{funid ↦ (strid : I, strexp : I′, B)\} ⟨+ F ⟩}  (187)

\frac{Inter B ⊢ psigexp ⇒ I  Inter B + \{strid ↦ I\} ⊢ psigexp′ ⇒ I′ ⟨B ⊢ funbind ⇒ F ⟩}{B ⊢ funid ( strid : psigexp ) : psigexp′ = ? ⟨and funbind⟩ ⇒ \{funid ↦ (strid : I, TrivStrExp I′ : I′, B)\} ⟨+ F ⟩}  (187.1)

Functor Declarations  B ⊢ fundec ⇒ F

\frac{B ⊢ funbind ⇒ F}{B ⊢ functor funbind ⇒ F}  (188)

\overline{B ⊢ ⇒ \{\}}  (189)

\frac{B ⊢ fundec_{1} ⇒ F_{1} B + F_{1} ⊢ fundec_{2} ⇒ F_{2}}{B ⊢ fundec_{1} ⟨;⟩ fundec_{2} ⇒ F_{1} + F_{2}}  (190)

Top-level Declarations  B ⊢ topdec ⇒ B′/p
\frac{B ⊢ strdec ⇒ E}{B ⊢ strdec ⇒ E in Basis}  (191)

\frac{Inter B ⊢ sigdec ⇒ G}{B ⊢ sigdec ⇒ G in Basis}  (192)

\frac{B ⊢ fundec ⇒ F}{B ⊢ fundec ⇒ F in Basis}  (193)

8 Verification Semantics for the Core

While the dynamic semantics defines evaluation of an expression in an environment, the verification semantics defines its evaluation in a model, which consists of an environment, a trace, and an interpretation for question marks, see below. We do not require a priori that the question mark interpretation is well-formed in the sense that the replacement of question marks leads to a well-typed program; such ill-formed models are eliminated a posteriori during verification.

Another difference to the dynamic semantics is that some rules in the verification semantics are non-computational, involving e.g. infinitary premises (expressed using higher-order rules), which is necessary to give meaning to specification constructs.

8.1 Semantic Objects

Many semantic objects used in the verification semantics already occur in the static and dynamic semantics. We use the same names for these object classes and the same variables to range over them, except when ambiguities occur. In that case, we attach to variables (similarly for object classes) a subscript STAT (resp. DYN), to indicate that it ranges over the corresponding object class of the static (resp. dynamic) semantics.

Additional and modified semantic objects are shown in Figure 17.

The conventions and notations used in earlier sections are adopted here as well; for example projection, injection and modification retain the meaning they were given in Section 4.3.

For type values, we have instantiation, equivalence, and closure analogous to type schemes and trace schemes: ∀α^{(k)}.(v, τ) ≻ (v′, τ′) if there is a type substitution ϑ with Dom ϑ = α^{(k)} and ϑ(τ) = τ′, ϑ(v) = v′. (In general, ϑ(v) = v does not hold, because values can contain closures and closures can contain type information in traces and environments.) Clos_{C}(v, τ) = ∀α^{(k)}.(v, τ), where α^{(k)} are the variables occurring in v or τ but not in C. Closure of variable environments is also analogous to the closure of static variable environments, e.g. Clos_{FE}VE can be obtained from VE by pointwise abstracting all type variables not free in FE.

We use the notation M(x) or FE(x) to apply the appropriate component of E of FE to x, where x is a (possibly long) identifier of some sort. The application of environments to long identifiers is analogous to its definition in Section 4.3.

8.2 Question Mark Interpretation

A question mark interpretation QI consists of two maps, QIE (for expressions) and QIT (for types). These maps are not much more than (infinite) lists of pieces of syntax (of the bare language), intended as replacements for occurrences of question marks in expressions and type bindings. The well-formedness of these

n ∈ N = {0, 1, 2, ...}
CT ∈ TyCons = Fin(Id × TypeScheme)
ET ∈ TyExcs = Fin(ExName × Type)
V T ∈ ValTemp = TyCons × TyExcs
TI or φ_{Ty} ∈ TypeInt = TyName → TypeFcn
QI ∈ QInt = QIntExp × QIntTy
QIE ∈ QIntExp = N → Exp
QIT ∈ QIntTy = N → Ty
(ens, TI, φ_{Ty}, V T , n, l) or s ∈ State = ExNameSet × TypeInt × TypeInt

× ValTemp × N × Bit

(SE, TE, VE) or E ∈ Env = StrEnv × TyEnv × VarEnv
SE ∈ StrEnv = StrId →^{fin} Str
VE ∈ VarEnv = Id →^{fin} TypeVal
∀α^{(k)}.(v, τ) or tv ∈ TypeVal = ⊎_{k≥0}TyVar^{k} × Val × Type
(E, m) or S ∈ Str = Env × StrName
v ∈ Val = SVal ⊎ BasVal ⊎ Con ⊎ (Con × Val)

⊎ ExVal ⊎ Record ⊎ Closure

r ∈ Record = Lab →^{fin} Val
e ∈ ExVal = ExName ⊎ (ExName × Val)
[e] or p ∈ Pack = ExVal
(match, M, VE) ∈ Closure = Match × Mod × VarEnv
(E, QI) or FE ∈ FullEnv = Env × QInt
(FE, γ) or M ∈ Mod = FullEnv × Trace

Figure 17: Semantic Objects replacements w.r.t. the context in which they occur is checked during verification, for instance rule 201 checks that the replacement of a question mark in an expression has the right type.

We use the state (see next section) to associate the elements of these lists with occurrences of question marks.

8.3 State

A state s has six components: a set of exception names ens, for exactly the same purpose as in the dynamic semantics; a type interpretation TI for modelling the interpretation of type names originating from question mark type bindings; another type interpretation φ_{Ty} for representing the matching realisations of abstract types in signatures; a pair of sets of value templates V T for maintaining some necessary additional information about constructors — see the next section; a natural number n for counting occurrences of ?; and a flag l which will be used later in the module semantics. We write s ⊕ n for the state in which n of s is replaced by n. Similarly to the dynamic semantics, we write s_{⊥} and s_{⊤} for the state s modified by setting l to ⊥ or ⊤, respectively.

The component nofs is always statically known; in other words, using the state is not essential for finding the right interpretations for question mark occurrences. An alternative would be to change the syntax of the bare language, requiring a (unique) label for each occurrence of ?; the semantics of derived forms could be used to compute such labels. However, the method we use here seems to make less “noise”.

We define a family of functions Replace : (Phrase×QInt×N) → (Phrase×N), where Phrase is a class of syntactical phrases (of the core). These functions replace all occurrences of ? by the corresponding object taken from the question mark interpretation. The purpose of the natural number is to establish this correspondence. For example, we have for atomic expressions:

Replace(?, QI, n) = ((QIE of QI)(n), n + 1)
Replace(longvar, QI, n) = (longvar, n)
Replace(let dec in exp end, QI, n) = (let dec′ in exp′ end, n′′) where
(dec′, n′) = Replace(dec, QI, n)
(exp′, n′′) = Replace(exp, QI, n′)

On other syntactical phrases, Replace is defined completely analogously, following the schema of let-expressions for all composed phrases. Replace(phrase, QI, n) can be obtained from phrase by replacing the k + 1-th occurrence of ? (an atomic expression or in a type binding) by either (QIEofQI)(n+k) or (QIT ofQI)(n+k), respectively.

8.4 Value Access

The V T component of the state contains the value templates; these are all value constructors and exception names introduced so far. Any value of any type can be decomposed into value templates, basic values, special values, and closures. The purpose of storing the value templates is to allow quantifiers to access values that are “hidden” due to e.g. value constructors used to build them being no longer in scope.

We define a semantic function Comp : Env × ValTemp → VarEnv for completing environments as follows: Comp(E, V T) = VE where

1. For each (en, τ) in V T there is an id such that VE(id) = (en, τ).

2. For each (id, ∀α^{(k)}.τ) in V T there is an id′ such that VE(id′) = ∀α^{(k)}.(idc, τ).

3. Any id in the domain of VE is of one of the two above forms and is not in the domain of E.

We abbreviate Comp(E of FE, V T of s) as Comp(FE, s).

The intention is to enable each value “belonging to a type” to be obtained by verificating some expression in Comp(FE, s).

To convert constructor environments to value templates, we assume another semantic function Graph, which maps a finite function to its graph (set of pairs). In particular, Graph maps a constructor environment CE to a finite set of value templates CT.

8.5 Type Interpretation

Type interpretations are the same as type realisations (see Section 5.6), but they have a wider application in EML than type realisations have in the semantics of SML, therefore the different name. A type interpretation TI provides a way of translating (semantic) types, for example to interpret ?-types or to translate between a concrete and an abstract type. Given a type interpretation TI, we define a function TI^{#} between types as follows:

TI^{#}(τ) = τ{TI(t^{(k)})/t^{(k)} ; t^{(k)} ∈ Dom TI}

For the notation, see Section 4.4. We shall also apply TI^{#} to other semantic objects, meaning the simultaneous application of TI^{#} to all components.

A state s contains a type interpretation TI and a type realisation φ_{Ty}. The purpose of TI is to interpret question mark types, i.e. to replace type names that were chosen during static analysis for unknown types by their replacement in the given model. φ_{Ty} is the type realisation for abstract types in signatures. We abbreviate (TI of s)^{#} as s^{#} and (φ_{Ty} of s)^{#} ∘ s^{#} as s^{##}.

Static information stored in traces is typically model-independent, having been obtained from the static analysis of phrases. When interpreting this information in a given model we have to replace type names generated by question mark type bindings (rule 28.1) by the concrete types the model provides. This explains the frequent use of s^{#} in the rules. With s^{##} we can access the underlying structure of a type, i.e. how it is “implemented”; we use this for quantification and comparison of values.

8.6 Fresh Type Names

The static semantics ensures that the type names chosen for two different datatype definitions are different whenever these types “exist” at the same point in a program. For the purposes of verification this insurance is not secure enough, because the earlier described Comp functions tears down all scope barriers. To deal with that properly we rename type names in a certain way. For this purpose we employ a function Fresh : TyNameSet × State → TyRea which is specified as follows: let Fresh(T, s) = φ_{Ty} then the following properties hold:

• φ_{Ty} is injective and φ_{Ty}^{−1} ∈ TyRea

• Supp(φ_{Ty}) = T

• Yield(φ_{Ty}) ∩ tynames(s) = ∅.

8.7 Projections to Dynamic and Static Semantics

The notion of value is slightly different from that in the dynamic semantics because models are part of closures. We define a family of functions Dyn mapping semantic objects of the verification semantics to the corresponding semantic objects of the dynamic semantics having the same name, as follows:

π_{i}(x_{1}, ···, x_{i}, ···, x_{n}) = x_{i}
Dyn(SE, TE, VE) = (Dyn SE, Dyn VE)
Dyn VE = Dyn ∘ VE
Dyn SE = Dyn ∘ π_{1} ∘ SE
Dyn(∀α^{(k)}.(v, τ)) = Dyn v
Dyn v = v, v ∈ SVal ⊎ BasVal ⊎ Con ⊎ ExName
Dyn(v, v′) = (v, Dyn v′), v ∈ Con ⊎ ExName
Dyn r = Dyn ∘ r
Dyn[e] = [Dyn e]
Dyn(match, M, VE) = (Replace(match, QI of M, 0), Dyn M, Dyn VE)
Dyn M = Dyn(FE of M)
Dyn FE = Dyn(E of FE)
Dyn s = (⊤, ens of s)

The function Replace is used to replace question marks in closure values. It is assumed here that the question mark interpretation in a closure always indexes its occurrences of ? from 0. The function Rec is extended to variable environments of the verification semantics in the obvious way, i.e. it unrolls closure values analogously as in the dynamic semantics (without changing any types).

We define another family of functions Stat, mapping objects of the verification semantics to corresponding objects in the static semantics. It is defined as follows:

Stat(SE, TE, VE) = (Stat SE, TE, Stat VE)
Stat VE = Stat ∘ VE
Stat(∀α^{(k)}.(v, τ)) = ∀α^{(k)}.τ
Stat SE = {strid ↦ (m, Stat E) ; SE(strid) = (E, m)}

8.8 Relationship to Dynamic Semantics

If any expression exp^{•} evaluates in the dynamic semantics to a value or packet, i.e. s_{DYN}, E_{DYN} ⊢_{DYN} exp^{•} ⇒ v_{DYN}/p_{DYN}, s′_{DYN} without changing the flag, i.e. sp of s_{DYN} = sp of s′_{DYN} = ⊤, then for any s such that s_{DYN} = Dyn s and for any M such that E_{DYN} = Dyn M we also have s, M ⊢ exp^{•} ⇒ v/p, s′ such that Dyn(v/p) = v_{DYN}/p_{DYN} and Dyn s′ = s′_{DYN}, provided the trace γ of M is wellformed for exp.

Dynamic and verification semantics differ on expressions only when the dynamic semantics sets the sp component to ⊥. Even in that case, the differences are not substantial. In particular, any non-terminating evaluation in the dynamic semantics corresponds to non-termination in the verification semantics.

This close relationship between verification semantics and dynamic semantics is due to the fact that the rules differ significantly only in places where either the sp component of the state in the dynamic semantics is set to ⊥, or where packets (in particular [NoCode]) are treated that do not occur in the corresponding place in the verification semantics. The packet [NoCode] cannot be handled: NoCode is a basic exception name not associated with any identifier, see Section 6.5, and furthermore it cannot be matched by a variable pattern in a handler, see rules 120–121.1 of the dynamic semantics. The dynamic semantics provides only one place to capture [NoCode]: rule 135.1, for value declarations. This means that the dynamic semantics can ignore NoCode, provided it ignores the declaration that raises it, since using an identifier bound to Incomplete raises NoCode again, rule 104.1.

The evaluation of an expression containing a question mark, when it yields a value, can differ from its corresponding verification; this is the case when the question mark interpretation maps a ? occurrence to an expression which raises an exception. Whenever the verification semantics makes reference to the dynamic semantics, it is with a phrase that does not contain question marks.

One possible result when verificating exp^{•} terminates is the packet [Abuse], see rule 216. In this case the evaluation of exp^{•} terminated successfully, but sp was set to ⊥. Thus successful evaluation does not guarantee successful verification — the packet [Abuse] indicates that we have not obtained reliable information about the termination of the verification of exp^{•}.

8.9 Sentences of Static and Dynamic Semantics

Another difference between dynamic and verification semantics is that the latter makes explicit use of the results of the static semantics; in particular it typechecks certain expressions using contexts produced in the course of static analysis.

These contexts are explicitly provided by the γ component of a model. The reader may observe that traces are decomposed in the verification semantics in the same way as they are composed in the static semantics.

To distinguish sentences of the static and dynamic semantics from those of the verification semantics, we supply the ⊢ with an appropriate subscript in the former case, that is ⊢_{STAT} or ⊢_{DYN}, respectively.

8.10 Inference Rules

The semantic rules allow sentences of the form s, A ⊢ phrase ⇒ A′, s′ to be inferred, where A is usually a model, A′ is some semantic object and s, s′ are the states before and after verification represented by the sentence. Additionally, we have two other forms of sentences, equality sentences s, FE, γ ⊢ exp_{1}^{•} ≡ exp_{2}^{•} ⇒ v, comparison sentences C, τ, E_{DYN} ⊢ (s_{DYN}^{1}, v_{DYN}^{1}) ≈ (s_{DYN}^{2}, v_{DYN}^{2}) ⇒ v and approximation sentences C, τ, E_{DYN} ⊢ (s_{DYN}^{1}, v_{DYN}^{1}) ⊑ (s_{DYN}^{2}, v_{DYN}^{2}) ⇒ v. Beside these sentences, we allow other hypotheses as in the dynamic semantics, including hypotheses in the form of sentences of the static or dynamic semantics as explained in Section 8.9. All these other hypotheses have the status of side-conditions; this includes higher-order rules.

In most rules the states s and s′ are omitted from sentences. The state and exception convention are adopted as in the dynamic semantics for the Core, except that “state” refers there to a different semantic object.

The exception convention does not apply to rules 210–218 (those for the equality predicate ==, quantifiers, terminates and the exception handler) nor to rules 224–231 (equality and comparison rules).

Atomic Expressions  M ⊢ atexp ⇒ v/p

M ⊢ scon ⇒ val(scon)

(194)

\frac{FE(longvar) ≻ (v, s^{#}(τ))  \frac{FE(longvar) ≻ (v′, s^{#}(τ))}{∃ϑ. ϑ(v) = v′ ∧ Dom ϑ ∩ tyvars FE = ∅}}{s, (FE, τ) ⊢ longvar ⇒ v, s}  (195)

\frac{M(longcon) ≻ (con, τ)}{M ⊢ longcon ⇒ con}  (196)

\frac{M(longexcon) = (en, τ)}{M ⊢ longexcon ⇒ en}  (197)

\frac{⟨(FE, γ) ⊢ exprow ⇒ r⟩}{(FE, ϵ⟨·γ⟩) ⊢ \{ ⟨exprow⟩ \} ⇒ \{\}⟨+ r⟩ in Val}  (198)

\frac{(FE, γ) ⊢ dec ⇒ E′ (FE + E′, γ′) ⊢ exp ⇒ v}{(FE, γ · γ′) ⊢ let dec in exp end ⇒ v}  (199)

\frac{M ⊢ exp ⇒ v}{M ⊢ ( exp ) ⇒ v}  (200)

\frac{n = n of s (QIE of FE)(n) = exp^{•} s^{#}(C) ⊢_{STAT} exp^{•} ⇒ τ′, ∅, γ  s^{#}(τ) = τ′ s ⊕ (n + 1), (FE, γ) ⊢ exp^{•} ⇒ v, s′}{s, (FE, (C, τ)) ⊢ ? ⇒ v, s′}  (201)

Comments:

(195) Types in verification environments have already been interpreted with an appropriate type interpretation TI, but τ, which comes from the elaboration, has not been so interpreted.

Applying a type substitution to a value has an effect only if the value contains closures and the closures contain free type variables in the domain of the type substitution. The type substitution is typically determined by s^{#}(τ), but one can construct pathological examples for which this is not true. The side-condition excludes such a choice to keep verification deterministic.

The value Incomplete does not appear in the verification semantics; therefore we have no rule corresponding to 104.1 (same for rules 135.1, 136.1, 148.1, 150.1, 151.1 and 152.1).

(201) The model substitutes each occurrence of ? by a fixed expression, preferably of the appropriate type. The type is appropriate if it is equal to the type of ? after taking the interpretation of types into consideration. We do not get appropriateness of types for free, thus the side-condition s^{#}(τ) = τ′ which excludes unwanted models.

By using an expression rather than a value we implicitly use a kind of secondorder substitution, because the value of this expression depends on the context. In fact each ? in an expression can roughly be seen as an abbreviation for ?(x_{1}, ..., x_{n}) where the x_{i} are the variables bound by the context in which ? occurs. Here, ? could indeed be replaced by a value, a n-ary function.

Notice that there is a subtle problem with the type of exp^{•}. We require that exp^{•} has exactly the same type as the particular occurrence of ?; otherwise the rule is not applicable. In practice, this means that ? almost always has to be qualified by its intended type. The reason for requiring equality of types rather than allowing instances is type safety, i.e. we may have used an instance (or even different instances) of a polymorphic object that was defined using ?. Since such instances only may be in conflict with the type of exp^{•}, this is not necessarily harmful, but the alternative to the rule given would be to make the static context dependent on the model’s choice for question marks, and hence to have a separate static semantics for each model.

Expression Rows  M ⊢ exprow ⇒ r/p
\frac{(FE, γ) ⊢ exp ⇒ v ⟨(FE, γ′) ⊢ exprow ⇒ r⟩}{(FE, γ⟨·γ′⟩) ⊢ lab = exp ⟨ , exprow⟩ ⇒ \{lab ↦ v\}⟨+ r⟩}  (202)

Expressions  M ⊢ exp ⇒ v/p
\frac{M ⊢ atexp ⇒ v}{M ⊢ atexp ⇒ v}  (203)

\frac{(FE, γ) ⊢ exp ⇒ con  (FE, γ′) ⊢ atexp ⇒ v}{(FE, γ · γ′) ⊢ exp atexp ⇒ (con, v)}  (204)

\frac{(FE, γ) ⊢ exp ⇒ en (FE, γ′) ⊢ atexp ⇒ v}{(FE, γ · γ′) ⊢ exp atexp ⇒ (en, v)}  (205)

\frac{(FE, γ) ⊢ exp ⇒ b (FE, γ′) ⊢ atexp ⇒ v APPLY(b, Dyn v) = v′/p}{(FE, γ · γ′) ⊢ exp atexp ⇒ v′/p} (206)

\frac{s_{1}, (FE, γ) ⊢ exp ⇒ (match, M, VE), s_{2} s_{2}, (FE, γ′) ⊢ atexp ⇒ v, s_{3} s_{3} ⊕ 0, M + Rec VE, v ⊢ match ⇒ v′, s_{4}}{s_{1}, (FE, γ · γ′) ⊢ exp atexp ⇒ v′, s_{4} ⊕ (n of s_{3})} (207)

\frac{s_{1}, (FE, γ) ⊢ exp ⇒ (match, M, VE), s_{2} s_{2}, (FE, γ′) ⊢ atexp ⇒ v, s_{3} s_{3} ⊕ 0, M + Rec VE, v ⊢ match ⇒ FAIL, s_{4}}{s_{1}, (FE, γ · γ′) ⊢ exp atexp ⇒ [Match], s_{4} ⊕ (n of s_{3})} (208)

\frac{M ⊢ exp ⇒ v}{M ⊢ exp : ty ⇒ v}  (209)

\frac{\frac{γ ≻ γ′ = (C, τ) · γ′′}{s, FE, γ′ ⊢ exp_{1}^{•} ≡ exp_{2}^{•} ⇒ v}}{s, (FE, γ) ⊢ exp_{1}^{•} == exp_{2}^{•} ⇒ v, s}  (210)

Comments:

(206) The reason for the application of “Dyn” is that the function APPLY operates on dynamic values and not verification values. This is largely irrelevant, because most basic values only operate on numbers and strings which are in both value classes. One exception though is the polymorphic equality =.

(207),(208) To verificate match we have to reset the nofs component to 0, because the question mark interpretation in M indexes occurrences of question marks starting from 0; see also rule 223 and the definition of Dyn. Similarly, the n of s component of the final state is taken from s_{3}, because match is not a subphrase of exp atexp.

(209) The type expression ty is ignored. The type it describes may not be “accurate” (in an intuitive sense) anyway, because the explicit type variables in exp are subject to abstraction and instantiation. If we needed to obtain type information from ty here, we would have to extend the environment by a type variable environment, mapping type variables to types. But this is fortunately unnecessary since type information (coming from the static semantics) is provided by traces, see rule 347.

(210) Equality is type dependent. However, the premise requires that it is not dependent on the instantiation of type variables local to the expression — all instances should give the same result. Note that the state does not change, even if exp_{1} and/or exp_{2} change the state.

\frac{( \frac{Comp(FE, s) = VE  γ ≻ γ_{1} = (C, τ) · γ_{2}  s^{##}(τ) = τ′}{s^{##}(C) + Stat VE ⊢_{STAT} atexp^{•} ⇒ τ′, ∅, γ_{3} ∧ Dyn(s, FE + VE) ⊢_{DYN} atexp^{•} ⇒ v_{DYN}, (⊤, ens) ∧ s, (FE + VE, γ_{1} · γ_{3}) ⊢ (fn match^{•}) atexp^{•} ⇒ true, s′} )}{s, (FE, γ) ⊢ exists match^{•} ⇒ true, s}  (211)

\frac{Comp(FE, s) = VE_{\frac{( \begin{matrix}γ ≻ γ_{1} = (C, τ) · γ_{2} s^{##}(C) + Stat VE ⊢_{STAT} atexp^{•} ⇒ τ′, ∅, γ_{3} \\ s^{##}(τ) = τ′ Dyn(s, F E + V E) ⊢_{DYN} atexp^{•} ⇒ v_{DYN}, (⊤, ens) \end{matrix} )}{∃s′. s, (F E + V E, γ_{1} · γ_{3}) ⊢ (fn match^{•}) atexp^{•} ⇒ false, s′}}}{s, (FE, γ) ⊢ exists match^{•} ⇒ false, s}  (212)

\frac{Comp(FE, s) = VE_{\frac{( \begin{matrix}γ ≻ γ_{1} = (C, τ) · γ_{2} s^{##}(C) + Stat VE ⊢_{STAT} atexp^{•} ⇒ τ′, ∅, γ_{3} \\ s^{##}(τ) = τ′ Dyn(s, F E + V E) ⊢_{DYN} atexp^{•} ⇒ v_{DYN}, (⊤, ens) \end{matrix} )}{∃s′. s, (F E + V E, γ_{1} · γ_{3}) ⊢ (fn match^{•}) atexp^{•} ⇒ true, s′}}}{s, (FE, γ) ⊢ forall match^{•} ⇒ true, s}  (213)

\frac{( \frac{Comp(FE, s) = VE  γ ≻ γ_{1} = (C, τ) · γ_{2}  s^{##}(τ) = τ′}{s^{##}(C) + Stat VE ⊢_{STAT} atexp^{•} ⇒ τ′, ∅, γ_{3} ∧ Dyn(s, FE + VE) ⊢_{DYN} atexp^{•} ⇒ v_{DYN}, (⊤, ens) ∧ s, (FE + VE, γ_{1} · γ_{3}) ⊢ (fn match^{•}) atexp^{•} ⇒ false, s′} )}{s, (FE, γ) ⊢ forall match^{•} ⇒ false, s}  (214)

Comments:

(211)–(214) Verification of a quantified expression does not change the state. All state changes that happen during its verification are recovered. The purpose of Comp(FE, s) is to complete the environment to make all values accessible by syntactic means. In other words: quantification ranges over all expressible values, including even all values of abstract types in signatures, and not just over those values that are expressible at the particular point in the program where the quantified expression occurs.

Quantification ranges only over defined values (no packets), therefore the required evaluation to a value.

The premises of these rules contain a rule themselves, i.e. these are higherorder rules.

(211),(214) The premise requires a witness for each type instance. This is not the same as requiring a witness for the most general type, because the body of the quantifier may be type-dependent; typically this situation occurs when quantifiers are nested.

Notice that the quantifier rules are not complete in the sense that a quantified expression does not necessarily verificate to either true or false. The “missing case” occurs when we are not able to provide a witness for truth of an existentially quantified formula (resp. falsity of a universally quantified formula) which is as polymorphic as the match, but the existentially quantified formula is not false (resp. the universally quantified formula is not true) because on some values given by atexp^{•} the body of the formula does not verificate to true (resp. false) because it either verificates to false (resp. true), or raises an exception, or does not terminate. An important consequence of this is that a polymorphically quantified formula is taken to be undefined if it is true for type instances and false for others.

\frac{Dyn(s, M) ⊢_{DYN} exp^{•} ⇒ v_{DYN}/p_{DYN}, (⊤, ens)}{s, M ⊢ exp^{•} terminates ⇒ true, s}  (215)

\frac{Dyn(s, M) ⊢_{DYN} exp^{•} ⇒ v_{DYN}/p_{DYN}, (⊥, ens)}{s, M ⊢ exp^{•} terminates ⇒ [Abuse], s}  (216)

\frac{s_{DYN}, E_{DYN} = Dyn(s, M) ¬∃v_{DYN}/p_{DYN}, s′_{DYN}. s_{DYN}, E_{DYN} ⊢_{DYN} exp^{•} ⇒ v_{DYN}/p_{DYN}, s′_{DYN}}{s, M ⊢ exp^{•} terminates ⇒ false, s}  (217)

Comments:

(215) Raising an exception is treated as a terminating case.

Notice that the flag sp of the dynamic state must stay ⊤ to make the convergence predicate true. As any specification construct sets the flag to ⊥, no such construct can occur during an evaluation that does not change the flag.

(216) If an evaluation terminates in the dynamic semantics but the flag sp is set to ⊥, then the verification semantics might or might not derive a semantic value for the same evaluation. The packet [Abuse] indicates an abuse of the convergence predicate — it is not intended to be used for expressions containing specification constructs.

(217) The convergence predicate is verificated using the dynamic semantics. This is necessary to avoid paradoxes caused by the non-existence premise of this rule.

\frac{(FE, γ) ⊢ exp ⇒ v}{(FE, γ · γ′) ⊢ exp handle match ⇒ v}  (218)

Comments:

(210)–(218) These rules are exempted from the exception convention.

\frac{(FE, γ) ⊢ exp ⇒ [e] e ≠ Abuse (FE, γ′), e ⊢ match ⇒ v}{(FE, γ · γ′) ⊢ exp handle match ⇒ v}  (219)

\frac{(FE, γ) ⊢ exp ⇒ [e] e ≠ Abuse (FE, γ′), e ⊢ match ⇒ FAIL}{(FE, γ · γ′) ⊢ exp handle match ⇒ [e]}  (220)

\frac{(FE, γ) ⊢ exp ⇒ [Abuse]}{(FE, γ · γ′) ⊢ exp handle match ⇒ [Abuse]}  (221)

Comments:

(219)–(221) The exception Abuse is treated specially, similarly to NoCode in the dynamic semantics. We do not need special treatment for NoCode here, because it is never raised in the verification semantics.

\frac{(FE, γ) ⊢ exp ⇒ e}{(FE, τ · γ) ⊢ raise exp ⇒ [e]}  (222)

\frac{n = n of s M = ((E, (QIE, QIT)), (C, τ) · γ) (match′, n′) = Replace(match, (QIE, QIT), n) s^{#}(C) ⊢_{STAT} match′ ⇒ τ′, U, γ′ s^{#}(τ) = τ′ f = λk.k − n QIE′ = QIE ∘ f  QIT′ = QIT ∘ f M′ = ((E, (QIE′, QIT′)), γ)}{s, M ⊢ fn match ⇒ (match, M′, \{\}), s ⊕ n′}  (223)

Comments:

(223) The purpose of substituting all question marks in the premise is to avoid any ill-typed interpretations for the question marks when the closure is applied to an argument. The so-obtained phrase match′ is not used for the closure for technical reasons (traces and type interpretations are not quite right). The difference between n′ and n is the number of question marks occurring in match. When verificating a closure, we have to know at which number the labelling of question marks starts. The composition of the question mark interpretations with f makes it start from 0; this convention is used for closure application (rules 207 and 208) and for mapping verification values to dynamic values in the definition of Dyn. The set of unguarded type variables U in match′ is left unspecified. If we wanted to consider QIE as textual substitution, we would need that all type variables in U are free in the context C.

Equality  s, FE, γ ⊢ exp_{1} ≡ exp_{2} ⇒ v

\frac{Dyn(s, FE) ⊢_{DYN} exp_{1} ⇒ v_{DYN}^{1}, s_{DYN}^{1} sp of s_{DYN}^{1} = ⊤ Dyn(s, FE) ⊢_{DYN} exp_{2} ⇒ v_{DYN}^{2}, s_{DYN}^{2} sp of s_{DYN}^{2} = ⊤ VE = Comp(FE, s) C′ = C + Stat VE  E_{DYN} = Dyn(FE + VE) C′, s^{##}(τ), E_{DYN} ⊢ (s_{DYN}^{1}, v_{DYN}^{1}) ≈ (s_{DYN}^{2}, v_{DYN}^{2}) ⇒ v}{s, FE, (C, τ) · γ_{1} · γ_{2} ⊢ exp_{1} ≡ exp_{2} ⇒ v} (224)

\frac{Dyn(s, FE) ⊢_{DYN} exp_{1} ⇒ [e_{DYN}^{1}], s_{DYN}^{1} sp of s_{DYN}^{1} = ⊤ Dyn(s, FE) ⊢_{DYN} exp_{2} ⇒ [e_{DYN}^{2}], s_{DYN}^{2} sp of s_{DYN}^{2} = ⊤ VE = Comp(FE, s) C′ = C + Stat VE  E_{DYN} = Dyn(FE + VE) C′, exn, E_{DYN} ⊢ (s_{DYN}^{1}, e_{DYN}^{1}) ≈ (s_{DYN}^{2}, e_{DYN}^{2}) ⇒ v}{s, FE, (C, τ) · γ_{1} · γ_{2} ⊢ exp_{1} ≡ exp_{2} ⇒ v} (225)

\frac{Dyn(s, FE) ⊢_{DYN} exp_{1} ⇒ v_{DYN}, s_{DYN}^{1} sp of s_{DYN}^{1} = ⊤ Dyn(s, FE) ⊢_{DYN} exp_{2} ⇒ [e_{DYN}], s_{DYN}^{2} sp of s_{DYN}^{2} = ⊤}{s, FE, (C, τ) · γ_{1} · γ_{2} ⊢ exp_{1} ≡ exp_{2} ⇒ false}  (226)

\frac{Dyn(s, FE) ⊢_{DYN} exp_{1} ⇒ [e_{DYN}], s_{DYN}^{1} sp of s_{DYN}^{1} = ⊤ Dyn(s, FE) ⊢_{DYN} exp_{2} ⇒ v_{DYN}, s_{DYN}^{2} sp of s_{DYN}^{2} = ⊤}{s, FE, (C, τ) · γ_{1} · γ_{2} ⊢ exp_{1} ≡ exp_{2} ⇒ false}  (227)

\frac{s, (FE, γ_{1}) ⊢ exp_{1} terminates ⇒ false, s s, (FE, γ_{2}) ⊢ exp_{2} terminates ⇒ false, s}{s, FE, (C, τ) · γ_{1} · γ_{2} ⊢ exp_{1} ≡ exp_{2} ⇒ true}  (228)

\frac{Dyn(s, FE) ⊢_{DYN} exp_{1} ⇒ v_{DYN}/p_{DYN}, s_{DYN}^{1} sp of s_{DYN}^{1} = ⊤ s, (FE, γ_{2}) ⊢ exp_{2} terminates ⇒ false, s}{s, FE, (C, τ) · γ_{1} · γ_{2} ⊢ exp_{1} ≡ exp_{2} ⇒ false}  (229)

\frac{s, (FE, γ_{1}) ⊢ exp_{1} terminates ⇒ false, s Dyn(s, FE) ⊢_{DYN} exp_{2} ⇒ v_{DYN}/p_{DYN}, s_{DYN}^{2} sp of s_{DYN}^{2} = ⊤}{s, FE, (C, τ) · γ_{1} · γ_{2} ⊢ exp_{1} ≡ exp_{2} ⇒ false}  (230)

Comments:

(224),(225) The last sentence in the premise of both rules refers to the comparison rules (for comparing values), 232 to 231.

(225) The type τ is arbitrary (and does not contribute to the result) when comparing packets, because raising an exception gives an arbitrary type.

(228)–(230) Notice that the sentence s, M ⊢ exp terminates ⇒ false, s (see the premises of these rules) ensures that exp has no semantic value, i.e. the rules do not overlap. This is guaranteed by the rules for the convergence predicate, see rule 217.

The predicate ≡ is a partial congruence relation. It is partial because it is undefined if the evaluation of exp_{1} or exp_{2} involves specification constructs.

Comparisons  C, τ, E_{DYN} ⊢ (s_{DYN}^{1}, v_{DYN}^{1}) ≈ (s_{DYN}^{2}, v_{DYN}^{2}) ⇒ v

\frac{C, τ, E_{DYN} ⊢ (s_{DYN}^{1}, v_{DYN}^{1}) ⊑ (s_{DYN}^{2}, v_{DYN}^{2}) ⇒ true C, τ, E_{DYN} ⊢ (s_{DYN}^{2}, v_{DYN}^{2}) ⊑ (s_{DYN}^{1}, v_{DYN}^{1}) ⇒ true}{C, τ, E_{DYN} ⊢ (s_{DYN}^{1}, v_{DYN}^{1}) ≈ (s_{DYN}^{2}, v_{DYN}^{2}) ⇒ true}  (231)

\frac{C, τ, E_{DYN} ⊢ (s_{DYN}^{1}, v_{DYN}^{1}) ⊑ (s_{DYN}^{2}, v_{DYN}^{2}) ⇒ false}{C, τ, E_{DYN} ⊢ (s_{DYN}^{1}, v_{DYN}^{1}) ≈ (s_{DYN}^{2}, v_{DYN}^{2}) ⇒ false}  (232)

\frac{C, τ, E_{DYN} ⊢ (s_{DYN}^{2}, v_{DYN}^{2}) ⊑ (s_{DYN}^{1}, v_{DYN}^{1}) ⇒ false}{C, τ, E_{DYN} ⊢ (s_{DYN}^{1}, v_{DYN}^{1}) ≈ (s_{DYN}^{2}, v_{DYN}^{2}) ⇒ false}  (233)

Approximations C, τ, E_{DYN} ⊢ (s_{DYN}^{1}, v_{DYN}^{1}) ⊑ (s_{DYN}^{2}, v_{DYN}^{2}) ⇒ v

\frac{id ∉ Dom(VE of C) C + \{id ↦ τ\} ⊢_{STAT} exp ⇒ \{\}, ∅, γ s_{DYN}^{1}, E_{DYN} + \{id ↦ v_{DYN}^{1}\} ⊢_{DYN} exp ⇒ \{\}, s_{DYN} sp of s_{DYN} = ⊤ ¬∃s′_{DYN}. (s_{DYN}^{2}, E_{DYN} + \{id ↦ v_{DYN}^{2}\} ⊢_{DYN} exp ⇒ \{\}, s′_{DYN} sp of s′_{DYN} = ⊤)}{C, τ, E_{DYN} ⊢ (s_{DYN}^{1}, v_{DYN}^{1}) ⊑ (s_{DYN}^{2}, v_{DYN}^{2}) ⇒ false}

(234)

\frac{( \frac{id ∉ Dom(VE of C)  C + \{id ↦ τ\} ⊢_{STAT} exp ⇒ \{\}, ∅, γ s_{DYN}^{1}, E_{DYN} + \{id ↦ v_{DYN}^{1}\} ⊢_{DYN} exp ⇒ \{\}, s_{DYN}  sp of s_{DYN} = ⊤}{∃s′_{DYN}. (s_{DYN}^{2}, E_{DYN} + \{id ↦ v_{DYN}^{2}\} ⊢_{DYN} exp ⇒ \{\}, s′_{DYN}  sp of s′_{DYN} = ⊤)} )}{C, τ, E_{DYN} ⊢ (s_{DYN}^{1}, v_{DYN}^{1}) ⊑ (s_{DYN}^{2}, v_{DYN}^{2}) ⇒ true} (235)

Comments:

(234),(235) The exp is an arbitrary expression of type {}, the empty record type. This type contains only one value, the empty map {}. We only compare the termination behaviour of exp.

(224)–(235) The exception convention does not apply to these rules.

Matches  M, v ⊢ match ⇒ v′/p/FAIL

\frac{(FE, γ), v ⊢ mrule ⇒ v′}{(FE, γ⟨·γ′⟩), v ⊢ mrule ⟨ | match⟩ ⇒ v′}  (236)

\frac{M, v ⊢ mrule ⇒ FAIL}{M, v ⊢ mrule ⇒ FAIL}  (237)

\frac{(FE, γ), v ⊢ mrule ⇒ FAIL (FE, γ′), v ⊢ match ⇒ v′/FAIL}{(FE, γ · γ′), v ⊢ mrule | match ⇒ v′/FAIL}  (238)

Match Rules  M, v ⊢ mrule ⇒ v′/p/FAIL

\frac{(FE, γ), v ⊢ pat ⇒ VE  (FE + VE, γ′) ⊢ exp ⇒ v′}{(FE, γ · γ′), v ⊢ pat => exp ⇒ v′}  (239)

\frac{(FE, γ), v ⊢ pat ⇒ FAIL}{(FE, γ · γ′), v ⊢ pat => exp ⇒ FAIL}  (240)

Declarations  M ⊢ dec ⇒ E/p

\frac{γ ∉ TraceScheme α^{(k)} ∩ tyvars(FE) = ∅ (FE, γ) ⊢ valbind ⇒ VE  VE′ = Clos_{FE}VE}{(FE, ∀α^{(k)}.γ) ⊢ val valbind ⇒ VE′ in Env}  (241)

\frac{s_{1}, (FE, γ) ⊢ typbind ⇒ \{\}, s_{2}}{s_{1}, (FE, TE · γ) ⊢ type typbind ⇒ s_{2}^{#}(TE) in Env, s_{2}}  (242)

\frac{s_{1}, (FE, γ) ⊢ typbind ⇒ \{\}, s_{2}}{s_{1}, (FE, TE · γ) ⊢ eqtype typbind ⇒ s_{2}^{#}(TE) in Env, s_{2}}  (243)

\frac{TI = Fresh(Tnames(TE of E_{STAT}), s) s_{1} = s + TI CT = s_{1}^{#}(Graph(VE of E_{STAT})) s_{1}, (FE, γ) ⊢ datbind ⇒ VE, s_{1}}{s, (FE, E_{STAT} · γ) ⊢ datatype datbind ⇒ s_{1}^{#}(VE, TE of E_{STAT}) in Env, s_{1} + CT}  (244)

\frac{TI_{1} = Fresh(Tnames(TE of E_{STAT}), s) s_{1} = s + TI_{1} CT = s_{1}^{#}(Graph(VE of E_{STAT})) s_{1}, (FE, γ) ⊢ datbind ⇒ VE, s_{1} s_{1} + CT , (FE + s_{1}^{#}(VE), γ′) ⊢ dec ⇒ E, s_{2} TI_{2} = Fresh(φ_{Ty}^{−1}(Tnames(TE of E_{STAT})), s_{2}) φ′_{Ty} = TI_{1} ∘ φ_{Ty} ∘ TI_{2}^{−1} E = φ′_{Ty}(E′) tynames(E′) ∩ Yield(φ′_{Ty}) = ∅ s_{3} = s_{2} + φ′_{Ty} + TI_{2}}{s, (FE, (E_{STAT}, φ_{Ty}) · γ · γ′) ⊢ abstype datbind with dec end ⇒ E′, s_{3}} (245)

\frac{s, M ⊢ exbind ⇒ VE, s′}{s, M ⊢ exception exbind ⇒ s^{#}(VE) in Env, s′}  (246)

\frac{(FE, γ) ⊢ dec_{1} ⇒ E  (FE + E, γ′) ⊢ dec_{2} ⇒ E′}{(FE, γ · γ′) ⊢ local dec_{1} in dec_{2} end ⇒ E′}  (247)

\frac{M(longstrid_{1}) = (E_{1}, m_{1}) ··· M(longstrid_{n}) = (E_{n}, m_{n})}{s, M ⊢ open longstrid_{1} ··· longstrid_{n} ⇒ E_{1} + ··· + E_{n}, s}  (248)

\overline{M ⊢  ⇒ \{\} in Env}  (249)

\frac{(FE, γ) ⊢ dec_{1} ⇒ E  (FE + E, γ′) ⊢ dec_{2} ⇒ E′}{(FE, γ · γ′) ⊢ dec_{1} ⟨;⟩ dec_{2} ⇒ E + E′}  (250)

Comments:

(241) Dropping the quantifier is a particular way of instantiating the trace scheme ∀α^{(k)}.γ. Other instantiations might lead to different variable environments, but only in pathological cases involving type-dependent specification constructs (e.g. quantification) and type assertions with explicit type variables to prevent the specification constructs from binding these type variables.

(244),(245) Remember that Graph is the graph of a finite map and that the component CT of the state is used for comparing values and for quantification.

The state s does not change when verificating a datbind, i.e. the requirement that no state change takes place does not restrict the applicability of the rule.

(245) The type realisation φ_{Ty} maps type names of abstract types to their implementing types, see rule 20 and the definition of Abs_{C}. Because both the type names of the abstract types and their implementing types are renamed, we have to be pre- and postcompose φ_{Ty} with these renamings to obtain the corresponding realisation φ′_{Ty} that operates on the new type names. We apply it “backwards” to the environment E to obtain an environment E′ in which the implementing types (Yield(φ′_{Ty})) have been replaced by the corresponding abstract type names. Such an E′ always exists because φ′_{Ty} maps type names to type names, and it is uniquely determined because φ′_{Ty} is injective and because we require that E′ does not contain type names of the implementing types.

Value Bindings  M ⊢ valbind ⇒ VE/p

\frac{(FE, γ′) ⊢ exp ⇒ v (FE, γ), v ⊢ pat ⇒ VE ⟨(FE, γ′′) ⊢ valbind ⇒ VE′⟩}{(FE, γ · γ′⟨·γ′′⟩) ⊢ pat = exp ⟨and valbind⟩ ⇒ VE ⟨+ VE′⟩}  (251)

\frac{(FE, γ′) ⊢ exp ⇒ v (FE, γ), v ⊢ pat ⇒ FAIL}{(FE, γ · γ′⟨·γ′′⟩) ⊢ pat = exp ⟨and valbind⟩ ⇒ [Bind]}  (252)

\frac{M ⊢ valbind ⇒ VE}{M ⊢ rec valbind ⇒ Rec VE}  (253)

Comments:

(251) In a value binding, verification order differs from elaboration order. This is the reason why the first verification (exp) is done using the second trace and vice versa. Although in general a difference between verification order and syntactic appearance may cause problems w.r.t. the replacement of question marks, in this particular case everything works smoothly, since question marks do not occur in patterns.

Type Bindings  M ⊢ typbind ⇒ {}
\frac{⟨(FE, γ) ⊢ typbind ⇒ \{\}⟩}{(FE, ϵ⟨·γ⟩) ⊢ tyvarseq tycon = ty ⟨and typbind⟩ ⇒ \{\}}  (254)

\frac{n = n of s (QIT of FE)(n) = ty  s^{#}(C) ⊢_{STAT} ty ⇒ τ tyvarseq = α^{(k)}  tyvars(ty) ⊆ α^{(k)} TI = \{t ↦ Λα^{(k)}.τ\} s′ = (s + TI) ⊕ (n + 1) ⟨s′, (FE, γ) ⊢ typbind ⇒ \{\}, s′′⟩}{s, (FE, (C, t)⟨·γ⟩) ⊢ tyvarseq tycon = ? ⟨and typbind⟩ ⇒ \{\}, s′⟨′⟩}  (255)

Comments:

(255) The question mark interpretation QIT maps occurrences of ? to type expressions. These type expressions can be built from the type constructors available so far, i.e. they have to elaborate at the position in the program at which the ? occurs.

Data Type Bindings  M ⊢ datbind ⇒ VE
\frac{(FE, γ) ⊢ conbind ⇒ VE  ⟨(FE, γ′) ⊢ datbind ⇒ VE′⟩}{(FE, γ⟨·γ′⟩) ⊢ tyvarseq tycon = conbind ⟨and datbind⟩ ⇒ VE ⟨+VE′⟩} (256)

Constructor Bindings  M ⊢ conbind ⇒ VE
\frac{con = idc ⟨(FE, γ) ⊢ conbind ⇒ VE⟩}{(FE, τ⟨·γ⟩) ⊢ con ⟨ | conbind⟩ ⇒ \{id ↦ Clos(con, τ)\} ⟨+ VE⟩}  (257)

\frac{con = idc ⟨(FE, γ) ⊢ conbind ⇒ VE⟩}{(FE, τ⟨·γ⟩) ⊢ con of ty ⟨ | conbind⟩ ⇒ \{id ↦ Clos(con, τ)\} ⟨+ VE⟩} (258)

Exception Bindings  M ⊢ exbind ⇒ VE

\frac{excon = ide en = min(ExName \ (ens of s)) s′ = s + (\{en\} in ExNameSet, \{(en, exn)\} in ValTemp) ⟨s′, (FE, γ) ⊢ exbind ⇒ VE, s′′ ⟩}{s, (FE, ϵ⟨·γ⟩) ⊢ excon ⟨and exbind⟩ ⇒ \{id ↦ (en, exn)\} ⟨+ VE⟩, s′⟨′⟩}  (259)

\frac{excon = ide en = min(ExName \ (ens of s)) τ′ = s^{#}(τ) → exn s′ = s + (\{en\} in ExNameSet, \{(en, τ′)\} in ValTemp) ⟨s′, (FE, γ) ⊢ exbind ⇒ VE, s′′ ⟩}{s, (FE, τ⟨·γ⟩) ⊢ excon of ty ⟨and exbind⟩ ⇒ \{id ↦ (en, τ′)\} ⟨+ VE⟩, s′⟨′⟩} (260)

\frac{excon = ide FE(longexcon) = (en, τ) ⟨(FE, γ) ⊢ exbind ⇒ VE⟩}{(FE, ϵ⟨·γ⟩) ⊢ excon = longexcon ⟨and exbind⟩ ⇒ \{id ↦ (en, τ)\}⟨+ VE⟩} (261)

Comments: (259),(260) The use of min ensures that excon is uniquely determined.

Atomic Patterns  M, v ⊢ atpat ⇒ VE/FAIL
\overline{M, v ⊢ ⇒ \{\}}  (262)
\frac{v = val(scon)}{M, v ⊢ scon ⇒ \{\}}  (263)
\frac{v ≠ val(scon)}{M, v ⊢ scon ⇒ FAIL}  (264)
\frac{var = idv}{s, (FE, τ), v ⊢ var ⇒ \{id ↦ (v, s^{#}(τ))\}, s}  (265)
\frac{M(longcon) ≻ (con, τ) v = con}{M, v ⊢ longcon ⇒ \{\}}  (266)
\frac{M(longcon) ≻ (con, τ) v ≠ con}{M, v ⊢ longcon ⇒ FAIL}  (267)
\frac{M(longexcon) = (v, τ)}{M, v ⊢ longexcon ⇒ \{\}}  (268)
\frac{M(longexcon) = (v′, τ) v′ ≠ v}{M, v ⊢ longexcon ⇒ FAIL}  (269)
\frac{v = \{\}⟨+r⟩ in Val ⟨(FE, γ), r ⊢ patrow ⇒ VE/FAIL⟩}{(FE, ϵ⟨·γ⟩), v ⊢ \{ ⟨patrow⟩ \} ⇒ \{\}⟨+VE/FAIL⟩}  (270)
\frac{M, v ⊢ pat ⇒ VE/FAIL}{M, v ⊢ ( pat ) ⇒ VE/FAIL}  (271)

Pattern Rows  M, r ⊢ patrow ⇒ VE/FAIL
\overline{M, r ⊢ ... ⇒ \{\}}  (272)

\frac{(FE, γ), r(lab) ⊢ pat ⇒ FAIL}{(FE, γ⟨·γ′⟩), r ⊢ lab = pat ⟨ , patrow⟩ ⇒ FAIL}  (273)

\frac{(FE, γ), r(lab) ⊢ pat ⇒ VE  ⟨(FE, γ′), r ⊢ patrow ⇒ VE′/FAIL⟩}{(FE, γ⟨·γ′⟩), r ⊢ lab = pat ⟨ , patrow⟩ ⇒ VE⟨+ VE′/FAIL⟩} (274)

Patterns  M, v ⊢ pat ⇒ VE/FAIL
\frac{M, v ⊢ atpat ⇒ VE/FAIL}{M, v ⊢ atpat ⇒ VE/FAIL}  (275)

\frac{FE(longcon) ≻ (con, τ′) v = (con, v′) (FE, γ), v′ ⊢ atpat ⇒ VE/FAIL}{(FE, τ · γ), v ⊢ longcon atpat ⇒ VE/FAIL}  (276)

\frac{M(longcon) ≻ (con, τ) v ∉ \{con\} × Val}{M, v ⊢ longcon atpat ⇒ FAIL}  (277)

\frac{M(longexcon) = (en, τ) v = (en, v′) M, v′ ⊢ atpat ⇒ VE/FAIL}{M, v ⊢ longexcon atpat ⇒ VE/FAIL}  (278)

\frac{M(longexcon) = (en, τ) v ∉ \{en\} × Val}{M, v ⊢ longexcon atpat ⇒ FAIL}  (279)

\frac{M, v ⊢ pat ⇒ VE/FAIL}{M, v ⊢ pat : ty ⇒ VE/FAIL}  (280)

\frac{(FE, γ), v ⊢ var ⇒ VE  (FE, γ′), v ⊢ pat ⇒ VE′/FAIL}{(FE, γ · γ′), v ⊢ var⟨: ty⟩ as pat ⇒ VE + VE′/FAIL}  (281)

Type Expressions and Type-expression Rows

There are no primitive sentence forms for these phrase classes; although type expressions are present in the verification semantics for the Core, they are either disregarded (e.g. rule 209) or interpreted via the static semantics (e.g. rule 255).

9 Verification Semantics for Modules

9.1 Compound Objects

The compound objects for the Modules verification semantics, extra to those for the Core verification semantics, are shown in Figure 18. For each semantic class A there is a class Set(A) = ℘(State × A); each A ∈ Set(A) is a (possibly infinite) set of pairs (s, a), s ∈ State, a ∈ A. We use the same conventions as in the verification semantics for the Core to refer to semantic objects of the static and dynamic semantics.

(B, γ, axdesc) ∈ BasicAx = Basis × Trace × AxDesc
(N, B)(I, A) ∈ ExistAx = NameSet × Basis × (Int × GenAx)
A ∈ GenAx = BasicAx ⊎ ExistAx ⊎

(GenAx × GenAx) ⊎ Bit

(IE, TE, VE_{STAT}, A) or I ∈ Int = IntEnv × TyEnv ×

VarEnv_{STAT} × GenAx

(I, m) or IS ∈ IntStr = Int × StrName
IE ∈ IntEnv = StrId →^{fin} IntStr
(N)IS or Σ ∈ Sig = NameSet × IntStr
ostrexp ∈ OptStrExp = StrExp ⊎ {?}
(strid, ostrexp, B, (N)(IS, Σ)) ∈ FunctorClosure =

StrId × OptStrExp ×

Basis × NameSet × IntStr × Sig

G ∈ SigEnv = SigId →^{fin} Sig
F ∈ FunEnv = FunId →^{fin} FunctorClosure
(N, F, G, E) or B ∈ Basis = NameSet × FunEnv × SigEnv × Env
(N, F, G, IE, E) or IB ∈ IntBasis = NameSet × FunEnv × SigEnv ×

IntEnv × Env

S ∈ Set(Str)
R ∈ Set(Rea × Str)
E ∈ Set(Env)
SE ∈ Set(StrEnv)
B ∈ Set(Basis)

Figure 18: Further Compound Semantic Objects

An interface I ∈ Int represents a “view” of a structure. Specifications will verificate to interfaces; moreover, during the verification of a specification or signature expression, structures (to which a specification may refer via “open”) are represented only by their interfaces. A signature Σ ∈ Sig has the form (N)(I, m). Signatures are similar to signatures in the static semantics, as they can be imposed on structures, requiring certain checks and determining a matching realisation, but they are also similar to interfaces in the dynamic semantics, as a signature includes a rudimentary environment with only static information.

A functor closure (strid, ostrexp, B, (N)(IS, Σ)) has four components. It contains the structure identifier strid of its argument structure and the basis B in which the functor binding appeared for the same reasons that functor closures in the dynamic semantics do. However, the rôle of the functor body ostrexp is less significant, because the semantics of a functor only depends on its interface, not on its implementation. The functor body ostrexp is only of significance for the generation of “arbitrary” structures. The last component of a functor closure corresponds to a static functor signature, the only difference being that interface structures contain more information than static structures.

To extract an interface from an environment we define the operation Inter : Env → Int as follows:

Inter(SE, TE, VE) = (IE, TE, Stat VE, ⊥)
where IE = {strid ↦ (Inter E, m) ; SE(strid) = (E, m)}

An interface structure IS is an instance of a signature Σ = (N)IS′, written Σ≥IS, if there exists a realisation φ such that φ(IS′) = IS and Supp φ ⊆ N. We write Σ≥_{φ}IS if we want to make φ explicit. This is analogous to signature instantiation in the static semantics, see section 5.9.

An interface basis IB = (N, F, G, IE, E) is derived from a basis for verificating signature expressions and specifications. An interface basis in the verification semantics contains more components than an interface basis in the dynamic semantics — the extra components are mainly for the interpretation of axioms.

The function Inter is extended to create an interface basis from a basis B as follows:

Inter(N, F, G, E) = (N, F, G, IE of (Inter E), E)

Specifications may hide components of an environment by reusing identifiers. This affects the verification of axiom specifications. We define the environment E \ I as the restriction of E to identifiers not specified in I. More precisely, given an environment E = (SE, TE, VE) and an interface I, we define the environment E \ I to be (SE′, TE′, VE′), which is the same as E except that the domains are restricted as follows:

Dom SE′ = Dom SE \ Dom(IE of I)
Dom TE′ = Dom TE \ Dom(TE of I)
Dom VE′ = Dom VE \ Dom(VE_{STAT} of I)

9.2 Generalised Axioms

A generalised axiom A ∈ GenAx is a “mobile” axiom, capable of being interpreted in different environments. Generalised axioms arise when verificating axioms in signature expressions, and checking that a structure matches a signature involves interpreting generalised axioms from the signature in the environment corresponding to the structure. The basis B in a generalised axiom (B, γ, axdesc) has the same purpose as the environment in a closure — because the axiom is mobile, it has to carry the basis of its original occurrence. The trace γ is (originally) the one obtained from the static analysis of axdesc; it is modified in the course of matching a structure against a signature, which involves applying a realisation to an interface. The interface I in a generalised axiom (N, B)(I, A) can be viewed as a kind of existential quantification: some auxiliary structure matching the signature (N)(I, m) (for an appropriate m) has to be found, which builds on components in basis B, such that A holds. A pair of generalised axioms (A_{1}, A_{2}) can be understood as their logical conjunction. The generalised axiom ⊤ is always satisfied. It serves as a default value for GenAx — for example, (VE_{STAT} in Int) stands for ({}, {}, VE_{STAT}, ⊤). The generalised axiom ⊥ is never satisfied.

9.3 Combining Interfaces

Given two interfaces I_{1} and I_{2} with I_{k} = (IE_{k}, TE_{k}, VE_{STAT}^{k}, A_{k}), we define their sequential composition I_{1} ⊕ I_{2} as follows:

I_{1} ⊕ I_{2} = (IE_{1} + IE_{2}, TE_{1} + TE_{2}, VE_{STAT}^{1} + VE_{STAT}^{2}, (A_{1}, A_{2}))

Notice that the restrictions imposed by the static semantics make sure that the combined maps have always disjoint domains.

9.4 Extracting Objects of the Static Semantics

We extend the family of functions Stat defined in Section 8.7 to semantic objects of the module semantics as follows:

Stat(N, F, G, E) = (N, Stat F, Stat ∘G, Stat E)
Stat(N, F, G, IE, E) = (N, Stat F, Stat ∘G, Stat E + (Stat ∘IE))
Stat F = {funid ↦ (N)(Stat IS, Stat Σ) ;
F (funid) = (strid, B, (N)(IS, Σ))}
Stat((N)IS) = (N) Stat IS
Stat(I, m) = (m, Stat I)
Stat(IE, TE, VE_{STAT}, A) = (Stat ∘IE, TE, VE_{STAT})

Interfaces and environments are both mapped to static environments; similarly, bases and interface bases are both mapped to static bases.

9.5 Sets

The verification of a core phrase in a given state and environment typically leads to a pair consisting of some semantic object (value, environment, etc.) and a new state. For the verification semantics for Modules we typically have sets of such pairs as verification results.

There are two major reasons for this: first, we interpret a structure binding

    structure S: SIG = T

not as a binding of the identifier S to (some restriction of) the structure T, but as the binding of S to any structure matching the signature SIG. In other words, we abstract from the concrete structure T.

The second reason is the presence of ? in core phrases. The verification semantics for the Core operates with a given interpretation of question marks. The verification semantics for Modules enumerates all question mark interpretations that lead to successful verifications and collects the results, see rule 304.

9.6 Inference Rules

There is no state convention and no exception convention for the verification semantics for Modules: states are always made explicit.

In contrast to most other parts of the semantics, we have not only sentences of the form A ⊢ phrase ⇒ A′ where phrase is a syntactic object, but also a variety of sentence forms (not involving syntax) that determine whether a given structure matches a signature.

The convention for referring to sentences of the static semantics is the same as in the Core verification semantics.

Satisfying Signatures  s, Σ ⊢ S ⇒ S′, φ

Sentences of this form can be read as: in state s, structure S successfully matches signature Σ via realisation φ, returning structure S′.

\frac{Supp φ ⊆ N  φ(IS) = (I, m) s, E ⊢ I ⇒ E′}{s, (N)IS ⊢ (E, m) ⇒ (E′, m), φ}  (282)

Restricting Environments  s, E ⊢ I ⇒ E′

In the dynamic semantics, the effect of “cutting down” an environment E to an interface I, written E ↓ I, was defined in Section 7.2. In the verification semantics the situation is a bit more difficult: an environment is not just cut down to an interface, it also has to satisfy its (generalised) axiom, and the types have to fit. We therefore express this operation formally in terms of rules.

\frac{\begin{matrix}s, SE ⊢ IE ⇒ SE′ TE ⊢ TE′ ⇒ TE′′ VE ⊢ VE_{STAT} ⇒ VE′ \\ E′ = (SE′, TE′′, VE′) s, E′ ⊢ A ⇒ \{\} \end{matrix}}{s, (SE, TE, VE) ⊢ (IE, TE′, VE_{STAT}, A) ⇒ E′}  (283)

Restricting Structure Environments  s, SE ⊢ IE ⇒ SE′
\frac{s, SE ⊢ IE ⇒ SE′ s, E ⊢ I ⇒ E′}{s, SE + \{strid ↦ (E, m)\} ⊢ IE + \{strid ↦ (I, m)\} ⇒ SE′ + \{strid ↦ (E′, m)\}}  (284)

\overline{s, SE ⊢ \{\} ⇒ \{\}}  (285)

Restricting Type Environments  TE ⊢ TE′ ⇒ TE′′
\frac{TE ⊢ TE′ ⇒ TE′′ CE = CE′ ∨ CE′ = \{\}}{TE + \{tycon ↦ (θ, CE)\} ⊢ TE′ + \{tycon ↦ (θ, CE′)\} ⇒ TE′′ + \{tycon ↦ (θ, CE′)\}}  (286)

\overline{TE ⊢ \{\} ⇒ \{\}}  (287)

Comments:

(286) Notice that the side-condition closely relates to the enrichment of type structures, see section 5.11.

Restricting Variable Environments  VE ⊢ VE_{STAT} ⇒ VE′
\frac{VE ⊢ VE_{STAT} ⇒ VE′ ∀α^{(k)}.τ ≻_{ϑ} ∀β^{(l)}.τ′}{VE + \{id ↦ ∀α^{(k)}.(v, τ)\} ⊢ VE_{STAT} + \{id ↦ ∀β^{(l)}.τ′\} ⇒ VE′ + \{id ↦ ∀β^{(l)}.(ϑ(v), τ′)\}}  (288)

\overline{VE ⊢ \{\} ⇒ \{\}}  (289)

Comments:

(288) There is a certain amount of arbitrariness in this rule, similarly as in rules 195 and 241 in the verification semantics for the Core. The arbitrariness is again in the possibility that v may contain free type variables which are not in τ, and thus not in the domain of ϑ.

Satisfying Generalised Axioms  s, E ⊢ A ⇒ {}
\frac{l of s = ⊥}{s, E ⊢ A ⇒ \{\}}  (290)
\overline{s, E ⊢ ⊤ ⇒ \{\}}  (291)

\frac{s, E ⊢ A_{1} ⇒ \{\} s, E ⊢ A_{2} ⇒ \{\}}{s, E ⊢ (A_{1}, A_{2}) ⇒ \{\}}  (292)

\frac{l of s = ⊤ s, B + E, γ ⊢ axdesc ⇒ \{\}}{s, E ⊢ (B, γ, axdesc) ⇒ \{\}}  (293)

\frac{m ∉ (N of B ∪ N) l of s = ⊤ s_{⊥}, B, (N)(I, m) ⊢ strexp^{•} ⇒ R (s′, (φ, (E′, m′))) ∈ R s′_{⊤}, E + E′ ⊢ φ(A) ⇒ \{\}}{s, E ⊢ (N, B)(I, A) ⇒ \{\}} (294)

Comments:

(290) Axioms in signatures are ignored if the flag l of the state is ⊥.

(294) Notice that the rule has two implicit existential quantifiers: we have to find some structure expression such that some environment obtained from its verification satisfies the axiom.

Validating Axiom Descriptions  s, B, γ ⊢ axdesc ⇒ {}
\frac{s, B, γ_{1} ⊢ specexp ⇒ \{\} ⟨s, B, γ_{2} ⊢ axdesc ⇒ \{\}⟩}{s, B, γ_{1}⟨·γ_{2}⟩ ⊢ specexp ⟨and axdesc⟩ ⇒ \{\}}  (295)

Validating Specification Expressions s, B, γ ⊢ specexp ⇒ {}

\frac{s, B, γ_{1} ⊢ strdec ⇒ E  \frac{(s′, E) ∈ E}{s′, B + E, γ_{2} ⊢ axexp ⇒ \{\}}}{s, B, γ_{1} · γ_{2} ⊢ let strdec in axexp end ⇒ \{\}}  (296)

Axiomatic Expressions  s, B, γ ⊢ axexp ⇒ {}

\frac{( \frac{γ ≻ γ′}{s, ((E of B, (\{\}, \{\})), γ′) ⊢ exp^{•} ⇒ true, s′} )}{s, B, γ ⊢ exp^{•} ⇒ \{\}}  (297)

Comment: An axiomatic expression exp^{•} holds if it verificates to true; hence false, non-termination, and exceptions are treated equally here. Verification of an axiomatic expression has no side-effect, i.e. any side-effect that appeared during verification disappears.

Structure Expressions  s, B, γ ⊢ strexp ⇒ S
\frac{s, B, γ ⊢ strdec ⇒ E}{s, B, m · γ ⊢ struct strdec end ⇒ \{(s′, (E, m)) | (s′, E) ∈ E\}}  (298)

\frac{B(longstrid) = S}{s, B, γ ⊢ longstrid ⇒ \{(s, S)\}}  (299)

\frac{B(funid) = (strid, ostrexp, B′, (N)(IS, Σ)) φ′ = s^{#}(φ) l of s = ⊤ φ′(IS, Σ) = (IS′, Σ′) s, B, γ ⊢ strexp ⇒ S TI = Fresh(N, s)  \frac{(s′, S) ∈ S}{∃S′, φ′′. s′, (N)IS′ ⊢ S ⇒ S′, φ′′}}{s, B, φ · γ ⊢ funid ( strexp ) ⇒ \{(s′′_{⊤}, S′) | (s′, S) ∈ S, s′_{⊥}, B′ ⊕ \{strid ↦ S\}, TI(Σ′) ⊢ strexp^{•} ⇒ R, (s′′, (φ′′, S′)) ∈ R \}}  (300)

\frac{B(funid) = (strid, strexp′, B′, (N)(IS, Σ)) φ′ = s^{#}(φ) l of s = ⊥ φ′(IS, Σ) = (IS′, Σ′) s, B, γ ⊢ strexp ⇒ S TI = Fresh(N, s)  \frac{(s′, S) ∈ S}{∃S′, φ′′. s′, (N)IS′ ⊢ S ⇒ S′, φ′′}}{s, B, φ · γ ⊢ funid ( strexp ) ⇒ \{(s′′, S′) | (s′, S) ∈ S, s′, B′ ⊕ \{strid ↦ S\}, TI(Σ′) ⊢ strexp′ ⇒ R, (s′′, (φ′′, S′)) ∈ R \}}  (301)

\frac{s, B, γ ⊢ strdec ⇒ E  \frac{(s_{1}, E) ∈ E}{∃S. s_{1}, B ⊕ E, γ′ ⊢ strexp ⇒ S}}{s, B, γ · γ′ ⊢ let strdec in strexp end ⇒ \{(s_{2}, S) | (s_{1}, E) ∈ E, s_{1}, B ⊕ E, γ′ ⊢ strexp ⇒ S, (s_{2}, S) ∈ S\}} (302)

Comments:

(300) It should be emphasised here that strexp and strexp^{•} are different metavariables; strexp^{•} is an arbitrary structure expression (not containing ?). There are no explicit restrictions concerning elaboration of strexp^{•} needed, because they are implicit in the sentence form used, see rule 303.

(301) For this rule to succeed, it is necessary that the ostrexp component of B(funid) is a proper structure expression and not a ? — this is implicit in the first equation.

Structure vs. Signature  s, B, Σ ⊢ strexp ⇒ R

Sentences of this form can be read as: in state s and basis B, the structure expression strexp verificates and matches the signature Σ in the ways specified by R. Each member (s′, (S, φ)) of R consists of the resulting state s′, the matching realisation φ, and the structure S obtained from cutting down the verification result of strexp to Σ.

\frac{Stat B ⊢_{STAT} strexp ⇒ (m, E_{STAT}), γ s_{1}, B, γ ⊢ strexp ⇒ S  \frac{(s_{2}, S) ∈ S}{∃S′, φ. s_{2}, Σ ⊢ S ⇒ S′, φ}}{s_{1}, B, Σ ⊢ strexp ⇒ \{(s_{2} + φ_{Ty}, (φ, S′)) | (s_{2}, S) ∈ S, s_{2}, Σ ⊢ S ⇒ S′, φ\}}  (303)

Comment: s_{2}+φ_{Ty} is the state obtained by extending the type realisation φ_{Ty} of s_{2} by the type part of the realisation φ. The effect of using this state instead of s_{2} is to make the implementing types known for the purposes of quantification and comparison.

Structure-level Declarations  s, B, γ ⊢ strdec ⇒ E

Notice that the semantic value of a structure declaration is an E, not an E/p.

\overline{s, (N, F, G, E), γ ⊢ dec ⇒ \{(s′, E′) | s, (E, QI), γ ⊢ dec ⇒ E′, s′\}}  (304)

s, B, γ ⊢ axiom ax ⇒ {(s, {} in Env) | s, B, γ ⊢ ax ⇒ {} } (305)

\frac{s, B, γ ⊢ strbind ⇒ SE}{s, B, γ ⊢ structure strbind ⇒ \{(s′, SE in Env) | (s′, SE) ∈ SE\}}  (306)

\frac{s, B, γ_{1} ⊢ strdec_{1} ⇒ E  \frac{(s_{1}, E) ∈ E}{∃E′. s_{1}, B ⊕ E, γ_{2} ⊢ strdec_{2} ⇒ E′}}{s, B, γ_{1} · γ_{2} ⊢ local strdec_{1} in strdec_{2} end ⇒ \{(s_{2}, E′) | (s_{1}, E) ∈ E, s_{1}, B ⊕ E, γ_{2} ⊢ strdec_{2} ⇒ E′, (s_{2}, E′) ∈ E′\}} (307)

\overline{s, B, γ ⊢ ⇒ \{(s, \{\} in Env)\}}  (308)

\frac{s, B, γ_{1} ⊢ strdec_{1} ⇒ E  \frac{(s_{1}, E) ∈ E}{∃E′. s_{1}, B ⊕ E, γ_{2} ⊢ strdec_{2} ⇒ E′}}{s, B, γ_{1} · γ_{2} ⊢ strdec_{1} ⟨;⟩ strdec_{2} ⇒ \{(s_{2}, E + E′) | (s_{1}, E) ∈ E, s_{1}, B ⊕ E, γ_{2} ⊢ strdec_{2} ⇒ E′, (s_{2}, E′) ∈ E′\}} (309)

Comments:

(304) The sentence in the set comprehension is a sentence of the verification semantics for the Core. Notice that every Core declaration (viewed here as a strdec) verificates, but it may verificate to an empty set; it may also verificate to a set with more than one element, because QI can be chosen arbitrarily. All Core verifications resulting in packets are ignored.

(305) Verification of an axiom always succeeds: if the axiom “holds”, the result is a singleton set containing the empty environment; otherwise it is the empty set. An axiom only holds if it does so for all type instances of its trace.

Axioms  s, B, γ ⊢ ax ⇒ {}

\frac{s, B, γ ⊢ axexp ⇒ \{\} ⟨s, B, γ′ ⊢ ax ⇒ \{\}⟩}{s, B, γ⟨·γ′⟩ ⊢ axexp ⟨and ax⟩ ⇒ \{\}}  (310)

Structure Bindings  s, B, γ ⊢ strbind ⇒ SE

\frac{s, B, γ ⊢ sglstrbind ⇒ SE  ⟨ \frac{(s′, SE) ∈ SE}{∃SE′. s′, B + names SE, γ′ ⊢ strbind ⇒ SE′} ⟩}{s, B, γ⟨·γ′⟩ ⊢ sglstrbind ⟨and strbind⟩ ⇒ \{(s′⟨′⟩, SE⟨+SE′⟩) | (s′, SE) ∈ SE ⟨ , s′, B + names SE, γ′ ⊢ strbind ⇒ SE′, (s′′, SE′) ∈ SE′⟩ \}} (311)

Single Structure Bindings  s, B, γ ⊢ sglstrbind ⇒ SE
\frac{s, Inter B, γ ⊢ psigexp ⇒ Σ s, B, Σ ⊢ strexp ⇒ R l of s = ⊤}{s, B, γ · γ′ ⊢ strid : psigexp = strexp ⇒ \{(s′_{⊤}, \{strid ↦ S′\}) | s_{⊥}, B, Σ ⊢ strexp^{•} ⇒ R′, (s′, (φ, S′)) ∈ R′ \}} (312)

\frac{s, Inter B, γ ⊢ psigexp ⇒ Σ s, B, Σ ⊢ strexp ⇒ R l of s = ⊥}{s, B, γ · γ′ ⊢ strid : psigexp = strexp ⇒ \{(s′, \{strid ↦ S′\}) | s, B, Σ ⊢ strexp ⇒ R′, (s′, (φ, S′)) ∈ R′ \}} (313)

\frac{s, Inter B, γ ⊢ psigexp ⇒ Σ}{s, B, γ ⊢ strid : psigexp = ? ⇒ \{(s′_{⊤}, \{strid ↦ S\}) | s_{⊥}, B, Σ ⊢ strexp^{•} ⇒ R, (s′, (φ, S)) ∈ R \}} (314)

\frac{s, B, γ ⊢ strexp ⇒ S}{s, B, γ ⊢ strid = strexp ⇒ \{(s′, \{strid ↦ S\}) | (s′, S) ∈ S\}}  (315)

Comments:

(312) The second premise implicitly requires every interpretation of strexp to match the signature Σ (see rule 303). The resulting set R is then ignored and the result is the union of all expressible sets of structures (since strexp^{•} is arbitrary) matching the signature.

Notice that the trace γ′ is thrown away, although the verification of strexp re-builds it later using the judgements of the static semantics. The reason for this arrangement is that judgements of the form s, B, Σ ⊢ strexp ⇒ R are also used for cases in which there is no trace readily available, e.g. rules 314 and 300.

(312),(313) Notice the subtle difference between both rules: rule 313 uses strexp instead of strexp^{•} in its conclusion.

Signature Expressions  s, IB, γ ⊢ sigexp ⇒ IS
\frac{s, IB, γ ⊢ spec ⇒ I}{s, IB, m · γ ⊢ sig spec end ⇒ (I, m)}  (316)

\frac{IB(sigid)≥_{φ}IS}{s, IB, φ ⊢ sigid ⇒ IS}  (317)

Principal Signatures  s, IB, γ ⊢ psigexp ⇒ Σ
\frac{N ∩ N of IB = ∅ s, IB, γ ⊢ sigexp ⇒ IS}{s, IB, (N)γ ⊢ sigexp ⇒ (N)IS}  (318)

Comments:

(318) The rôle of this rule is similar to that of rule 65. Principality of (N)IS does not have to be imposed because it is implicitly satisfied, as the derivation of s, IB, γ ⊢ sigexp ⇒ IS uses the same realisations as the corresponding derivation of B_{STAT} ⊢_{STAT} sigexp ⇒ S_{STAT}, γ when determining the principal signature for rule 65.

Signature Declarations  s, IB, γ ⊢ sigdec ⇒ G
\frac{s, IB, γ ⊢ sigbind ⇒ G}{s, IB, γ ⊢ signature sigbind ⇒ G}  (319)
\overline{s, IB, γ ⊢ ⇒ \{\}}  (320)

\frac{s, IB, γ_{1} ⊢ sigdec_{1} ⇒ G_{1} s, IB + G_{1}, γ_{2} ⊢ sigdec_{2} ⇒ G_{2}}{s, IB, γ_{1} · γ_{2} ⊢ sigdec_{1} ⟨;⟩ sigdec_{2} ⇒ G_{1} + G_{2}}  (321)

Signature Bindings  s, IB, γ ⊢ sigbind ⇒ G
\frac{s, IB, γ ⊢ psigexp ⇒ Σ ⟨s, IB, γ′ ⊢ sigbind ⇒ G⟩}{s, IB, γ⟨·γ′⟩ ⊢ sigid = psigexp ⟨and sigbind⟩ ⇒ \{sigid ↦ Σ\} ⟨+ G⟩}  (322)

Specifications  s, IB, γ ⊢ spec ⇒ I

s, IB, VE_{STAT} ⊢ val valdesc ⇒ s^{#}(VE_{STAT}) in Int

(323)

s, IB, TE ⊢ type typdesc ⇒ s^{#}(TE) in Int

(324)

s, IB, TE ⊢ eqtype typdesc ⇒ s^{#}(TE) in Int

(325)

s, IB, (TE, VE_{STAT}) in Env_{STAT} ⊢ datatype datdesc ⇒ (s^{#}(TE), s^{#}(VE_{STAT})) in Int

(326)

s, IB, VE_{STAT} in Env_{STAT} ⊢ exception exdesc ⇒ (s^{#}(VE_{STAT})) in Int

(327)

s, IB, γ ⊢ axiom axdesc ⇒ (B of IB, γ, axdesc) in Int

(328)

\frac{s, IB, γ ⊢ strdesc ⇒ IE}{s, IB, γ ⊢ structure strdesc ⇒ IE in Int}  (329)

s, IB, γ ⊢ sharing shareq ⇒ {} in Int

(330)

\frac{IB = (N, F, G, IE, E) s, IB, γ_{1} ⊢ spec_{1} ⇒ I_{1} IB′ = (N ∪ names I_{1}, F, G, IE + IE of I_{1}, E \ I_{1}) s, IB′, γ_{2} ⊢ spec_{2} ⇒ I_{2} I_{2} = (IE, TE, VE_{STAT}, A) N_{1} = names I_{2} \ names I_{1} \ N I_{3} = (IE, TE, VE_{STAT}, (N_{1}, B of IB)(I_{1}, A))}{s, IB, γ_{1} · γ_{2} ⊢ local spec_{1} in spec_{2} end ⇒ I_{3}}

(331)

\frac{IB(longstrid_{1}) = (I_{1}, m_{1}) ··· IB(longstrid_{n}) = (I_{n}, m_{n})}{s, IB, γ ⊢ open longstrid_{1} ··· longstrid_{n} ⇒ I_{1} ⊕ ··· ⊕ I_{n}}  (332)

\frac{IB(sigid_{1})≥_{φ_{1}}(I_{1}, m_{1}) ··· IB(sigid_{n})≥_{φ_{n}}(I_{n}, m_{n})}{s, IB, φ_{1} · . . . · φ_{n} ⊢ include sigid_{1} ··· sigid_{n} ⇒ I_{1} ⊕ ··· ⊕ I_{n}}  (333)
\overline{s, IB, γ ⊢ ⇒ \{\} in Int}  (334)

\frac{IB = (N, F, G, IE, E) s, IB, γ_{1} ⊢ spec_{1} ⇒ I_{1} IB′ = (N ∪ names I_{1}, F, G, IE + IE of I_{1}, E \ I_{1}) s, IB′, γ_{2} ⊢ spec_{2} ⇒ I_{2}}{s, IB, γ_{1} · γ_{2} ⊢ spec_{1} ⟨;⟩ spec_{2} ⇒ I_{1}I_{2}}

(335)

Comments:

(323)–(327) The various traces in these rules have to be interpreted in the current state to make choices for question mark types known for verification of phrases that depend on these. Notice also that we use s^{#} and not s^{##}, i.e. specifications in EML do not see the implementing types from other structure bindings.

(330) All the necessary sharing has already been checked in the static analysis, therefore this rule needs no premise.

(331),(335) Notice that the E component of IB shrinks while the IE component increases. E contains global objects which can be hidden by specifications (hence the shrinking), while IE contains interfaces of global structures as well as of specified structures.

Structure Descriptions  s, IB, γ ⊢ strdesc ⇒ IE

\frac{s, IB, γ ⊢ sigexp ⇒ IS  ⟨s, IB, γ′ ⊢ strdesc ⇒ IE⟩}{s, IB, γ⟨·γ′⟩ ⊢ strid : sigexp ⟨and strdesc⟩ ⇒ \{strid ↦ IS\} ⟨+ IE⟩}  (336)

Functor Declarations  s, B, γ ⊢ fundec ⇒ F

\frac{s, B, γ ⊢ funbind ⇒ F}{s, B, γ ⊢ functor funbind ⇒ F}  (337)

\overline{s, B, γ ⊢ ⇒ \{\}}  (338)

\frac{s, B, γ_{1} ⊢ fundec_{1} ⇒ F_{1} s, B + F_{1}, γ_{2} ⊢ fundec_{2} ⇒ F_{2}}{s, B, γ_{1} · γ_{2} ⊢ fundec_{1} ⟨;⟩ fundec_{2} ⇒ F_{1} + F_{2}}  (339)

Functor Bindings  s, B, γ ⊢ funbind ⇒ F

\frac{IB = Inter B  γ = γ_{1} · γ_{2} · γ_{3}⟨·γ_{4}⟩ s, IB, γ_{1} ⊢ psigexp ⇒ Σ Σ = (N)IS  N ∩ N of IB = ∅ l = l of s s, IB ⊕ \{strid ↦ IS\}, γ_{2} ⊢ psigexp′ ⇒ Σ′ ⟨s, B, γ_{4} ⊢ funbind ⇒ F ⟩  \frac{s_{⊥}, B, Σ ⊢ strexp^{•} ⇒ R  (s′, (φ, S)) ∈ R}{∃R′. s′_{l}, B ⊕ \{strid ↦ S\}, Σ′ ⊢ strexp ⇒ R′}}{s, B, γ ⊢ funid ( strid : psigexp ) : psigexp′ = strexp ⟨and funbind⟩ ⇒ \{funid ↦ (strid, strexp, B, (N)(IS, Σ′))\} ⟨+ F ⟩} (340)

\frac{IB = Inter B  γ = γ_{1} · γ_{2}⟨·γ_{3}⟩ s, IB, γ_{1} ⊢ psigexp ⇒ Σ Σ = (N)IS  N ∩ N of IB = ∅ s, IB ⊕ \{strid ↦ IS\}, γ_{2} ⊢ psigexp′ ⇒ Σ′ ⟨s, B, γ_{3} ⊢ funbind ⇒ F ⟩}{s, B, γ ⊢ funid ( strid : psigexp ) : psigexp′ = ? ⟨and funbind⟩ ⇒ \{funid ↦ (strid,?, B, (N)(IS, Σ′))\} ⟨+F ⟩} (341)

Comments:

(340) The rule in the premise ensures that the argument in a functor application can safely be replaced by anything satisfying the input signature (including generalised axioms) of the functor. “Safely” means here that the functor application is guaranteed to verificate.

(340),(341) There is no difference in the result of these two rules: rule 340 simply has an additional check that strexp satisfies the signature psigexp′ for any valid functor argument.

Top-level Declarations  s, B, γ ⊢ topdec ⇒ B
\frac{s, B, γ ⊢ strdec ⇒ E}{s, B, γ ⊢ strdec ⇒ \{(s′, (names E, E) in Basis) | (s′, E) ∈ E\}}  (342)

\frac{s, Inter B, γ ⊢ sigdec ⇒ G}{s, B, γ ⊢ sigdec ⇒ \{(s, (names G, G) in Basis)\}}  (343)

\frac{s, B, γ ⊢ fundec ⇒ F}{s, B, γ ⊢ fundec ⇒ \{(s, (names F, F) in Basis)\}}  (344)

10 Programs

The phrase classes FullProgram and Program of programs are defined as follows:

program ::= topdec ; ⟨program⟩
fullprogram ::= program

The variable topdec above refers to top-level declarations of the Full language. As the semantic rules shown so far only operate on the Bare language, we have to translate such a topdec into a top-level declaration of the Bare language — the rules for this purpose are 485–488 in Appendix B.

Semantic objects in this section are the semantic objects for the verification semantics; objects coming from other parts of the semantics are accordingly indexed, for example C_{DER} is a context of the semantics for derived forms. Similarly, we attribute each turnstile with the part of the semantics that it refers to — a missing index means “program semantics”.

Consider a sentence of the form ⊢ fullprogram ⇒ B, C_{DER}. The following main situations can arise:

• There is no B, C_{DER} such that ⊢ fullprogram ⇒ B, C_{DER} holds. This is the case if fullprogram either contains static errors (static semantics, derived forms) or an interface error of the verification semantics for modules, i.e. a structure (resp. functor) in fullprogram does not match its signature (resp. signatures).

• We have ⊢ fullprogram ⇒ B, C_{DER} but B = ∅. This situation arises if fullprogram contains a the structure or functor declaration which is inconsistent, i.e. which has an empty class of models. This inconsistency can arise in a number of ways, most typically if a stated axiom does not hold in any model or if a value declaration does not terminate or raises an exception.

• Otherwise all of the structure and functor declarations in fullprogram are consistent and each (s, B) ∈ B (together with C_{DER}) can be seen as a model of fullprogram.

Top-level Declarations  s, B, C_{DER} ⊢ topdec ⇒ B, C′_{DER}
\frac{¬∃C′_{DER}, topdec′. C_{DER} ⊢_{DER} topdec ⇒ topdec′, C′_{DER}}{s, B, C_{DER} ⊢ topdec ⇒ \{(s, B)\}, C_{DER}}  (345)

\frac{C_{DER} ⊢_{DER} topdec ⇒ topdec′, C′_{DER} ¬∃B_{STAT}, γ. Stat B ⊢_{STAT} topdec′ ⇒ B_{STAT}, γ}{s, B, C_{DER} ⊢ topdec ⇒ \{(s, B)\}, C_{DER}}  (346)

\frac{C_{DER} ⊢_{DER} topdec ⇒ topdec′, C′_{DER}  Stat B ⊢_{STAT} topdec′ ⇒ B_{STAT}, γ \frac{Stat B ⊢_{STAT} topdec′ ⇒ B′_{STAT}, γ′}{(names γ \ N of B)γ ≻ γ′}  s, B, γ ⊢_{VER} topdec′ ⇒ B}{s, B, C_{DER} ⊢ topdec ⇒ \{(s′, B ⊕ B′) | (s′, B′) ∈ B\}, C_{DER} + C′_{DER}}

(347)

Comments:

(346) A failing elaboration has no effect whatever. Even derived form declarations are “undone”. In contrast to SML there is no rule for dealing with raised exceptions, because packets cannot escape core level verification in EML.

(347) The rule in the premise ensures that the top-level declaration is verificated with a principal trace.

Programs  s, B, C_{DER} ⊢ program ⇒ B, C′_{DER}

\frac{s, B, C_{DER} ⊢ topdec ⇒ B, C′_{DER} ⟨ \frac{(s′, B′) ∈ B}{∃B′. s′, B′, C′_{DER} ⊢ program ⇒ B′, C′′_{DER}} ⟩}{s, B, C_{DER} ⊢ topdec ; ⟨program⟩ ⇒ \{(s′⟨′⟩, B′⟨′⟩) | (s′, B′) ∈ B, ⟨s′, B′, C′_{DER} ⊢ program ⇒ B′, C′′_{DER}, (s′′, B′′) ∈ B′⟩\}, C′⟨′⟩_{DER}}

(348)

Comment: Notice that C′′_{DER} is scoped at the main rule, see Section 1.2 — the resulting context for derived forms is not model-dependent and is the same for all (s′, B′) ∈ B. Another consequence of this scoping is that C′′_{DER} is arbitrary if B = ∅.

Full Program  ⊢ fullprogram ⇒ B, C_{DER}
\frac{s_{0}, B_{0}, C_{DER}^{0} ⊢ program ⇒ B, C_{DER}}{⊢ program ⇒ B, C_{DER}}  (349)

Comment: This rule connects the program semantics with the initial state s_{0}, the initial verification basis B_{0}, and the inital context for derived forms C_{DER}^{0}.

A Appendix: Full Grammar

This section gives the full grammar of Extended ML, which includes the syntax for the Core, the syntax for Modules and the derived forms. Syntactic phrases of the Full Language contain identifiers without status labels, i.e. the class Id takes the rôle of the classes Var, StrId, etc.

The Full language uses the same names for its phrase classes as the Bare language, see figures 3 and 7 on pages 11 and 17, respectively. Concerning the syntax of expressions, two additional subclasses of the phrase class Exp are introduced, namely AppExp (application expressions) and InfExp (infix expressions). The inclusion relation among the four classes is as follows:

AtExp ⊂ AppExp ⊂ InfExp ⊂ Exp

The effect is that certain phrases, such as “2 + if ··· then ··· else ··· ”, are now disallowed. An analogous construction applies to patterns, i.e. we also have additional phrase classes AppPat and InfPat, etc. Concerning identifiers, there are the phrase classes Id (and LongId, analogous to Section 2.4), Lab and TyVar. Each id ∈ Id is either alphanumeric (but not starting with a prime) or symbolic. Members of Id are considered to be lexical items. Another additional phrase class is D (digits): each d ∈ D is a character between 0 and 9 and is also regarded as a lexical item.

The grammatical conventions are similar to Section 2, namely:

• The brackets ⟨ ⟩ enclose optional phrases.

• For any syntax class X (over which x ranges) we define the syntax class Xseq (over which xseq ranges) as follows:

xseq ::= x  (singleton sequence)

(empty sequence)

(x_{1},···,x_{n}) (sequence, n ≥ 1)

Note that the “···” used here, a meta-symbol indicating syntactic repetition, must not be confused with “...” which is a reserved word of the language. To range over all three alternatives for sequences in semantic rules we write x_{1}···x_{n} (with n ≥ 0), which suppresses the syntactic commas and parentheses. The ambiguity for n = 1 will be harmless whenever we use this notation.

• Alternative forms for each phrase class are in order of decreasing precedence. This precedence resolves ambiguity in parsing in the following way. Suppose that a phrase class phrase has several alternative forms F_{1}···F_{n}. If a lexical sequence L_{1}···L_{k} reduces to more than one of the F_{i}, then it reduces to phrase via the F_{i} with lowest precedence. Example: The parsing of the sequence

if exp_{1} then exp_{2} else exp_{3} handle match

is determined by the above principle. Because if-expressions have lower precedence than handle-expressions, the sequence parses as

if exp_{1} then exp_{2} else (exp_{3} handle match)

Note particularly that the use of precedence does not decrease the class of admissible phrases; it merely rejects alternative ways of parsing certain phrases. In particular, the purpose is not to prevent a phrase, which is an instance of a form with higher precedence, having a constituent which is an instance of a form with lower precedence. Thus for example

            if ··· then case ··· of ··· else case ··· of ···

is quite admissible, and will be parsed as

           if ··· then (case ··· of ···) else (case ··· of ···)

• Longest match: Suppose F_{1}F_{2} is an alternative form of a phrase class. A natural number i is called a split index w.r.t. F_{1}F_{2} for a lexical sequence L_{1}···L_{k} if 0 ≤ i ≤ k and L_{1}···L_{i} reduces to F_{1} and L_{i+1}···L_{k} reduces to F_{2}. If for a given lexical sequence L = L_{1}···L_{k} there are different split indices w.r.t. F_{1}F_{2}, then L reduces to F_{1}F_{2} by reducing L_{1}···L_{j} to F_{1}, where j is either the maximal split index, or — iff the alternative form is labelled (R), indicating a right associative infix construct — the minimal split index.

• The disambiguation principles (precedence and longest match) do not apply to phrase classes InfExp and InfPat.

• For any syntax class X (over which x ranges) we define the syntax class X^{•} (over which x^{•} ranges) as the same as X, except that phrases of class X^{•} may not contain ?.

Disregarding the disambiguation principles for InfExp and InfPat makes parsing of these classes ambiguous. The derived form semantics (appendix B) ensures that only one of the obtained syntax trees can be translated into a program of the bare language.

atexp ::= scon  special constant
⟨op⟩longid  long identifier
{ ⟨exprow⟩ }  record
# lab  record selector
()  0-tuple
(exp_{1} , ··· , exp_{n})  n-tuple, n ≥ 2
[exp_{1} , ··· , exp_{n}]  list, n ≥ 0
(exp_{1} ; ··· ; exp_{n})  sequence, n ≥ 2
let dec in exp_{1} ; ··· ; exp_{n} end local declaration, n ≥ 1

( exp )

?  undefined value
exprow ::= lab = exp ⟨ , exprow⟩  expression row
appexp ::= atexp
appexp atexp  application expression
infexp ::= appexp
infexp_{1} id infexp_{2}  infix expression
exp  ::= infexp
exp : ty  typed
exp_{1}^{•} == exp_{2}^{•}  comparison (R)
exp_{1}^{•} =/= exp_{2}^{•}  comparison (R)
exists match^{•}  existential quantifier
forall match^{•}  universal quantifier
exp^{•} terminates  convergence predicate
exp^{•} proper  definedness predicate
exp_{1} andalso exp_{2}  conjunction
exp_{1} orelse exp_{2}  disjunction
exp_{1} implies exp_{2}  implication (R)
exp_{1} iff exp_{2}  if and only if
exp handle match  handle exception
raise exp  raise exception
exp raises match  test for exception
exp raises pat  test for exception
if exp_{1} then exp_{2} else exp_{3}  conditional
case exp of match  case analysis
fn match  function
match ::= mrule ⟨ | match⟩
mrule ::= pat => exp

dec  ::= val valbind  value declaration
fun fvalbind  function declaration
type typbind  type declaration
eqtype typbind  equality type declaration
datatype datbind  datatype declaration

⟨withtype typbind^{•}⟩

abstype datbind  abstype declaration

⟨withtype typbind^{•}⟩

    with dec end

exception exbind  exception declaration
local dec_{1} in dec_{2} end  local declaration
open longid_{1}···longid_{n}  open declaration, n ≥ 1
dec_{1} ⟨;⟩ dec_{2}  sequential declaration

empty declaration

infix ⟨d⟩ id_{1} ··· id_{n}  infix directive, n ≥ 1
infixr ⟨d⟩ id_{1} ··· id_{n}  infix directive, n ≥ 1
nonfix id_{1} ··· id_{n}  nonfix directive, n ≥ 1
valbind ::= pat = exp ⟨and valbind⟩

rec valbind

fvalbind ::= funcbind ⟨and fvalbind⟩  function declarations
funcbind ::= fpat ⟨:ty⟩ = exp ⟨| funcbind⟩ single function
typbind ::= tyvarseq id = ty ⟨and typbind⟩ type binding
tyvarseq id = ? ⟨and typbind⟩ question mark type binding
datbind ::= tyvarseq id = conbind

⟨and datbind⟩

conbind ::= id ⟨of ty⟩ ⟨| conbind⟩
exbind ::= id ⟨of ty⟩ ⟨and exbind⟩

id = longid ⟨and exbind⟩

Figure 20: Grammar: Declarations and Bindings

atpat ::=  wildcard
scon  special constant

⟨op⟩longid

{ ⟨patrow⟩ }  record
()  0-tuple
(pat_{1} , ··· , pat_{n})  n-tuple, n ≥ 2
[pat_{1} , ··· , pat_{n}]  list, n ≥ 0

( pat )

patrow ::= ...  wildcard
lab = pat ⟨ , patrow⟩  pattern row
id⟨:ty⟩ ⟨as pat⟩ ⟨, patrow⟩  label as variable
apppat ::= ⟨op⟩longid atpat  construction
atpat  atomic
infpat ::= apppat  application or atomic
infpat_{1} id infpat_{2}  infix construction
pat  ::= infpat
pat : ty  typed
⟨op⟩id ⟨: ty⟩ as pat  layered
fpat  ::= ⟨op⟩id atpat_{1}···atpat_{n}  fvalbind pattern sequence
(atpat_{1} id atpat′_{1}) atpat_{2}···atpat_{n}
atpat_{1} id atpat′_{1}

Figure 21: Grammar: Patterns

ty  ::= tyvar  type variable
{ ⟨tyrow⟩ }  record type
tyseq longid  type construction
ty_{1} * ··· * ty_{n}  tuple type, n ≥ 2
ty -> ty′  function type (R)

        ( ty )

tyrow ::= lab : ty ⟨ , tyrow⟩ type-expression row

Figure 22: Grammar: Type expressions

strexp  ::= struct strdec end  generative
longid  structure identifier
id ( strexp )  functor application

id ( strdec )

let strdec in strexp end  local declaration
strdec  ::= dec  declaration
axiom ax  axiom
structure strbind  structure
local strdec_{1} in strdec_{2} end local
strdec_{1} ⟨;⟩ strdec_{2}  sequential

empty

ax  ::= axexp ⟨and ax⟩  axioms
axexp  ::= exp^{•}  axiomatic expression
strbind  ::= sglstrbind ⟨and strbind⟩  structure binding
sglstrbind ::= id : psigexp = strexp  single structure binding
id : psigexp = ?  undefined structure binding
id = strexp  unguarded structure binding
sigexp  ::= sig spec end  generative
id  signature identifier
psigexp ::= sigexp  principal signature
sigdec  ::= signature sigbind  single
sigdec_{1} ⟨;⟩ sigdec_{2}  sequential

empty

sigbind  ::= id = psigexp ⟨and sigbind⟩

spec  ::= val valdesc  value
type typdesc  type
eqtype typdesc  eqtype
datatype datdesc  datatype
exception exdesc  exception
axiom axdesc  axiom
structure strdesc  structure
sharing shareq  sharing
local spec_{1} in spec_{2} end  local
open longid_{1}···longid_{n}  open (n ≥ 1)
include id_{1}···id_{n}  include (n ≥ 1)
spec_{1} ⟨;⟩ spec_{2}  sequential

empty

valdesc ::= id : ty ⟨and valdesc⟩
typdesc ::= tyvarseq id ⟨and typdesc⟩
datdesc ::= tyvarseq id = condesc ⟨and datdesc⟩
condesc ::= id ⟨of ty⟩ ⟨| condesc⟩
exdesc ::= id ⟨of ty⟩ ⟨and exdesc⟩
axdesc ::= specexp ⟨and axdesc⟩
specexp ::= let strdec in axexp end
exp^{•}
strdesc ::= id : sigexp ⟨and strdesc⟩
shareq ::= longid_{1} = ··· = longid_{n}  structure sharing
(n ≥ 2)
type longid_{1} = ··· = longid_{n}  type sharing
(n ≥ 2)
shareq_{1} and shareq_{2}  multiple

fundec  ::= functor funbind  single
fundec_{1} ⟨;⟩ fundec_{2}  sequence

empty

funbind  ::= id ( id′ : psigexp ): psigexp′  functor binding

= strexp ⟨and funbind⟩ id ( spec ) : psigexp

= strexp ⟨and funbind⟩

id ( id′ : psigexp ): psigexp′  undefined functor binding
= ? ⟨and funbind⟩

id ( spec ) : psigexp

= ? ⟨and funbind⟩
topdec  ::= strdec  structure-level declaration
sigdec  signature declaration
fundec  functor declaration
exp  expression at top-level
program  ::= topdec ; ⟨program⟩
fullprogram ::= program

Note: No topdec may contain, as an initial segment, a shorter toplevel declaration followed by a semicolon.

Figure 25: Grammar: Functors and Top-level Declarations

A.1 Syntactic Restrictions

The syntactic restrictions mentioned in sections 2.9 and 3.5 apply analogously to the full grammar.

Further restrictions are expressed in the next section, the semantics of derived forms.

B Appendix: Derived Forms

The rules in this section translate syntactical phrases of the full grammar into syntactical phrases of the Bare language.

B.1 Semantic Objects

The semantic objects of this section are the syntactic phrases of Bare and Full language and the objects in Figure 26.

st ∈ Status = {v, c, e, g, s, f, t}
fix ∈ Fixity = {l, r, n}
n ∈ N = {0, 1, 2, …}
VE ∈ VarEnv = Id →^{fin} (N × Fixity)
StE ∈ StatEnv = Id →^{fin} Status
TE ∈ TyEnv = Id →^{fin} (TypeFcn ⊎ {FAIL})
Λα^{(k)}.ty ∈ TypeFcn = ⊎_{k≥0}TyVar^{k} × Ty
SE ∈ StrEnv = Id →^{fin} Env
F ∈ FunEnv = Id →^{fin} (Env × Env)
G ∈ SigEnv = Id →^{fin} Env
(SE, TE, StE) or E ∈ Env = StrEnv × TyEnv × StatEnv
(E, VE, F, G) or C ∈ Context = Env × VarEnv × FunEnv × SigEnv
idval ∈ Idval = Env ⊎ TypeFcn ⊎ Status ⊎

(N × Fixity) ⊎ (Env × Env) ⊎ {FAIL}

π ∈ Context → (Id →^{fin} Idval)

Figure 26: Semantic Objects for Derived Forms

The results of looking up a long identifier in a context (rules 350–352) includes an identifier value. The object class IdVal contains the codomains of all environments of a context plus {FAIL}. The identifier value FAIL indicates that the access is unsuccessful, see rule 351. This is also used to generate “fresh” identifiers. Within type environments an identifier is bound to FAIL if this binding does not originate from a withtype type binding.

The variable π serves as a placeholder for various projections from a context to its components. A concrete projection is written with an indicating the argument position, e.g. (SEofEof ) selects the structure environment of a context.

Given a type expression ty, a sequence of type variables α_{1}, …, α_{k} and a sequence of type expressions ty_{1}, …, ty_{k}, we write ty{ty_{1}/α_{1}, …, ty_{k}/α_{k}} for the result of the simultaneous substitution of the type variables α_{i} throughout ty by the corresponding type expressions ty_{i}. The conventions and notations used for projection, injection and modification in preceding sections are adapted here as well, except that within this section, we write C ⊕E for the context obtained from C by replacing its first component by E. To obtain default behaviour for certain forms of environments, we introduce the following notation:

[StE](id) = StE(id) if id ∈ Dom StE
= v  otherwise
[VE](id) = VE(id) if id ∈ Dom VE
= (0, n) otherwise

In other words: [StE] resp. [VE] is an (infinite) map which extends the finite map StE resp. VE by the default value v resp. (0, n).

B.2 Identifiers

The Bare language distinguishes different forms of identifiers, e.g. value variables and value constructors, structure identifiers and signature identifiers. Syntactically, identifiers in the classes Var, Con, ExCon, TyCon, StrId, SigId and FunId all belong to the class Id. Within phrases of the Bare language, we distinguish them by their attached identifier status, i.e. id^{st} belongs to the class indicated by st, where v, c, e, t, s, g and f refer to Var, Con, ExCon, TyCon, StrId, SigId and FunId, respectively. Thus, any value variable var has the form idv with id ∈ Id, etc.

Variable environments map identifiers to their fixity (n, fix). This is used for parsing expressions with infix operators: the number n is the precedence of the identifier (when used infix) and fix says whether it is left- or right-associative (l or r, respectively) or non-infix (n).

Phrases of the Full language only contain plain identifiers (i.e. without attached status) and the semantic rules in this section which translate the Full into the Bare language also provide this status information.

Given a natural number n, we write \overline{n} for a label lab that is a string of digits and that denotes this number when interpreted as a special constant.

B.3 Enrichment

We define a relation ≻ on identifier status as st ≻ st′ ⟺ st = st′ ∨ st′ = v. We extend this to (status, structure) environments as follows:

E_{1} ≻ E_{2} ⟺ StE of E_{1} ≻ StE of E_{2} ∧ SE of E_{1} ≻ SE of E_{2}
SE_{1} ≻ SE_{2} ⟺ ∀id ∈ Dom SE_{2}. id ∈ Dom SE_{1} ∧ SE_{1}(id) ≻ SE_{2}(id)
StE_{1} ≻ StE_{2} ⟺ ∀id ∈ Dom StE_{2}. id ∈ Dom StE_{1} ∧ StE_{1}(id) ≻ StE_{2}(id)

B.4 Inference Rules

All sentences of this part of the semantics have the form C, A_{1}^{∗} ⊢ phrase ⇒ phrase′, A_{2}^{∗}, where C is a context, A_{1}^{∗} and A_{2}^{∗} are sequences of semantic or syntactic objects, phrase is a phrase of the Full language and phrase′ is a (corresponding) phrase of the Bare language. Syntactic objects in A_{1}^{∗} and A_{2}^{∗} belong to the Bare language. When we have C, A_{1}^{∗} ⊢ phrase ⇒ phrase′, A_{2}^{∗}, then phrase′ and A_{2}^{∗} are determined by C, A_{1}^{∗}, and phrase, modulo choice of fresh identifier names (e.g. as in rule 357).

We do not give all rules explicitly. When we omit the sentence form for a phrase class Phrase, the sentence form is C ⊢ phrase ⇒ phrase′. When we omit rules for an alternative form of a phrase class, then these rules can be determined as follows: if the alternative form in the full grammar is t_{1} v_{1} t_{2} ···t_{k} v_{k} t_{k+1} (k ≥ 0), where each t_{i} is a sequence of lexical items (terminals) and each v_{i} is a variable ranging over a phrase class (in the Full language), then the missing rule is:

\frac{C ⊢ v_{1} ⇒ v′_{1} ··· C ⊢ v_{k} ⇒ v′_{k}}{C ⊢ t_{1} v_{1} t_{2} ···t_{k} v_{k} t_{k+1} ⇒ t_{1} v′_{1} t_{2} ···t_{k} v′_{k} t_{k+1}}

Long Identifiers  C, π, st ⊢ longid ⇒ longid′, idval
\frac{id ∈ Dom(πC) idval = π(C)(id)}{C, π, st ⊢ id ⇒ id^{st}, idval}  (350)

\frac{id ∉ Dom(πC)}{C, π, st ⊢ id ⇒ id^{st}, FAIL}  (351)

\frac{(SE of E of C)(id) = E  C ⊕ E, π, st ⊢ longid ⇒ longid′, idval}{C, π, st ⊢ id.longid ⇒ ids.longid′, idval}  (352)

Comments:

(351) This rule has two purposes. On the one hand, it detects identifiers that are used without being declared. On the other, it is also used to generate fresh identifiers, e.g. in rule 357.

Value Identifiers  C ⊢ ⟨op⟩ longid ⇒ longid′, st
\frac{[VE of C](id) = (n, fix) fix ≠ n [StE of E of C](id) = st}{C ⊢ op id ⇒ id^{st}, st}  (353)

\frac{[VE of C](id) = (n, n) [StE of E of C](id) = st}{C ⊢ ⟨op⟩ id ⇒ id^{st}, st}  (354)

\frac{(SE of E of C)(id) = E  C ⊕ E ⊢ op longid ⇒ longid′, st}{C ⊢ ⟨op⟩ id.longid ⇒ ids.longid′, st}  (355)

Comments:

(355) The presence of op in the premise, regardless whether it occurs in the conclusion or not, means that identifiers with infix status can be used noninfix in their long form.

Atomic Expressions  C ⊢ atexp ⇒ atexp′
\frac{C ⊢ ⟨op⟩longid ⇒ longid′, st}{C ⊢ ⟨op⟩longid ⇒ longid′}  (356)

\frac{C, StE of E of , v ⊢ id ⇒ var, FAIL}{C ⊢ # lab ⇒ (fn \{ lab=var,...\} => var)}  (357)

\overline{C ⊢ () ⇒ \{\}}  (358)

\frac{n ≥ 2 C ⊢ exp_{1} ⇒ exp′_{1} ··· C ⊢ exp_{n} ⇒ exp′_{n}}{C ⊢ (exp_{1},···,exp_{n}) ⇒ \{1=exp′_{1},···,\overline{n}=exp′_{n}\}}  (359)

\frac{n ≥ 0 C ⊢ (exp_{1})::···::(exp_{n})::nil ⇒ exp}{C ⊢ [exp_{1},···,exp_{n}] ⇒ (exp)}  (360)

\frac{n ≥ 1 C ⊢ case (exp_{1}) of => ··· case (exp_{n}) of => (exp) ⇒ exp′}{C ⊢ (exp_{1};···;exp_{n};exp) ⇒ (exp′)}

(361)

\frac{n ≥ 1 C ⊢ dec ⇒ dec′, C′ C + C′ ⊢ (exp_{1};···;exp_{n}) ⇒ atexp}{C ⊢ let dec in exp_{1};···;exp_{n} end ⇒ let dec′ in atexp end} (362)

Comments:

(357) The premise selects a fresh identifier id and attributes it with status v, giving the value variable var.

(360) It is assumed here that neither nil nor :: has been rebound, and :: still has right-associative infix status.

(362) The side-condition n ≥ 1 means that the rule applies to all let-expressions.

Applications  C ⊢ appexp ⇒ exp
\frac{C ⊢ appexp ⇒ exp  C ⊢ atexp ⇒ atexp′}{C ⊢ appexp atexp ⇒ (exp) atexp′}  (363)

Infix Expressions  C, n, fix ⊢ infexp ⇒ exp
\frac{C ⊢ appexp ⇒ exp}{C, n, fix ⊢ appexp ⇒ exp}  (364)

\frac{[VE of C](id) = (n′, l) n < n′ ∨ (n = n′ ∧ fix = l) [StE of E of C](id) = st C, n′, l ⊢ infexp_{1} ⇒ exp_{1} C, n′, n ⊢ infexp_{2} ⇒ exp_{2}}{C, n, fix ⊢ infexp_{1} id infexp_{2} ⇒ id^{st} \{1=exp_{1},2=exp_{2}\}}  (365)

\frac{[VE of C](id) = (n′, r) n < n′ ∨ (n = n′ ∧ fix = r) [StE of E of C](id) = st C, n′, n ⊢ infexp_{1} ⇒ exp_{1} C, n′, r ⊢ infexp_{2} ⇒ exp_{2}}{C, n, fix ⊢ infexp_{1} id infexp_{2} ⇒ id^{st} \{1=exp_{1},2=exp_{2}\}}  (366)

Comments:

(366) The SML definition makes two different right-associative operators of the same precedence associate to the left. This rule makes them associate to the right.

Expressions  C ⊢ exp ⇒ exp′

Not all of the parentheses these rules generate are really necessary; many of them are here only for uniformity of presentation.

\frac{C, 0, fix ⊢ infexp ⇒ exp}{C ⊢ infexp ⇒ (exp)}  (367)

\frac{C ⊢ not(exp_{1}^{•} == exp_{2}^{•}) ⇒ exp}{C ⊢ exp_{1}^{•} =/= exp_{2}^{•} ⇒ (exp)}  (368)

      \frac{C ⊢ (exp^{•} terminates) andalso not(exp^{•} raises ) ⇒ exp}{C ⊢ exp^{•} proper ⇒ (exp)}  (369)

\frac{C ⊢ if exp_{1} then exp_{2} else false ⇒ exp}{C ⊢ exp_{1} andalso exp_{2} ⇒ (exp)}  (370)

\frac{C ⊢ if exp_{1} then true else exp_{2} ⇒ exp}{C ⊢ exp_{1} orelse exp_{2} ⇒ (exp)}  (371)

\frac{C ⊢ if exp_{1} then exp_{2} else true ⇒ exp}{C ⊢ exp_{1} implies exp_{2} ⇒ (exp)}  (372)

\frac{C ⊢ if exp_{1} then exp_{2} else not(exp_{2}) ⇒ exp}{C ⊢ exp_{1} iff exp_{2} ⇒ (exp)}  (373)

   \frac{C ⊢ ((exp ; false) handle match) handle  => false ⇒ exp′}{C ⊢ exp raises match ⇒ (exp′)}  (374)

\frac{C ⊢ exp raises pat => true ⇒ exp′}{C ⊢ exp raises pat ⇒ (exp′)}  (375)

\frac{C ⊢ case exp_{1} of true => (exp_{2}) | false => (exp_{3}) ⇒ exp}{C ⊢ if exp_{1} then exp_{2} else exp_{3} ⇒ (exp)}  (376)

\frac{C ⊢ (fn match)(exp) ⇒ exp′}{C ⊢ case exp of match ⇒ (exp′)}  (377)

Comments:

(367) The fixity fix can be chosen arbitrarily. If it were fixed, then either left- or right-associative or all operators of precedence 0 would be ruled out.

(368),(369),(373) It is assumed here that not has not been rebound, neither in StE nor in VE.

(370)–(376) It is assumed here that true and false have not been rebound.

Match Rules  C ⊢ mrule ⇒ mrule′
\frac{C ⊢ pat ⇒ pat′, StE  C + StE ⊢ exp ⇒ exp′}{C ⊢ pat => exp ⇒ pat′ => exp′}  (378)

Declarations  C ⊢ dec ⇒ dec′, C′
\frac{C ⊢ valbind ⇒ valbind′, StE}{C ⊢ val valbind ⇒ val valbind′, StE in Env in Context}  (379)

\frac{C + StE ⊢ fvalbind ⇒ valbind, StE}{C ⊢ fun fvalbind ⇒ val rec valbind, StE in Env in Context}  (380)

\frac{C ⊢ typbind ⇒ typbind′, TE, TE′}{C ⊢ type typbind ⇒ type typbind′, TE′ in Env in Context}  (381)

\frac{C ⊢ typbind ⇒ typbind′, TE, TE′}{C ⊢ eqtype typbind ⇒ eqtype typbind′, TE′ in Env in Context}  (382)

132 B APPENDIX: DERIVED FORMS ⟨C + E ⊢ typbind^{•} ⇒ typbind′, TE, TE′⟩ C + E⟨ +TE⟩ ⊢ datbind ⇒ datbind′, E

C ⊢ datatype datbind ⟨withtype typbind^{•}⟩ ⇒ datatype datbind′ ⟨ ; type typbind′⟩, E⟨+TE′⟩ in Context

(383)

\frac{⟨C + E ⊢ typbind^{•} ⇒ typbind′, TE, TE′ C + E⟨ +TE⟩ ⊢ datbind ⇒ datbind′, E C + E⟨+TE′⟩ ⊢ dec ⇒ dec′, C′}{C ⊢ abstype datbind ⟨withtype typbind^{•}⟩ with dec end ⇒ abstype datbind′ with ⟨type typbind′ ;⟩ dec′ end, ⟨TE′ in Context +⟩C′}  (384)
\frac{C ⊢ exbind ⇒ exbind′, StE}{C ⊢ exception exbind ⇒ exception exbind′, StE in Env in Context} (385)
\frac{C ⊢ dec_{1} ⇒ dec′_{1}, C_{1} C + C_{1} ⊢ dec_{2} ⇒ dec′_{2}, C_{2}}{C ⊢ local dec_{1} in dec_{2} end ⇒ local dec′_{1} in dec′_{2} end, C_{2}}  (386)

\frac{C, SE of E of , s ⊢ longid_{1} ⇒ longid′_{1}, E_{1} ··· C, SE of E of , s ⊢ longid_{n} ⇒ longid′_{n}, E_{n}}{C ⊢ open longid_{1}···longid_{n} ⇒ open longid′_{1}···longid′_{n}, E_{1} + ··· + E_{n} in Context}

(387)

C ⊢  ⇒  , {} in Context

(388)

\frac{C ⊢ dec_{1} ⇒ dec′_{1}, C_{1} C + C_{1} ⊢ dec_{2} ⇒ dec′_{2}, C_{2}}{C ⊢ dec_{1} ⟨;⟩ dec_{2} ⇒ dec′_{1} ⟨;⟩ dec′_{2}, C_{1} + C_{2}}  (389)
\frac{n ≥ 1 VE = \{id ↦ (0⟨+d⟩, l) ; id ∈ \{id_{1}, ···, id_{n}\}\}}{C ⊢ infix ⟨d⟩ id_{1} ··· id_{n} ⇒  , VE in Context}  (390)
\frac{n ≥ 1 VE = \{id ↦ (0⟨+d⟩, r) ; id ∈ \{id_{1}, ···, id_{n}\}\}}{C ⊢ infixr ⟨d⟩ id_{1} ··· id_{n} ⇒  , VE in Context}  (391)
\frac{n ≥ 1 VE = \{id ↦ (0, n) ; id ∈ \{id_{1}, ···, id_{n}\}\}}{C ⊢ nonfix id_{1} ··· id_{n} ⇒  , VE in Context}  (392)

Comments:

(383),(384) Type declarations of these forms are mutually recursive.

(390)–(392) Infix directives are replaced by the empty declaration. The digit d is treated in the premise as the corresponding natural number.

Value Bindings  C ⊢ valbind ⇒ valbind′, StE

\frac{C ⊢ pat ⇒ pat′, StE  C ⊢ exp ⇒ exp′ ⟨C ⊢ valbind ⇒ valbind′, StE′⟩}{C ⊢ pat = exp ⟨and valbind⟩ ⇒ pat′ = exp′ ⟨and valbind′⟩, StE⟨+StE′⟩} (393)

\frac{C + StE ⊢ valbind ⇒ valbind′, StE}{C ⊢ rec valbind ⇒ rec valbind′, StE}  (394)

Comments:

(394) The recursive binding of StE allows constructor status to be overwritten. This is not possible in SML (although the SML semantics is not entirely clear about this).

Function Value Bindings  C ⊢ fvalbind ⇒ valbind, StE

A function value binding does not make “holes” in the scope of constructors, but we need to make it produce a status environment in order to correctly generate fresh identifiers.

\frac{C ⊢ funcbind ⇒ match, var, n var = idv ∀i, j. 1 ≤ i, j ≤ n ∧ i ≠ j ⟹ id_{i} ≠ id_{j} ∀i. 1 ≤ i ≤ n ⟹ C, StE of E of , v ⊢ id_{i} ⇒ var_{i}, FAIL C ⊢ case (id_{1}, ···, id_{n}) of match ⇒ exp ⟨C ⊢ fvalbind ⇒ valbind, StE⟩}{C ⊢ funcbind ⟨and fvalbind⟩ ⇒ var = fn var_{1} => ··· fn var_{n} => exp ⟨and valbind⟩, \{id ↦ v\}⟨+StE⟩} (395)

Single Function Bindings  C ⊢ funcbind ⇒ match, var, n

\frac{C ⊢ fpat ⇒ pat, var, n, StE  ⟨C ⊢ ty ⇒ ty′⟩ C + StE ⊢ exp ⇒ exp′ ⟨⟨C ⊢ funcbind ⇒ match, var, n⟩⟩}{C ⊢ fpat ⟨:ty⟩ = exp ⟨⟨| funcbind⟩⟩ ⇒ pat => exp′ ⟨:ty′⟩ ⟨⟨| match⟩⟩, var, n}  (396)

Comment: Notice that the function name and the number of parameters have to be the same throughout a funcbind.

Type Bindings  C ⊢ typbind ⇒ typbind′, TE, TE′

A type binding produces two type environments, the first for expansion of type abbreviations (for withtype types), the second for declaring the type constructors to be irreducible within type expressions, see rule 430.

\frac{tyvarseq = α^{(k)} C ⊢ ty ⇒ ty′ ⟨C ⊢ typbind ⇒ typbind′, TE, TE′⟩}{C ⊢ tyvarseq id = ty ⟨and typbind⟩ ⇒ tyvarseq idt = ty′ ⟨and typbind′⟩, \{id ↦ Λα^{(k)}.ty′\}⟨+TE⟩, \{id ↦ FAIL\}⟨+TE′⟩}

(397)

\frac{tyvarseq = α^{(k)} ⟨C ⊢ typbind ⇒ typbind′, TE, TE′⟩}{C ⊢ tyvarseq id = ? ⟨and typbind⟩ ⇒ tyvarseq idt = ? ⟨and typbind′⟩, \{id ↦ FAIL\}⟨+TE⟩, \{id ↦ FAIL\}⟨+TE′⟩}  (398)

Data Type Bindings  C ⊢ datbind ⇒ datbind′, E
\frac{C ⊢ conbind ⇒ conbind′, StE  ⟨C ⊢ datbind ⇒ datbind′, E⟩}{C ⊢ tyvarseq id = conbind ⟨and datbind⟩ ⇒ tyvarseq idt = conbind′ ⟨and datbind′⟩, (\{id ↦ FAIL\}, StE) in Env ⟨+E⟩}  (399)

Constructor Bindings  C ⊢ conbind ⇒ conbind′, StE
\frac{⟨C ⊢ conbind ⇒ conbind′, StE⟩}{C ⊢ id ⟨ | conbind⟩ ⇒ idc ⟨ | conbind′⟩, \{id ↦ c\} ⟨+StE⟩}  (400)

\frac{C ⊢ ty ⇒ ty′ ⟨C ⊢ conbind ⇒ conbind′, StE⟩}{C ⊢ id of ty ⟨ | conbind⟩ ⇒ idc of ty′ ⟨ | conbind′⟩, \{id ↦ c\} ⟨+StE⟩} (401)

Exception Bindings  C ⊢ exbind ⇒ exbind′, StE
\frac{⟨C ⊢ ty ⇒ ty′⟩ ⟨⟨C ⊢ exbind ⇒ exbind′, StE⟩⟩}{C ⊢ id ⟨of ty⟩ ⟨⟨and exbind⟩⟩ ⇒ ide ⟨of ty′⟩ ⟨⟨and exbind′⟩⟩, \{id ↦ e\}⟨⟨+StE⟩⟩}  (402)

\frac{C, StE of E of , e ⊢ longid ⇒ longexcon, e ⟨C ⊢ exbind ⇒ exbind′, StE⟩}{C ⊢ id = longid ⟨and exbind⟩ ⇒ ide = longexcon ⟨and exbind′⟩, \{id ↦ e\}⟨+StE⟩}  (403)

Atomic Patterns  C ⊢ atpat ⇒ atpat′, StE
\overline{C ⊢ ⇒ , \{\}}  (404)
C ⊢ scon ⇒ scon, {}

(405)

\frac{C ⊢ ⟨op⟩ id ⇒ var, v}{C ⊢ ⟨op⟩ id ⇒ var, \{id ↦ v\}}  (406)
\frac{C ⊢ ⟨op⟩ longid ⇒ longid′, st st ≠ v}{C ⊢ ⟨op⟩ longid ⇒ longid′, \{\}}  (407)
\frac{⟨C ⊢ patrow ⇒ patrow′, StE⟩}{C ⊢ \{ ⟨patrow⟩ \} ⇒ \{ ⟨patrow′⟩ \}, \{\}⟨+StE⟩}  (408)
\overline{C ⊢ () ⇒ \{\}, \{\}}  (409)
\frac{n ≥ 2 C ⊢ pat_{1} ⇒ pat′_{1}, StE_{1} ··· C ⊢ pat_{n} ⇒ pat′_{n}, StE_{n}}{C ⊢ (pat_{1},···,pat_{n}) ⇒ \{1=pat_{1},···,\overline{n}=pat_{n}\}, StE_{1} + ··· + StE_{n}}  (410)
\frac{n ≥ 0 C ⊢ (pat_{1})::···::(pat_{n})::nil ⇒ pat, StE}{C ⊢ [pat_{1},···,pat_{n}] ⇒ (pat), StE}  (411)
\frac{C ⊢ pat ⇒ pat′, StE}{C ⊢ (pat) ⇒ (pat′), StE}  (412)

Comments:

(411) It is assumed here that neither nil nor :: has been rebound, and :: still has right-associative infix status.

Pattern Rows  C ⊢ patrow ⇒ patrow′, StE
\overline{C ⊢ ... ⇒ ..., \{\}}  (413)
\frac{C ⊢ pat ⇒ pat′, StE  ⟨C ⊢ patrow ⇒ patrow′, StE′⟩}{C ⊢ lab = pat ⟨ , patrow⟩ ⇒ lab = pat′ ⟨ , patrow′⟩, StE ⟨+StE′⟩}  (414)
\frac{lab = id in Lab C ⊢ lab = id⟨:ty⟩ ⟨⟨, patrow⟩⟩ ⇒ patrow′, StE}{C ⊢ id⟨:ty⟩ ⟨⟨, patrow⟩⟩ ⇒ patrow′, StE}  (415)

\frac{lab = id in Lab C ⊢ lab = id⟨:ty⟩ as pat ⟨⟨, patrow⟩⟩ ⇒ patrow′, StE}{C ⊢ id⟨:ty⟩ as pat ⟨⟨, patrow⟩⟩ ⇒ patrow′, StE}

Application Patterns  C ⊢ apppat ⇒ pat, StE
\frac{C ⊢ ⟨op⟩longid ⇒ longid′, st st ≠ v C ⊢ atpat ⇒ atpat′, StE}{C ⊢ ⟨op⟩longid atpat ⇒ longid′ atpat′, StE}  (417)

\frac{C ⊢ atpat ⇒ atpat′, StE}{C ⊢ atpat ⇒ atpat′, StE}  (418)

Infix Patterns  C, n, fix ⊢ infpat ⇒ pat, StE
\frac{C ⊢ apppat ⇒ pat, StE}{C, n, fix ⊢ apppat ⇒ pat, StE}  (419)

\frac{[VE of C](id) = (n′, l) n < n′ ∨ (n = n′ ∧ fix = l) [StE of E of C](id) = st ∈ \{c, e\} C, n′, l ⊢ infpat_{1} ⇒ pat_{1}, StE_{1} C, n′, n ⊢ infpat_{2} ⇒ pat_{2}, StE_{2}}{C, n, fix ⊢ infpat_{1} id infpat_{2} ⇒ id^{st} \{1=pat_{1},2=pat_{2}\}, StE_{1} + StE_{2}}  (420)

\frac{[VE of C](id) = (n′, r) n < n′ ∨ (n = n′ ∧ fix = r) [StE of E of C](id) = st ∈ \{c, e\} C, n′, n ⊢ infpat_{1} ⇒ pat_{1}, StE_{1} C, n′, r ⊢ infpat_{2} ⇒ pat_{2}, StE_{2}}{C, n, fix ⊢ infpat_{1} id infpat_{2} ⇒ id^{st} \{1=pat_{1},2=pat_{2}\}, StE_{1} + StE_{2}}  (421)

Patterns  C ⊢ pat ⇒ pat′, StE
\frac{C, 0, fix ⊢ infpat ⇒ pat, StE}{C ⊢ infpat ⇒ pat, StE}  (422)

\frac{C ⊢ ty ⇒ ty′ C ⊢ pat ⇒ pat′, StE}{C ⊢ pat : ty ⇒ pat′ : ty′, StE}  (423)

\frac{C ⊢ ⟨op⟩id ⇒ var, v ⟨⟨C ⊢ ty ⇒ ty′⟩⟩ C ⊢ pat ⇒ pat′, StE}{C ⊢ ⟨op⟩id⟨⟨: ty⟩⟩ as pat ⇒ var⟨⟨: ty′⟩⟩ as pat′, \{id ↦ v\} + StE}  (424)

Function Patterns  C ⊢ fpat ⇒ pat, var, n, StE
\frac{n ≥ 1 C ⊢ (atpat_{1},···,atpat_{n}) ⇒ pat, StE}{C ⊢ op id atpat_{1}···atpat_{n} ⇒ pat, idv, n, StE}  (425)

\frac{n ≥ 1 [VE of C](id) = (n′, n) C ⊢ (atpat_{1},···,atpat_{n}) ⇒ pat, StE}{C ⊢ id atpat_{1}···atpat_{n} ⇒ pat, idv, n, StE}

\frac{C ⊢ ((atpat_{1},atpat′_{1}),atpat_{2},···,atpat_{n}) ⇒ pat, StE [VE of C](id) = (n′, fix) fix ≠ n n ≥ 1}{C ⊢ (atpat_{1} id atpat′_{1}) atpat_{2}···atpat_{n} ⇒ pat, idv, n, StE}  (427)

\frac{[VE of C](id) = (n′, fix) fix ≠ n C ⊢ (atpat_{1},atpat′_{1}) ⇒ pat, StE}{C ⊢ atpat_{1} id atpat′_{1} ⇒ pat, idv, 1, StE} (428)

Type Expressions  C ⊢ ty ⇒ ty′

\frac{tyseq = ty_{1}···ty_{k}  C ⊢ ty_{1} ⇒ ty′_{1} ··· C ⊢ ty_{k} ⇒ ty′_{k} C, TE of E of , t ⊢ longid ⇒ longtycon, Λα_{1}···α_{k}.ty}{C ⊢ tyseq longid ⇒ ty\{ty′_{1}/α_{1}, …, ty′_{k}/α_{k}\}}  (429)

\frac{C, TE of E of , t ⊢ longid ⇒ longtycon, FAIL tyseq = ty_{1}···ty_{k} C ⊢ ty_{1} ⇒ ty′_{1} ··· C ⊢ ty_{k} ⇒ ty′_{k}  tyseq′ = ty′_{1}···ty′_{k}}{C ⊢ tyseq longid ⇒ tyseq′ longtycon}  (430)

\frac{n ≥ 2 C ⊢ \{1:ty_{1},···,\overline{n}:ty_{n}\} ⇒ ty}{C ⊢ ty_{1}* ··· *ty_{n} ⇒ ty}  (431)

Comments:

(429) This rule replaces type constructors defined in a withtype clause of a type declaration. The replacement of withtype types of the current context C does not apply to type constructors in ty — ty is a type expression for which withtype types have already been replaced.

Structure Expressions  C ⊢ strexp ⇒ strexp′, E
\frac{C ⊢ strdec ⇒ strdec′, C′}{C ⊢ struct strdec end ⇒ struct strdec′ end, E of C′}  (432)

\frac{C, SE of E of , s ⊢ longid ⇒ longstrid, E}{C ⊢ longid ⇒ longstrid, E}  (433)

\frac{C, F of , f ⊢ id ⇒ funid, (E_{1}, E_{2}) C ⊢ strexp ⇒ strexp′, E E ≻ E_{1}}{C ⊢ id ( strexp ) ⊢ funid ( strexp′ ), E_{2}} (434)

\frac{C ⊢ id ( struct strdec end ) ⇒ strexp′, E}{C ⊢ id ( strdec ) ⇒ strexp′, E}  (435)

\frac{C ⊢ strdec ⇒ strdec′, C′ C + C′ ⊢ strexp ⇒ strexp′, E}{C ⊢ let strdec in strexp end ⇒ let strdec′ in strexp′ end, E}  (436)

Structure-level Declarations  C ⊢ strdec ⇒ strdec′, C′
\frac{C ⊢ dec ⇒ dec′, C′}{C ⊢ dec ⇒ dec′, C′}  (437)

\frac{C ⊢ ax ⇒ ax′}{C ⊢ axiom ax ⇒ axiom ax′, \{\} in Context}  (438)

\frac{C ⊢ strbind ⇒ strbind′, SE}{C ⊢ structure strbind ⇒ structure strbind′, SE in Env in Context} (439)

\frac{C ⊢ strdec_{1} ⇒ strdec′_{1}, C_{1} C + C_{1} ⊢ strdec_{2} ⇒ strdec′_{2}, C_{2}}{C ⊢ local strdec_{1} in strdec_{2} end ⇒ local strdec′_{1} in strdec′_{2} end, C_{2}} (440)

C ⊢ ⇒ , {} in Context

(441)

\frac{C ⊢ strdec_{1} ⇒ strdec′_{1}, C_{1} C + C_{1} ⊢ strdec_{2} ⇒ strdec′_{2}, C_{2}}{C ⊢ strdec_{1} ⟨;⟩ strdec_{2} ⇒ strdec′_{1} ⟨;⟩ strdec′_{2}, C_{1} + C_{2}}  (442)

Structure Bindings  C ⊢ strbind ⇒ SE
\frac{C ⊢ sglstrbind ⇒ sglstrbind′, SE_{1} ⟨C ⊢ strbind ⇒ strbind′, SE_{2}⟩}{C ⊢ sglstrbind ⟨and strbind⟩ ⇒ sglstrbind′ ⟨and strbind′⟩, SE_{1} ⟨+SE_{2}⟩} (443)

Single Structure Bindings  C ⊢ sglstrbind ⇒ sglstrbind′, SE
\frac{C ⊢ psigexp ⇒ psigexp′, E_{1} C ⊢ strexp ⇒ strexp′, E_{2} E_{2} ≻ E_{1}}{C ⊢ id : psigexp = strexp ⇒ ids : psigexp′ = strexp′, \{id ↦ E_{1}\}} (444)

\frac{C ⊢ psigexp ⇒ psigexp′, E}{C ⊢ id : psigexp = ? ⇒ ids : psigexp′ = ?, \{id ↦ E\}}  (445)

\frac{C ⊢ strexp ⇒ strexp′, E}{C ⊢ id = strexp ⇒ ids = strexp′, \{id ↦ E\}}  (446)

Signature Expressions  C ⊢ sigexp ⇒ sigexp′, E
\frac{C ⊢ spec ⇒ spec′, E}{C ⊢ sig spec end ⇒ sig spec′ end, E}  (447)

\frac{C, G of , g ⊢ id ⇒ sigid, E}{C ⊢ id ⇒ sigid, E}  (448)

Principal Signatures  C ⊢ psigexp ⇒ psigexp′, E
\frac{C ⊢ sigexp ⇒ sigexp′, E}{C ⊢ sigexp ⇒ sigexp′, E}  (449)

Signature Declarations  C ⊢ sigdec ⇒ sigdec′, G
\frac{C ⊢ sigbind ⇒ sigbind′, G}{C ⊢ signature sigbind ⇒ signature sigbind′, G}  (450)

\overline{C ⊢ ⇒ , \{\}}  (451)

\frac{C ⊢ sigdec_{1} ⇒ sigdec′_{1}, G_{1} C + G_{1} ⊢ sigdec_{2} ⇒ sigdec′_{2}, G_{2}}{C ⊢ sigdec_{1} ⟨;⟩ sigdec_{2} ⇒ sigdec′_{1} ⟨;⟩ sigdec′_{2}, G_{1} + G_{2}}  (452)

Signature Bindings  C ⊢ sigbind ⇒ sigbind′, G
\frac{C ⊢ psigexp ⇒ psigexp′, E  ⟨C ⊢ sigbind ⇒ sigbind′, G⟩}{C ⊢ id = psigexp ⟨and sigbind⟩ ⇒ idg = psigexp′ ⟨and sigbind′⟩, \{id ↦ E\} ⟨+G⟩}  (453)

Specifications  C ⊢ spec ⇒ spec′, E
\frac{C ⊢ valdesc ⇒ valdesc′, E}{C ⊢ val valdesc ⇒ val valdesc′, E}  (454)

\frac{C ⊢ typdesc ⇒ typdesc′, TE}{C ⊢ type typdesc ⇒ type typdesc′, TE in Env}  (455)

\frac{C ⊢ typdesc ⇒ typdesc′, TE}{C ⊢ eqtype typdesc ⇒ eqtype typdesc′, TE in Env}  (456)

\frac{C ⊢ datdesc ⇒ datdesc′, E}{C ⊢ datatype datdesc ⇒ datatype datdesc′, E}  (457)

\frac{C ⊢ exdesc ⇒ exdesc′, StE}{C ⊢ exception exdesc ⇒ exception exdesc′, StE in Env}  (458)

\frac{C ⊢ axdesc ⇒ axdesc′}{C ⊢ axiom axdesc ⇒ axiom axdesc′, \{\} in Env}  (459)

\frac{C ⊢ strdesc ⇒ strdesc′, SE}{C ⊢ structure strdesc ⇒ structure strdesc′, SE in Env}  (460)

\frac{C ⊢ shareq ⇒ shareq′}{C ⊢ sharing shareq ⇒ sharing shareq′, \{\} in Env}  (461)

\frac{C ⊢ spec_{1} ⇒ spec′_{1}, E_{1} C + E_{1} ⊢ spec_{2} ⇒ spec′_{2}, E_{2}}{C ⊢ local spec_{1} in spec_{2} end ⇒ local spec′_{1} in spec′_{2} end, E_{2}}  (462)

\frac{C, SE of E of , s ⊢ longid_{1} ⇒ longstrid_{1}, E_{1} ··· C, SE of E of , s ⊢ longid_{n} ⇒ longstrid_{n}, E_{n}}{C ⊢ open longid_{1}···longid_{n} ⇒ open longstrid_{1} ··· longstrid_{n}, E_{1} + ··· + E_{n}}  (463)

\frac{C, G of , g ⊢ id_{1} ⇒ sigid_{1}, E_{1} ··· C, G of , g ⊢ id_{n} ⇒ sigid_{n}, E_{n}}{C ⊢ include id_{1}···id_{n} ⇒ include sigid_{1} ··· sigid_{n}, E_{1} + ··· + E_{n}}  (464)

\overline{C ⊢ ⇒ , \{\} in Env}  (465)

\frac{C ⊢ spec_{1} ⇒ spec′_{1}, E_{1} C + E_{1} ⊢ spec_{2} ⇒ spec′_{2}, E_{2}}{C ⊢ spec_{1} ⟨;⟩ spec_{2} ⇒ spec′_{1} ⟨;⟩ spec′_{2}, E_{1} + E_{2}}  (466)

Value Descriptions  C ⊢ valdesc ⇒ valdesc′, StE
\frac{C ⊢ ty ⇒ ty′ ⟨C ⊢ valdesc ⇒ valdesc′, StE⟩}{C ⊢ id : ty ⟨and valdesc⟩ ⇒ idv : ty′ ⟨and valdesc′⟩, \{id ↦ v\}⟨+StE⟩} (467)

Type Descriptions  C ⊢ typdesc ⇒ typdesc′, TE
\frac{⟨C ⊢ typdesc ⇒ typdesc′, TE⟩}{C ⊢ tyvarseq id ⟨and typdesc⟩ ⇒ tyvarseq idt ⟨and typdesc′⟩, \{id ↦ FAIL\}⟨+TE⟩}  (468)

Datatype Description  C ⊢ datdesc ⇒ datdesc′, E
\frac{C ⊢ condesc ⇒ condesc′, StE  ⟨C ⊢ datdesc ⇒ datdesc′, E⟩}{C ⊢ tyvarseq id = condesc ⟨and datdesc⟩ ⇒ tyvarseq idt = condesc′ ⟨and datdesc′⟩, (\{id ↦ FAIL\}, StE) in Env ⟨+E⟩}  (469)

Constructor Descriptions  C ⊢ condesc ⇒ condesc′, StE
\frac{⟨C ⊢ ty ⇒ ty′⟩ ⟨⟨C ⊢ condesc ⇒ condesc′, StE⟩⟩}{C ⊢ id ⟨of ty⟩ ⟨⟨| condesc⟩⟩ ⇒ idc ⟨of ty′⟩ ⟨⟨| condesc′⟩⟩, \{id ↦ c\}⟨⟨+StE⟩⟩}  (470)

Exception Descriptions  C ⊢ exdesc ⇒ exdesc′, StE
\frac{⟨C ⊢ ty ⇒ ty′⟩ ⟨⟨C ⊢ exdesc ⇒ exdesc′, StE⟩⟩}{C ⊢ id ⟨of ty⟩ ⟨⟨and exdesc⟩⟩ ⇒ ide ⟨of ty′⟩ ⟨⟨and exdesc′⟩⟩, \{id ↦ e\} ⟨⟨+StE⟩⟩}  (471)

Specification Expressions  C ⊢ specexp ⇒ specexp′
\frac{C ⊢ strdec ⇒ strdec′, E  C + E ⊢ axexp ⇒ exp}{C ⊢ let strdec in axexp end ⇒ let strdec′ in exp end}  (472)

\frac{C ⊢ let    in axexp end ⇒ specexp}{C ⊢ axexp ⇒ specexp}  (473)

Axiomatic Expressions  C ⊢ axexp ⇒ exp
\frac{C ⊢ exp^{•} ⇒ exp}{C ⊢ exp^{•} ⇒ exp}  (474)

Structure Descriptions  C ⊢ strdesc ⇒ strdesc′, SE
\frac{C ⊢ sigexp ⇒ sigexp′, E  ⟨C ⊢ strdesc ⇒ strdesc′, SE⟩}{C ⊢ id : sigexp ⟨and strdesc⟩ ⇒ ids : sigexp′ ⟨and strdesc′⟩, \{id ↦ E\} ⟨+SE⟩}  (475)

Functor Declarations  C ⊢ fundec ⇒ fundec′, F
\frac{C ⊢ funbind ⇒ funbind′, F}{C ⊢ functor funbind ⇒ functor funbind′, F}  (476)

\overline{C ⊢ ⇒ , \{\}}  (477)

\frac{C ⊢ fundec_{1} ⇒ fundec′_{1}, F_{1} C + F_{1} ⊢ fundec_{2} ⇒ fundec′_{2}, F_{2}}{C ⊢ fundec_{1} ⟨;⟩ fundec_{2} ⇒ fundec′_{1} ⟨;⟩ fundec′_{2}, F_{1} + F_{2}}  (478)

Functor Bindings  C ⊢ funbind ⇒ funbind′, F

\frac{C, SE of E of , s ⊢ id′′ ⇒ strid, FAIL C ⊢ id ( id′′ : sig spec end ) : id′ = let open id′′ in strexp end ⟨and funbind⟩ ⇒ funbind′, F}{C ⊢ id ( spec ) : id′ = strexp ⟨and funbind⟩ ⇒ funbind′, F}  (479)

\frac{C, SE of E of , s ⊢ id′ ⇒ strid, FAIL C ⊢ id ( id′ : sig spec end ) : sig local open id′ in spec′ end end = let open id′ in strexp end ⟨and funbind⟩ ⇒ funbind′, F}{C ⊢ id ( spec ) : sig spec′ end = strexp ⟨and funbind⟩ ⇒ funbind′, F} (480)

\frac{C, SE of E of , s ⊢ id′′ ⇒ strid, FAIL C ⊢ id ( id′′ : sig spec end ) : id′ = ? ⟨and funbind⟩ ⇒ funbind′, F}{C ⊢ id ( spec ) : id′ = ? ⟨and funbind⟩ ⇒ funbind′, F} (481)

\frac{C, SE of E of , s ⊢ id′ ⇒ strid, FAIL C ⊢ id ( id′ : sig spec end ) : sig local open id′ in spec′ end end = ? ⟨and funbind⟩ ⇒ funbind′, F}{C ⊢ id ( spec ) : sig spec′ end = ? ⟨and funbind⟩ ⇒ funbind′, F} (482)

\frac{C ⊢ psigexp_{1} ⇒ psigexp′_{1}, E_{1} C + (\{id_{2} ↦ E_{1}\} in Env) ⊢ psigexp_{2} ⇒ psigexp′_{2}, E_{2} C + (\{id_{2} ↦ E_{1}\} in Env) ⊢ strexp ⇒ strexp′, E  E ≻ E_{2} ⟨C ⊢ funbind ⇒ funbind′, F ⟩}{C ⊢ id_{1} ( id_{2} : psigexp_{1} ) :psigexp_{2} = strexp ⟨and funbind⟩ ⇒ idf_{1} ( ids_{2} : psigexp′_{1} ) :psigexp′_{2} = strexp′ ⟨and funbind′⟩, \{funid ↦ (E_{1}, E_{2})\} ⟨+F ⟩}  (483)

\frac{C ⊢ psigexp_{1} ⇒ psigexp′_{1}, E_{1} C + (\{id_{2} ↦ E_{1}\} in Env) ⊢ psigexp_{2} ⇒ psigexp′_{2}, E_{2} ⟨C ⊢ funbind ⇒ funbind′, F ⟩}{C ⊢ id_{1} ( id_{2} : psigexp_{1} ) :psigexp_{2} = ? ⟨and funbind⟩ ⇒ idf_{1} ( ids_{2} : psigexp′_{1} ) :psigexp′_{2} = ? ⟨and funbind′⟩, \{funid ↦ (E_{1}, E_{2})\} ⟨+F ⟩}  (484)

Top-level Declarations  C ⊢ topdec ⇒ topdec′, C′
\frac{C ⊢ val it = exp ⇒ topdec, C′}{C ⊢ exp ⇒ topdec, C′}  (485)

\frac{C ⊢ strdec ⇒ strdec′, C′}{C ⊢ strdec ⇒ strdec′, C′}  (486)

\frac{C ⊢ sigdec ⇒ sigdec′, G}{C ⊢ sigdec ⇒ sigdec′, G in Context}  (487)

\frac{C ⊢ fundec ⇒ fundec′, F}{C ⊢ fundec ⇒ fundec′, F in Context}  (488)

C Appendix: The Initial Basis

For the verification of full programs, see rule 349, we have to specify the initial (verification) basis B_{0}, an initial context C_{DER}^{0} for deriving phrases of the Bare language from phrases of the Full language, and an initial (verification) state s_{0}. The subscript “DER” refers to the semantics of derived forms in Appendix B.

C.1 The Initial State

The initial state s_{0} has the form

s_{0} = (BasExName, {}, {}, CT_{0} ∪ ET_{0}, 0, ⊤)

where BasExName can be found in section 6.5 on page 58. CT_{0} and ET_{0} are defined below in figure 27. Setting n of s_{0} to 0 is insignificant; any natural number would do. The reason for this arbitrariness is rule 304, which allows an arbitrary choice of question mark interpretation.

The component l of s_{0} is set to ⊤. This means that structure declarations ignore the actual “implementing” structure.

      CT_{0} = { (true, bool), (false, bool), (nil, ∀'a.'a list),

                 (::, ∀α.{1 ↦ 'a,2 ↦ 'a list} → 'a list) }

ET_{0} = {(excon, exn) | excon ∈ BasExName \ {NoCode, Abuse}}

Figure 27: Initial Value Templates

The set ET_{0} does not contain the corresponding pairs for NoCode and Abuse, because they are not ordinary exceptions. We use the exception mechanism to propagate certain information, but we do not want quantified variables of type exn to range over these special exceptions.

C.2 The Initial Context for Derived Forms

The initial context for the derived forms C_{DER}^{0} has the form

C_{DER}^{0} = ((SE_{DER}, TE_{DER}, StE^{0}), VE_{DER}^{0}, F_{DER}, SE_{DER})

where all components except VE_{DER}^{0} and StE^{0} are the empty map {}. VE_{DER}^{0} is defined in figure 28, StE^{0} in figure 29. The set BasVal is defined in section 6.4, page 58. PredFun is the set containing the identifiers

     o   @   ^map   rev   not

id ↦ (n,fix) condition
o ↦ (3,l)
id ↦ (4,l) id ∈ {=, <>, <, >, <=, >=}
@ ↦ (5,l)
:: ↦ (5,r)
id ↦ (6,l) id ∈ {+, -, ^}
id ↦ (7,l) id ∈ {div, mod, /, *}

Figure 28: Initial Infix Status VE_{DER}^{0}

id ↦ st condition
id ↦ e id ∈ BasExName \ {NoCode}

                id ↦ c id ∈ {true, false,::, nil}

id ↦ v id ∈ BasVal ∪ PredFun

Figure 29: Initial Status Environment StE^{0}

The initial status environment StE^{0} assigns identifier status to all predefined identifiers. Although the status v is the default status for identifiers in the semantics for derived forms, we still have to include value variables in StE^{0}, because the rules in the semantics for derived forms that require the generation of fresh variables take the condition id ∉ Dom StE as an indication of freshness.

146 C APPENDIX: THE INITIAL BASIS

C.3 The Initial Verification Basis

The initial verification basis B_{0} has the form

B_{0} = ((M_{0}, T_{0}), F_{0}, G_{0}, E_{0})

where • M_{0} = ∅

   • T_{0} = {bool, int, real, string, list, exn}

• F_{0} = {}

• G_{0} = {}

• E_{0} = (SE_{0}, TE_{0}, VE_{0})

• SE_{0} = {} All type names in T_{0} have arity 0, except list which has arity 1. All type names in T_{0} except exn admit equality.

The initial type environment TE_{0} is shown in figure 30. The initial variable environment VE_{0} consists of two parts, VE_{0} = VE′_{0} ∪ VE′′_{0} with Dom VE′_{0} = BasVal∪{true, false,::, nil}∪(BasExName\{NoCode, Abuse}) and Dom VE′′_{0} = PredFun. All identifiers id in the domain of VE′_{0} are mapped to typed values tv. The type schemes Stat tv of the predefined identifiers are given in figure 31; the basic exceptions (not listed there) have all type exn.

tycon ↦ { θ,  {con_{1} ↦ σ_{1}, …, con_{n} ↦ σ_{n}} } (n ≥ 0)
unit ↦ { Λ().{}, {} }

    bool ↦ { bool,  {true ↦ bool, false ↦ bool} }
     int ↦ { int,  {} }
    real ↦ { real,  {} }
  string ↦ { string, {} }
    list ↦ { list,  {nil ↦ ∀'a . 'a list,

                       :: ↦ ∀'a .{1 ↦ 'a, 2 ↦ 'a list} → 'a list} }

     exn ↦ { exn,  {} }

Figure 30: Static TE_{0}

NONFIX  INFIX
var ↦ σ  var ↦ σ
map ↦ ∀'a 'b. ('a → 'b) →  Precedence 7 :

         'a list → 'b list       / ↦ real ∗ real → real
rev ↦ ∀'a. 'a list → 'a list  div ↦ int ∗ int → int
not ↦ bool → bool           mod ↦ int ∗ int → int
  ~ ↦ ∀num. num → num          * ↦ ∀num. num ∗ num → num

abs ↦ ∀num. num → num  Precedence 6 :

floor ↦ real → int              + ↦ ∀num. num ∗ num → num
real ↦ int → real              - ↦ ∀num. num ∗ num → num
sqrt ↦ real → real             ^↦ string ∗ string → string

sin ↦ real → real  Precedence 5 :

cos ↦ real → real            :: ↦ ∀'a.'a ∗ 'alist → 'alist
arctan ↦ real → real             @ ↦ ∀'a. 'a list
exp ↦ real → real  ∗ 'a list → 'a list

ln ↦ real → real  Precedence 4 :

size ↦ string → int            = ↦ ∀''a. ''a ∗ ''a → bool
chr ↦ int → string           <> ↦ ∀''a. ''a ∗ ''a → bool
ord ↦ string → int            < ↦ ∀num. num ∗ num → bool
explode ↦ string → string list     > ↦ ∀num. num ∗ num → bool
implode ↦ string list → string    <= ↦ ∀num. num ∗ num → bool
true ↦ bool                   >= ↦ ∀num. num ∗ num → bool

false ↦ bool  Precedence 3 :

nil ↦ ∀'a. 'a list              o ↦ ∀'a 'b 'c. ('b → 'c)
                                       ∗ ('a → 'b) → ('a → 'c)

Notes:

• In type schemes we have taken the liberty of writing ty_{1} ∗ ty_{2} in place of {1 ↦ ty_{1}, 2 ↦ ty_{2}}.

• Recall that the special type variable num can be replaced by either real or int, see Section 4.5.

Figure 31: Static Variable Environment Stat VE_{0} (without exceptions)

C.4 Predefined Functions

Note that Dyn VE′_{0} is the identity function; this is because we have chosen to denote basic values by the names of variables to which they are initially bound. We assume that we can always distinguish basic values from constructors — therefore, the bare identifiers are not values, but these identifiers attributed with their status.

The semantics of these basic values (most of which are functions) lies principally in their behaviour under APPLY, which we describe below.

VE′′_{0} contains initial variable bindings which, unlike BasVal, are definable in ML; it is obtained as follows: the following top declaration topdec is verificated with the program semantics (page 117) in the initial state and basis as s_{0}, B′_{0}, C_{DER}^{0} ⊢ topdec ⇒ B, C′_{DER} where B′_{0} is the same as B_{0} but without VE′′_{0}. B = {(s, B)} is a singleton set with s = s_{0} and we get VE′′_{0} by removing all bindings in VE of E of B′_{0} from VE of E of B.

              fun (F o G)x = F(G x)
              fun nil @ M = M
                | (x::L) @ M = x::(L @ M)
              fun s ^s' = implode((explode s) @ (explode s'))
              fun map F nil = nil
                | map F (x::L) = (F x)::(map F L)
              fun rev nil = nil
                | rev (x::L) = (rev L) @ [x]
              fun not true = false
                | not false = true

We now describe the effect of APPLY upon each value b ∈ BasVal. For special values, we shall normally use i, r, n, s to range over integers, reals, numbers (integer or real), strings respectively. We also take the liberty of abbreviating “APPLY(abs, r)” to “abs(r)”, “APPLY(mod, {1 ↦ i, 2 ↦ d})” to “i mod d”, etc. .

• ~(n) returns the negation of n, or the packet [Neg] if the result is out of range.

• abs(n) returns the absolute value of n, or the packet [Abs] if the result is out of range.

• floor(r) returns the largest integer i not greater than r; it returns the packet [Floor] if i is out of range.

• real(i) returns the real value equal to i.

• sqrt(r) returns the square root of r, or the packet [Sqrt] if r is negative.

• sin(r) , cos(r) return the result of the appropriate trigonometric functions.

• arctan(r) returns the result of the appropriate trigonometric function in the range \underline{+}π/2.

• exp(r) , ln(r) return respectively the exponential and the natural logarithm of r, or an exception packet [Exp] or [Ln] if the result is out of range.

• size(s) returns the number of characters in s.

• chr(i) returns the character numbered i (see Section 2.2) if i is in the interval [0, 255], and the packet [Chr] otherwise.

• ord(s) returns the number of the first character in s (an integer in the interval [0, 255], see Section 2.2), or the packet [Ord] if s is empty.

• explode(s) returns the list of characters (as single-character strings) of which s consists.

• implode(L) returns the string formed by concatenating all members of the list L of strings.

• The arithmetic functions /,*,+,- all return the results of the usual arithmetic operations, or exception packets respectively [Quot], [Prod], [Sum],

[Diff] if the result is undefined or out of range.

• i mod d , i div d return integers r, q (remainder, quotient) determined by the equation d × q + r = i, where either 0 ≤ r < d or d < r ≤ 0. Thus the remainder has the same sign as the divisor d. The packet [Mod] or [Div] is returned if d = 0.

• The order relations <,>,<=,>= return boolean values in accord with their usual meanings.

• v_{1} = v_{2} returns true or false according as the values v_{1} and v_{2} are, or are not, identical. The type discipline (in particular, the fact that function types do not admit equality) ensures that equality is only ever applied to special values, nullary constructors, and values built out of such by record formation and constructor application.

• v_{1} <> v_{2} returns the opposite boolean value to v_{1} = v_{2}.

References

[BHW94] M. Bidoit, R. Hennicker and M. Wirsing. Characterizing behavioural semantics and abstractor semantics. Proc. 5th European Symposium on Programming, Edinburgh. Springer LNCS 788, 105–119 (1994).

[Gol84] R. Goldblatt. Topoi — The Categorical Analysis of Logic. North-Holland (1984).

[Han93] J. Hannan. Extended natural semantics. Journal of Functional Programming, 3(2), 123–152 (1993).

[Kah88] G. Kahn. Natural Semantics. In: K. Fuchi and M. Nivat, editors, Programming of Future Generation Computers, pages 237–258. North-Holland (1988).

[Kah93] S. Kahrs. Mistakes and ambiguities in the definition of Standard ML. Report ECS-LFCS-93-257, Univ. of Edinburgh (1993).

[Kah94] S. Kahrs. Mistakes and ambiguities in the definition of Standard ML – Addenda. Univ. of Edinburgh (1994).

[KST94] S. Kahrs and D. Sannella and A. Tarlecki. The semantics of Extended ML: a gentle introduction. Proc. Workshop on Semantics of Specification Languages, Utrecht, 1993. Springer Workshops in Computing, 186–215 (1994).

[MacQ86] D. MacQueen. Modules for Standard ML. In: R. Harper, D. MacQueen and R. Milner. Standard ML. Report ECS-LFCS-86-2, Univ. of Edinburgh (1986).

[MT91] R. Milner and M. Tofte. Commentary on Standard ML. MIT Press (1991).

[MTH90] R. Milner, M. Tofte and R. Harper. The Definition of Standard ML. MIT Press (1990).

[San90] D. Sannella. Formal program development in Extended ML for the working programmer. Proc. 3rd BCS/FACS Workshop on Refinement, Hursley Park, 1990. Springer Workshops in Computing, 99– 130 (1991).

[ST85] D. Sannella and A. Tarlecki. Program specification and development in Standard ML. Proc. 12th ACM Symp. on Principles of Programming Languages, New Orleans, 67–77 (1985).

[ST86] D. Sannella and A. Tarlecki. Extended ML: an institution-inde-pendent framework for formal program development. Proc. Workshop on Category Theory and Computer Programming, Guildford. Springer LNCS 240, 364–389 (1986).

[ST89] D. Sannella and A. Tarlecki. Toward formal development of ML programs: foundations and methodology. Proc. Joint Conf. on Theory and Practice of Software Development, Barcelona. Springer LNCS 352, 375–389 (1989).

[ST91] D. Sannella and A. Tarlecki. Extended ML: past, present and future. Proc. 7th Workshop on Specification of Abstract Data Types, Wusterhausen. Springer LNCS 534, 297–322 (1991).