Taming Intersection Types
and the Merge Operator

Xuejing Huang

A thesis submitted in partial ful�llment of the requirements forthe degree of Doctor of Philosophy
at The University of Hong KongD����������

I declare that this thesis represents my own work, except where due acknowledgment is made,and that it has not been previously included in a thesis, dissertation or report submitted to this
University or to any other institution for a degree, diploma or other quali�cations.

Xuejing Huang
January 2023

Abstract of thesis entitled“Taming Intersection Types
and the Merge Operator”
Submitted by
Xuejing Huangfor the degree of Doctor of Philosophy
at The University of Hong Kongin January, 2023

For modern programming languages, a systematic approach for establishing usability andreliability is to �rst have a formalized and veri�ed core language guarded by a type system.
This dissertation proposes a type-directed operational semantics (TDOS) approach to model
disjoint intersection types, and studies three calculi _8 , _8+ , and F8+ serving as a new foundation
for Compositional Programming.
Compositional Programming is a recently proposed programming style. Its prototype
language CP supports multiple inheritance in a type-safe way and provides simple solutions
to modularity problems that are hard for conventional object-oriented programming andfunctional programming languages. At the core of CP is F8+ , a polymorphic calculus that
supports a symmetric merge operator with subtyping. The merge operator generalizes record
concatenation to any type, enabling expressive forms of object composition.
Due to its �exibility and ambiguity, the merge operator lacks a satisfying direct operationalsemantics. Prior systems usually de�ne the runtime semantics indirectly by elaborating thesource expressions into a target language. In contrast, the TDOS approach gives a semantics toF8+ directly. Besides being deterministic and type sound, the new calculus supports additionalfeatures such as recursion and impredicative polymorphism.
As an essential part of the TDOS design, we show a novel algorithm for the subtyping ofintersection types with distributive laws. In this formulation, types that decompose into two
smaller parts are characterized by splittable types. This allows a simple proof of transitivity andthe modular addition of distributivity rules without pre-processing on types. We then extend
this idea to union types and present an algorithmic formulation of subtyping based on theminimal relevant logic B+. (268 words)

A���������������

I would like to express my deepest gratitude to my supervisor Bruno C. d. S. Oliveira, for his
advice, insights, and patience. I almost knew nothing about programming language theory
before I met Bruno and it was him taught me where to start and how to do research. Bruno
always encourages me when we meet problems and he is open to di�erent opinions. I reallyenjoy discussing and brainstorming with him and I am grateful to all the guidance he gave me.
I also want to thank my thesis advisory committee and examination committee, especiallyProf. Frank Pfenning and Prof. Ondřej Lhoták, for providing valuable feedback and suggestions.
Additionally, this endeavor would not have been possible without the contribution frommy coauthors: Jinxu Zhao, Andong Fan, Han Xu, and Yaozhu Sun. Special thanks to Weixin
Zhang and Yaozhu Sun for developing the CP language, and João Alpuim, Zhiyuan Shi, Xuan
Bi, Ningning Xie for their previous work on disjoint intersection types. I would like to extend
my sincere thanks to Baber Rehman, Wenjia Ye, Nick Rioux, and Steve Zdancewic. It is mypleasure to collaborate with you.
Thanks should also go to other people I have been working with in the HKU PL Group:
Tomas Tauber, Huang Li, Haoyuan Zhang, Yanlin Wang, Yanpeng Yang, Mingqi Xue, Xu Xue,
Chen Cui, Jinhao Tan, Shengyi Jiang, Yaoda Zhou, and Litao Zhou. I have received a lot of
feedback and learnt a great deal through our group seminars.
I would like to thank people in the PL community, which is not big, but very warm, including
the anonymous reviewers and readers of our papers, and many lovely people I met in OPLSS
2017, the beginning of my journey in PL research.
I thank my parents and everyone in my family for their support, including our beloved cat
Xiaohei who passed away before the beginning of 2023.
Especially, I thank my boyfriend Bingchen Gong, for his love, encouragement, and patience.
Thank you for always being here by my side.
Last several years were very hard, for Hong Kong, and for the world. Through it all, we
remain hopeful, and will be more brave. “If there is no struggle, there is no progress.”C�������

1 Introduction
1.1 Motivations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1
1
4

2 Background
2.1 Intersection Type Discipline and BCD-Subtyping . . . . . . . . . . . . . . . .
2.2 The Merge Operator and Dun�eld’s Semantics . . . . . . . . . . . . . . . . . .
2.3 The Information Hiding Problem in Subtyping . . . . . . . . . . . . . . . . . .
2.4 Disjoint Intersection Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.4.1 Disjointness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.4.2 Calculi with Disjoint Intersection Types . . . . . . . . . . . . . . . . .
2.5 Application of the Merge Operator: CP Examples . . . . . . . . . . . . . . . .
2.5.1 Typed First-Class Traits . . . . . . . . . . . . . . . . . . . . . . . . . .
2.5.2 Expression Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . .

9
10
12
13
15
16
17
18
18
20

I Distributive Subtyping27

3 Developing Subtyping Algorithms for Intersection Types with Distributivity 29
3.1 Background: Transitivity Elimination . . . . . . . . . . . . . . . . . . . . . . . 30
3.1.1 Conventional Subtyping with Intersection Types . . . . . . . . . . . . 30
3.1.2 Adding Distributivity: the Simple Approach to Transitivity Elimination
Fails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.2 A Simple and Modular Formulation of BCD with Splittable Types . . . . . . . 33
3.2.1 Modularity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3.3 Metatheory of Modular BCD . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.4 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4 Subtyping with Union Types
4.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2 Subtyping based on Minimal Relevant Logic . . . . . . . . . . . . . . . . . . .

41
41
42

4.3

4.4

4.2.1 Declarative subtyping . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2.2 Algorithmic Subtyping: Adding Union Types and More Distributivity .
Duotyping Based on Minimal Relevant Logic . . . . . . . . . . . . . . . . . . .
4.3.1 Declarative Duotyping . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3.2 Algorithmic Duotyping . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3.3 Metatheory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3.4 Coq Formalization and Proof Statistics . . . . . . . . . . . . . . . . . .
A Functional Implementation in Haskell . . . . . . . . . . . . . . . . . . . . .
4.4.1 Abstract Syntax and Modes . . . . . . . . . . . . . . . . . . . . . . . .
4.4.2 Type Splitting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.4.3 Duotyping and Subtyping . . . . . . . . . . . . . . . . . . . . . . . . .
4.4.4 Eliminating Backtracking . . . . . . . . . . . . . . . . . . . . . . . . .

42
44
48
49
50
54
56
57
57
58
58
59

II Calculi with the Merge Operator

61

5 The Basic System: _8 and its Type-Directed Operational Semantics
5.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.1.1 A Type-Driven Semantics for Type Preservation . . . . . . . . . . . . .
5.1.2 The Challenges of Functions . . . . . . . . . . . . . . . . . . . . . . . .
5.1.3 Disjoint Intersection Types and Consistency for Determinism . . . . .
5.2 Syntax, Subtyping and Typing . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2.1 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2.2 Subtyping and Disjointness . . . . . . . . . . . . . . . . . . . . . . . .
5.2.3 Bidirectional Typing . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.3 A Type-Directed Operational Semantics for _8 . . . . . . . . . . . . . . . . . .
5.3.1 Casting of Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.3.2 Consistency, Determinism and Type Soundness of Casting . . . . . . .
5.3.3 Reduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

63
63
63
66
67
69
69
70
71
74
74
76
79

6 The Nested Composition Calculus _8+
6.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.2 Syntax and Typing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.3 Operational Semantics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.4 Metatheory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.4.1 Completeness of the type system with respect to the original _8+ '18 (orNeColus) calculus. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.4.2 Properties of the TDOS. . . . . . . . . . . . . . . . . . . . . . . . . . .

81
81
84
88
92
92
93

7 The F8+ Calculus with Disjoint Polymophism
7.1 Motivations and Technical Innovations . . . . . . . . . . . . . . . . . . . . . .
7.1.1 Elaborating CP to F8+ . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.1.2 The Gap Between Theory and Practice . . . . . . . . . . . . . . . . . .
7.1.3 Technical Challenges and Innovations . . . . . . . . . . . . . . . . . .
7.2 The F8+ Calculus and Its Operational Semantics . . . . . . . . . . . . . . . . . .
7.2.1 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.2.2 Subtyping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.2.3 Bidirectional Typing . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.2.4 Small-Step Operational Semantics . . . . . . . . . . . . . . . . . . . . .
7.3 Algorithmics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.3.1 Algorithmic Subtyping . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.3.2 Disjointness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.3.3 Consistency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.4 Type Soundness and Determinism . . . . . . . . . . . . . . . . . . . . . . . . .
7.4.1 Determinism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.4.2 Progress . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.4.3 Preservation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

95
95
95
97
99
100
100
101
104
107
111
111
114
115
115
116
116
117

8 Discussion and Related work
123
8.1 Discussion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
8.1.1 TDOS versus an Elaboration Semantics . . . . . . . . . . . . . . . . . . 123
8.1.2 Implementation considerations . . . . . . . . . . . . . . . . . . . . . . 126
8.2 Formal Relations to Existing Calculi . . . . . . . . . . . . . . . . . . . . . . . . 128
8.2.1 Completeness of _8 with Respect to the Original Type System . . . . . 128
8.2.2 Soundness of _8 with respect to Dun�eld’s Operational Semantics . . . 130
8.3 Calculi with the Merge Operator . . . . . . . . . . . . . . . . . . . . . . . . . . 131
8.3.1 Calculi with the merge operator and a direct semantics . . . . . . . . . 131
8.3.2 Calculi with a Merge Operator and an Elaboration Semantics . . . . . 132
8.4 Record Calculi with Record Concatenation and Subtyping . . . . . . . . . . . 134
8.5 Languages and Calculi with a Type-Dependent Semantics . . . . . . . . . . . . 136
8.6 OOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
8.6.1 Dealing with Con�icts in OOP . . . . . . . . . . . . . . . . . . . . . . 137
8.7 Subtyping Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
8.7.1 BCD Subtyping Algorithms . . . . . . . . . . . . . . . . . . . . . . . . 139
8.8 Other Problems in Calculi with Intersection and Union Types . . . . . . . . . 141

9 Conclusions and Future work
143
9.1 Future Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
9.1.1 Mutable References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
9.1.2 Unannotated Lambda Functions . . . . . . . . . . . . . . . . . . . . . . 148
9.1.3 Lazy merges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150

CHAPTER 1

I�����������
A programming language does not only serves as a bridge between human and machines, butalso plays a key role for programmers to communicate and to organize their own ideas. While
natural languages can be ambiguous, programming languages are supposed to be well-de�ned
and have a clear interpretation. For execution, we want programs to always behave as expected,
and do not cause errors. A runtime error could be fatal as all immediate computation results will
be lost and the program stops to provide service. For coding, we like languages with intuitive
notations, supporting concise and reusable programs. Types provide abstraction, and helpclassify various data and regulate programs. For example, by specifying the addition function
only takes two integers, a language can prevent users to add a integer to a character in before
running the program, for which the expected behavior is unclear. Or, in a object-oriented
programming language, users can group a sort of data (objects) by characterizing their common
properties in the class de�nition, and be free to forget the implementation details when using
the class. For modern programming languages, a systematic approach to establishing theusability and reliability is to have a formalized and veri�ed core language guarded by a typesystem. Such a type system handles the interaction of all features in one language, making surethey do not con�ict, and guarantees the safety of programs, like the famous slogan “well-typed
programs cannot go wrong" [Mil78].
In this dissertation, we focus on the core calculus of programming languages, including
type systems, operational semantics, subtyping and related algorithms, towards a type-safeand modular programming language.

1.1

Motivations

Terms are characterized by types. On the other hand, types can be interpreted as a set of terms
that inhabit it. In some systems, one term can have multiple types, and some of the sets oftypes are fully contained by another set. Usually, it is the set inclusion relation that de�nes the1subtyping relation among types. Compared with its supertype, a subtype includes less terms
and therefore captures the properties of its inhabited terms more precisely. Any term that canbe typed by a subtype can also be typed by the supertype. Thus it is always “better” to use asubtype to type a term when it is possible.
Some work on type systems focuses on enhancing the expressiveness of types. With
universal quanti�ed types, parametric polymorphism [Gir72; Rey74] can assign the most
speci�c type to the identity function _x. x : 8U . U ! U. With intersection types, as a formof �nitary polymorphism, the same function can have type (Int ! Int) & (Bool ! Bool), or(Pos ! Pos) & (Neg ! Neg) which is a re�nement of Int ! Int. (Here Pos and Neg stands for
positive integers and negative integers). When types carry more information, some previously
ill-typed terms become well-typed. For example, the intersection type discipline accepts all
normalizing terms, including (_x. x x) (_x. x), which can also be typed with universal quanti�ed
types.
On the other hand, ad hoc polymorphism, or overloading, allows one name (usually afunction) to be associated with multiple implementations of di�erent types. This feature canbe encoded by a merge construct [CGL95]. A merge operator [Rey88] composes expressions,and the aggregated expression can directly behave like a sub-expression without destructors,
as shown in the following program:let x : Int & Bool = 1 ,, true in (x + 1, not x)
Here ,, stands for the merge operator while , is used to construct pairs. The variable x has theintersection type Int & Bool. Later uses of x can treat it either as an integer or as a Boolean. For
this example, the executing result is the pair (2, false). Note that in an intersection type systemwith conventional terms, Int & Bool is uninhabited, so is (A ! A) & (A ! A ! A). Because
the two parts of the intersection share no common normal forms. With such a construct thatmerges computationally di�erent terms, these two types become inhabited.
There are various practical applications for the merge operator. As Dun�eld argues, themerge operator provides “general mechanisms that subsume many di�erent features” [Dun14].
Besides overloading, merges of single-�eld records can encode multi-�eld records, and mergesof functions can be used as an elimination construct of union types. Furthermore, when we
restrict our attention to the concatenation of records, which the merge operator generalizes, thecombination of record concatenation and subtyping paves the ground for encoding expressive
forms of multiple inheritance [Wan89; Rém95; PZ04; Zwa97].
More recently, the merge operator has been used in calculi with disjoint intersection
types [OSA16]. The disjointness restriction means that the two values being merged havedistinct types. Such a variant of the symmetric merge operator has been used to encode several
non-trivial object-oriented features, which enable highly dynamic forms of object composition
that are not available in current mainstream languages such as Scala or Java. These include2�rst-class traits [BO18], dynamic mixins [AOS17], and forms of family polymorphism [BOS18].
These features enable widely used and expressive techniques for object composition used by
JavaScript programmers (and programmers in other dynamically typed languages), but in acompletely statically type-safe manner. Following is an example of �rst-class traits in the CP
language [ZSO21], which is based on disjoint intersection types.
// addId takes a trait as an argument, and returns another trait
addId (base : Trait<Person>) (idNumber : Int) =trait [self : Person] inherits base ) {// dynamically inheriting from an unknown person
id = idNumber};

Similarly to classes in JavaScript, �rst-class traits can be passed as arguments, returned as
results, and can be constructed dynamically (at run-time). In the program above inheritance is
encoded as a merge in the core language used by CP.
Despite over 30 years of research, the semantics of the merge operator has proved to be quite
elusive. This is perhaps not too surprising. It is well-known that, in the closely related area ofrecord calculi, the combination of record concatenation and subtyping is non-trivial [CM91].
Since the merge operator for intersection types generalizes record concatenation and calculi
with intersection types naturally give rise to subtyping, the semantics of the merge operator
will clearly face similar problems that appear in record calculi with subtyping.
Because of its pervasive importance, we would expect a simple and clear direct semantics
for calculi with a merge operator. After all, this is what we get for other foundational calculi
such as the simply-typed lambda calculus, System , System l , the calculus of constructions,
System <: , Featherweight Java and others. While for the merge operator there have been e�orts
in the past to de�ne direct operational semantics, these e�orts have placed severe limitations
that disallow many of the previously discussed applications or they lacked important properties.
Reynolds was the �rst to look at this problem, but in his calculus the merge operator is severely
limited [Rey91]. Castagna, Ghelli, and Longo studied another calculus, where only mergesof functions are possible [CGL95]. Pierce was the �rst to brie�y consider a calculus with anunrestricted merge operator (called glue in his work) [Pie91]. He discussed an extension to^ with a merge operator but he did not study the dynamic semantics with the extension.
Finally, Dun�eld goes further and presents a direct operational semantics for a calculus withan unrestricted merge operator [Dun14]. However, the problem is that subject reduction anddeterminism are lost.
Dun�eld also presents an alternative way to give the semantics for a calculus with the merge
operator indirectly by elaboration to another calculus. This elaboration semantics is type-safeand o�ers a reasonable implementation strategy, and it is also employed in more recent workon the merge operator with disjoint intersection types. However, the elaboration semantics

3

has two major drawbacks. Firstly, reasoning about the elaboration semantics is more involved:
to understand the semantics of programs with the merge operator we have to understandthe translation and semantics of the target calculus. This complicates informal and formal
reasoning. Secondly, in calculi de�ned by elaboration, we want to have coherence [Rey91],
which is a property that ensures that the meaning of a program is not ambiguous. Dun�eld’s
elaboration semantics is not coherent. To �x this, calculi with disjoint intersection types haveto impose some restrictions. However, even with such restrictions, coherence comes at a highprice: the calculi and proof techniques employed to prove coherence are complex, and can only
deal with terminating programs. The latter is a severe limitation in practice!

1.2

Overview

Mainly, this dissertation address two problems:• Finding algorithmic subtyping formulations with distributivity rules• Designing a type-directed operational semantics for calculi with the merge operator
Our focus This dissertation proposes a type-directed operational semantics (TDOS) for calculi
with intersection types and a merge operator. Our calculi address two key di�culties in the
dynamic semantics of calculi with a merge operator. The �rst di�culty is the type-dependent
nature of the merge operator. Using type annotations as casts to guide reduction addresses
this di�culty, and paves the way to prove type soundness. The second di�culty is that a fully
unrestricted merge operator is inherently ambiguous. For instance the merge 1 ,, 2 can evaluate
to both 1 and 2. To obtain a deterministic reduction semantics, our type systems employ adisjointness restriction that is used in calculi using disjoint intersection types, and a new notion
consistency, which relaxes the restriction on merges.
In the core of our reduction is the casting of terms. Our casting rules mirror the structureof subtyping de�nition. That is because casts correspond to coercions in the elaboration
semantics, which are generated by subtyping derivation. While coercions are conversion
functions, the reduction rules of casting directly convert terms. As we want the reduction
rules to be executable, the corresponding subtyping formulation has to be algorithmic. Besides,
one subtyping judgment can generate di�erent coercions because it has multiple derivations.
To ensure the elaboration semantics is unambiguous, the coherence property requires thatthe elaboration results of the same term are always equivalent, even when they containdi�erent coercions. Determinism in TDOS o�ers the same guarantee that coherence o�ers inan elaboration semantics. We will show that when two casting rules overlap, for which case in
the subtyping two di�erent coercions can be produced, the resulting term is unique. As a result,4the TDOS approach deals with recursion and impredicative polymorphism in a straightforwardway.
This thesis has two parts. One focus is to formulate subtyping with intersection and union
types in an algorithmic style. The other is to design calculi that support intersection types andthe merge operator. We will start from the subtyping algorithms and then talk about threecalculi: _8 , a minimal calculus with the merge operator and a deterministic direct operationalsemantics. _8+ , which extends _8 by BCD-style distributive subtyping rules, and also adds
support for record types and nested composition. F8+ , which extends _8+ by disjoint polymophism.
The subtyping relation in _8 is relatively simple while _8+ and _8+ make use of our algorithmic
formulation of subtyping.
Our calculi follow the idea of disjoint intersection types [OSA16; BOS18; Bi+19]. They
are based on the existing work: _8 of [OSA16], _8+ of Bi, Oliveira, and Schrijvers, and F8+ of
Bi et al. While our calculi share similar type systems with these calculi, we are the �rst to
employ the direct operational semantics approach to disjoint intersection types. Previous
calculi use the framework proposed by Dun�eld where the semantics is de�ned by elaboration.
In the elaboration semantics, terms in the source language are translated into a standard target
language via the typing derivation. A coercion is produced by each subtyping derivation to
help converting terms. A key property in such system is to show that all coercions of thesame subtyping judgment produce coherent results. It, then causes di�culty on the proof of
coherence. With the previous proof approach, some restrictions are needed in the systems: No
recursion, no impredicative polymorphism.
Summary of contributions In summary, the contributions of this thesis are as follows:• A novel algorithmic formulation of subtyping relations for intersection andunion types with distributivity: By generalizing the conjunction and disjunction
introduction rule in subtyping, our formulation embeds the challenging distributivity
rules in a modular way and eliminates the transitivity rule to obtain algorithmic properties.
We present two formulations that are sound and complete to the original BCD subtyping
and the subtyping based on B+ logic respectively.
• The _8 , _8+ , and F8+ calculi and their TDOS: We propose a type-directed operationalsemantics for calculi with intersection types and a merge operator, where type annotations are interpreted as casts. For each of the three calculi, we show the reduction isdeterministic and prove the type soundness property.
• Support for non-terminating programs and impredicative polymorphism: With adirect operational semantics, our proof methods can deal with recursion and impredicative
polymorphism, while the prior calculi with disjoint intersection types do not support
them due to limitations of the proof approaches for coherence.
5• Casting and consistency: We propose the reduction rules of casting and the notion of
consistency, which are useful to obtain determinism and type soundness.
• Coq formalization: All the results presented in this paper have been formalized in the
Coq theorem prover. The proofs for Chapter 3 and Chapter 4 can be found at https://github.com/XSnow/DistributingTypes. The proofs for Chapter 5 and Chapter 6
can be found at https://github.com/XSnow/TamingMerge. The proofs for Chapter 7
can be found at https://github.com/XSnow/CP-Foundations.
Roadmap The structure of the thesis is as follows:
Chapter 2 is about background of intersection types and the merge operator, including thehistory and applications of disjoint intersection types.
The following technical sections are divided into two parts.
The �rst part of the technical sections studies subtyping algorithms.
Chapter 3 focus on the subtyping of intersection types. Especially, it shows how weeliminate the transitivity rule to obtain algorithmic formulations.
Chapter 4 extends the discussion to union types. None of the three calculi supports union
types. So this part can be ignored for readers who want to focus on the development of thesecalculi.
The second part utilizes the algorithmic formulation of subtyping in three calculi.
Chapter 5, Chapter 6, and Chapter 7 presents the _8 calculus, _8+ calculus, and F8+ calculus
respectively.
Chapter 8 reviews related work. We compare _8 with the calculi proposed by Dun�eld andOliveira, Shi, and Alpuim (the original _8 calculus). In short, all programs that are accepted by
the original _8 calculus can type-check with our type system, and the semantics of _8 is soundwith respect to Dun�eld’s semantics.
Chapter 9 discusses some potential directions for future work.
Prior publications This thesis is based on these previously published papers:• Xuejing Huang, and Bruno C. d. S. Oliveira. 2020. “A Type-Directed Operational Semantics for a Calculus with a Merge Operator”. In European Conference on Object-Oriented
Programming (ECOOP).
• Xuejing Huang, Jinxu Zhao, and Bruno C. d. S. Oliveira. 2021. “Taming the Merge
Operator”. In Journal of Functional Programming (JFP).
• Xuejing Huang, and Bruno C. d. S. Oliveira. 2021. “Distributing Intersection and Union
Types with Splits and Duality (Functional Pearl)”. 2021. In ACM SIGPLAN International
Conference on Functional Programming (ICFP).

6

• Andong Fan*, Xuejing Huang*, Han Xu, Yaozhu Sun, and Bruno C. d. S. Oliveira. “Direct
Foundations for Compositional Programming”. 2022. In European Conference on ObjectOriented Programming (ECOOP). (Co-�rst authors)78CHAPTER 2

B���������
Intersection types have been studied since the 1970s. Saying that a term has an intersection
type A & B means it has both type A and type B. In the beginning, they were introduced
to type systems as a correspondence of conjunction. While intersection types enhance theexpressiveness of types, and help characterize all normalizing terms [CD78; Pot80; BCD83],
they do not correspond to conjunction from the view of propositions as types [How80], i.e. theprovability of propositions correspond to the inhabitation of types. The conjunction of two
provable propositions are always provable. But the intersection of two inhabited types is notinhabited unless there exists some term that belongs to both types. Compared with producttypes, which are thought to be the correspondence of conjunction, the two propositions in anintersection type must be proved by the same program, rather than two programs embedded
in a pair.
The term-level construct of intersection, merge operator, was later proposed for the imperative language Forsythe [Rey88]. A key advantage of the merge operator is its generality
and the ability to model various programming language features. However, it poses signi�cantchallenges to type system and semantics design. In this chapter, we brie�y review some related
work for background information:• Section 2.1 is about the early history of intersection types. It aims to provide justi�cation
for intersection subtyping.
• Section 2.2 shows the merge operator and its non-deterministic semantics proposedby Dun�eld [Dun14].
• Section 2.3 discuss the information hiding problem in subtyping.
• Section 2.4 presents the disjoint restriction that rejects ambiguous merges proposed
by Oliveira, Shi, and Alpuim [OSA16].

9• Section 2.5 demonstrates some language features encoded via the merge operators in a
Compositional Programming language.

2.1

Intersection Type Discipline and BCD-Subtyping

Following types à la Curry [CF58], lambda abstractions do not come with annotations, therefore
a function can have di�erent types.
, x :A ` e : B` _x. e : A ! B!�����

Curry’s system has the principal typing property: for any typeable term, a best type can befound, from which all the types that are assignable to the term can be generated. Commonly,
the betterness makes a partial order of types. That is the subtyping relation, written as A 6 B.
The subtype A is more speci�c and contains more information, while the supertype B is moregeneral and have more terms inhabited. In a type system with subtyping, the principal type ofa term is a subtype of any type that is assignable to it.
In this system, every typeable term is guaranteed to reduce to a normal form. But thereverse does not hold. In other words, types are preserved in reduction but not in expansion.
The type assignment system is conservative and rejects some strongly normalizing terms. A
typical example is the self application function:_x. x xThe variable x needs to have a function type in its �rst occurrence and an argument type
in its second occurrence. To better describe such polymorphism and capture these strongly
normalizing terms that cannot be accepted by previously existing systems, started from the1970s, multiple researchers, including Coppo, Dezani-Ciancaglini, Sallé, Pottinger, Venneri,and Barendregt, extended Curry’s system with intersection types, a new kind of type [CD80;
CDV81; CDS79; CDV80; Pot80; BCD83]. They gave the introduction and elimination rules forintersection types as follows.
`e:A

`e:B

` e : A&B

& �����

` e : A&B
`e:A

& ������

` e : A&B
`e:B

& ������

The previous self application term now has type A & (A ! B) ! B.
Note that we use & as the binary constructor for intersection type (and | for union type).
We follow the convention that intersections have higher precedence than arrows.

10

A, B, C ::= A | > | A ! B | A & B

)~?4
A6B

(Declarative BCD Subtyping)OS������

OS�����

A6B

A6A
OS����

A6B

B6C

A6C
A6C

A 6 B&C

OS����

OS����A��

A6>

>6>!>

OS����

B1 6 A1A2 6 B2

A1 ! A2 6 B1 ! B2

OS�����

OS�����

OS�����A��

A&B 6 A

A&B 6 B

(A ! B) & (A ! C) 6 A ! B & C

Figure 2.1: The BCD-subtyping with intersections and distributivity.

Such a system type checks all strongly normalizing terms. But it is then too powerful for
its type inference to be decidable.
A subtyping relation is later introduced by Barendregt, Coppo, and Dezani-Ciancagliniwith a more enhanced type assignment system [BCD83], shown in Figure 2.1. A denotes a
countable set of type atoms, and > is the universal type, which is the top element in subtyping.
Rules OS����, OS�����, and OS����� correspond to the introduction and elimination
typing rules for intersection types. Together they axiomatize that A & B is the greatest lower
bound of A and B. OS�����A�� is its signature rule. It states that arrow distributes overintersection. The rule OS����A�� is also interesting: in combination with the transitivity rule,
it makes > 6 A ! > admissible. With BCD subtyping, we can further justify the property> 6 A ! > by the distributivity rule (extended to multiple components):(A ! B1 ) & (A ! B2 ) & ... & (A ! Bn ) 6 A ! B1 & B2 & ... & Bn
The > type is commonly treated as an intersection of zero types. Therefore, when = = 0, theabove subtyping judgment becomes > 6 A ! >.
Two types can also be considered equivalent when they are subtypes of each other. In thiscase, we write A ⌘ B. For example, Int ⌘ Int & Int and Int & Bool ⌘ Bool & Int.
De�nition 2.1 (Type Equivalence). A ⌘ B , A 6 B and B 6 A.
Strictly speaking, the subtyping of intersection types is a preorder on types since equivalent
but syntactically di�erent types exist. But if we divide types into equivalence classes, thesubtyping can can be considered as a partial order relation.

11

2.2

The Merge Operator and Dun�eld’s Semantics

The merge operator for intersection types was �rstly introduced by Reynolds in the Forsythelanguage over 30 years ago [Rey88]. It takes two terms e1 and e2 of some types A and B, tocreate a new term e1 ,, e2 that can behave both as a term of type A and as a term of type B. It has
since been studied, re�ned and used in some language designs by multiple researchers [Pie91;
CGL95; Dun14; OSA16].
let x : Int & Bool = 1 ,, true in (x + 1, not x)

let x : (Int , Bool) = (1 , true) in (fst x + 1 , not (snd x))
The term-level construct makes intersection types very similar to product types. For instance,
the above two programs behave identically. We use (e1 , e2 ) for products and (A , B) forthe product type. The major di�erence between the two programs is that the elimination of
products is explicit. Projections are used to extract the inner component with its location
speci�ed: fst (or proj1 ) takes the �rst one while snd (or proj2 ) takes the second one.
In contrast, the extraction of values from merges is implicit. As demonstrated by the above
program, it is often driven by the types of the terms. But terms can have the same type. A key
problem with the merge operator is ambiguity. For instance, for the expression:(1 ,, 2) + 3
the result is ambiguous (it could be 4 or 5) since we could extract either 1 or 2 from the merge
to add to 3.
In a biased setting, one side of the merge has higher priority than the other side. For
example, in Reynolds’s merge, if there are multiple functions, the rightmost one overrides
others. Dun�eld proposed an unbiased merging construct to better align intersection types withlogical conjunction [Dun14]. On top of the previously shown three typing rules for intersection
types, she added the following two rules for merges.
` e1 : A` e1 ,, e2 : A�������

` e2 : A` e1 ,, e2 : A�������

Although no intersection type is directly involved in these two rules, with the help of theintroduction rule of intersection, merge can have an intersection type. This unbiased merge
operator has a �exible behavior, as de�ned by Dun�eld.
e1
e1 ,, e2e10e10 ,, e2e2e1 ,, e2e20
e1 ,, e20

e1 ,, e212e1

e1 ,, e2e2ee ,, eThere is no evaluation priority between the two components in a merge. Besides, e1 ,, e2(including values) can step, to its left subexpression or the right one. Other values can stepfurther as well, by the last rule, which allows any expression to split into two. As Dun�eld
noted, the operational semantics is nondeterministic and does not preserve types.
Problem 1: no subject reduction. Since the reduction is oblivious of types, a term canreduce to two terms with potentially di�erent (and unrelated) types. For instance:
1 ,, true1

1 ,, true

true

In Dun�eld’s calculus the term 1 ,, true can have multiple types, including Int or Bool or
Int & Bool or Bool & Int. Not all types that can be assigned to a term lead to type-preserving
reductions. For instance, if the term is given the type Int, then the second reduction above
does not preserve the type. What is worse, a well-typed expression can reduce to an ill-typed
expression by dropping the wrong part:(1 ,, _x. x + 1) 2

12

Problem 2: non-determinism. The choice between a merge always has two options. Evenin type-preserving reductions, a reduced term can lead to two other terms of the same typewith di�erent meanings.
1 ,, 2
1
1 ,, 2
2
There is even a third option to duplicate the whole merge:
1 ,, 2(1 ,, 2) ,, (1 ,, 2)In other words, the semantics is non-deterministic.
Dun�eld’s system uses elaboration typing to translate merges to products and insert projections. The elaboration semantics, although is type-safe, also su�ers from this issue. The merge
1 ,, 2 can elaborate to 1 or 2 when checked against Int by the typing rules. Her implementation
prioritizes the left part, resulting in a biased merge operator.

2.3

The Information Hiding Problem in Subtyping

The complications of subtyping. An intuition behind subtyping is that a subtype provides
more information for reasoning about a term. Then, naturally, we expect any term of asubtype can be safely used as a term of its supertype, which is called the principle of safe
substitution [Pie02]. The following subsumption rule, commonly seen in type systems with
subtyping, supports this principle.
13

`e:A

A <: B`e:B�����������

However, subtyping and the subsumption rule enable a program to “forget” about somestatic information about the types of values. Since the extraction of values from merges is
type-directed, such loss of type information can a�ect the search for the value. Consider thefollowing program:let x : Bool = true ,, 1 in (2 ,, x) + 3
Note that here we view true ,, 1 as a value. The merge has type Bool & Int, but because of
subtyping it also has type Bool, the type for G. In a naive operational semantics, for the program
above, we would eventually reach a point where we would need to extract a value from themerge 2 ,, true ,, 1. This merge has two con�icting integers values.
In a language employing a disjointness restriction the merge 2 ,, true ,, 1 ought to be rejected,
but such a merge only appears at run-time. In the program itself all merges are disjoint: true ,, 1
is disjoint; and 2 ,, x is also disjoint since x has type Bool. Thus the program should type-check!
One possibility would be to abort the program at run-time with a disjointness error. However,this would defeat the main purpose of the disjointness restriction, which is to provide a way tostatically prevent ambiguity.
A language o�ering an asymmetric merge operator would have other issues. Assumingthat the merge operator would be right-biased (giving preference to the values on the rightside), then a programmer may expect that because G has type Bool, (2 ,, x) + 3 should evaluate
to 5. However such static reasoning is not synchronized with the run-time behavior, since G
contains the integer 1 and therefore the result of the evaluation would be 4.
From another perspective, we could expect that a valid optimization of the program above
is to replace the expression (2 ,, x) + 3 by 2 + 3, since the static type of G has no integer type.
This optimization would be valid (for both symmetric and asymmetric merges) if the origin of
runtime values can be determined statically by looking at the types. However this is not thecase if we simply employ a naive semantics: we statically know that the merge contains an
integer 2, but at runtime 1 is extracted instead.
Note that the disjointness constraint assumes the type we know is complete: a term of type
Bool does not contain Int. But this is not true if we can directly use true ,, 1 when the context
expects a Bool. This is to say, we cannot have the principle of safe substitution, which is basedon the inclusive semantics of subtyping: a subtype is a subset of its supertype, when considering
types as sets of all inhabited values. Reynolds proposed the coercive semantics [Rey88] thatinterprets subtyping as implicit conversions. His type system still has the subsumption rule, but
the meaning of a program depends on its typing derivation and it is unambiguous. Although his

14system has an asymmetric merge operator, the idea of using subtyping to generate coercions
and de�ning the semantics of programs with the access of typing derivation inspires later workon the merge operator.
Record concatenation and subtyping. The problems with the merge operator and subtyping are closely related to the problem of typing record concatenation in the presence ofsubtyping. The latter is well-acknowledged to be a di�cult problem in the design of record
calculi [CM91]. Foundational work on programming languages in the end of the 80s and theearly 90s looked at this problem because the combination record concatenation with subtyping
was perceived as a way to extend lambda calculi with support for OOP. In essence, since
objects in OOP can be viewed as records, it is natural to look for a language that supports
records. Furthermore, record concatenation would provide support for encoding multiple
inheritance, which entails composing several objects/records together. Finally, subtyping isperceived as a key feature of OOP and should be supported as well. Unfortunately, the problem
was found to be quite challenging, for very similar reasons to those that make the interactionof the merge operator with subtyping di�cult. This should not come as a surprise, since themerge operator can generalize record concatenation. To see the relationship between the two
problems, consider the following variant of the previous program with records:
let x : {l : Bool} = {m = 1} ,, {l = true} in ({m = 2} ,, x).m + 3
In this variant, G is a record with the static type {l : Bool}, but having an extra �eld < that is
hidden by subtyping. The record G is then merged with the record {m = 2}. Statically thismerge seems safe, since the static types of both records do not share record labels in common.
However, when doing the �eld lookup for < at runtime there would be two �elds < withdi�erent values (once again assuming a naive semantics). In essence, we would have the sameproblems as with the earlier variant of the program without records.

2.4

Disjoint Intersection Types

Ideally, components of a merge are commutative. They cannot be selected via tags or locations.
But this does not mean there is no information for the elimination of merges. For example,
since the context [·] + 3 expects an integer and 1 is the only integer part in 1 ,, true, there is
no ambiguity for (1 ,, true) + 3 evaluates to 4. That is to say, the ill-typed possibility true + 3
is ignored. Following this approach, the elimination of merges can be deterministic as longas terms in a merge are always distinguishable by types. Terms like 1 ,, 2 should be rejected
because it provides two di�erent values to the same type Int, and is thus potentially ambiguous.
Such restriction on merges is conducted via a check on types called disjointness (A ⇤ B means

15

A and B are disjoint), introduced by Oliveira, Shi, and Alpuim [OSA16].
T��������

` e1 ) A` e2 ) B` e1 ,, e2 ) A & B

A⇤B

Note that in the above typing rule of merges, ) denotes the synthesis mode in bidirectional
typing [PT98]. In typing judgements with such a mode, types are synthesized from the term
and the typing environment, rather than provided as inputs for the term to be checked against.
The synthesized type is usually the principal type, and describes all the components containedby the expression exhaustively. For example, the term 1 ,, true has Int & Bool as its synthesized
type. If we are going to merge it with another term e, knowing that the synthesized type of edoes not have an Int or Bool part is enough to avoid con�icts.

2.4.1

Disjointness

To check whether two types are disjoint is to check whether they overlap. Here, overlapping isde�ned on subtyping. Any part of an intersection is its supertype. So the shared part of two
overlapping types is their common supertype. For example, Int is the smallest supertype of
Int & Bool and Char & Int. If two types are disjoint (e.g. (Int & Char) ⇤ Bool), they should haveno common part, and their corresponding values never con�ict (e.g. 1 ,, ‘c’ and true).
In general, knowing the A is a subtype of B means that any term of A can be used as (orconverted to) a term of B. Therefore, if e1 and e2 have type A1 and A2 , and they are both
subtypes of B, in a context expects a term of B either e1 or e2 can satisfy it. In this case, we say
A1 and A2 overlaps on B.
De�nition 2.2 (Disjointness speci�cation). If A is disjoint with B (written as A ⇤ B), any
common supertypes they have must be equivalent to >.
The top type > is the supertype of every type. It can be the empty type, or unit type, which
has only one kind of value. When a context wants a term of a top-equivalent (or top-like) type,
it is viewed as that the context needs no information from the term. Therefore it is harmlessfor multiple terms in a merge match a top-like type at the same time, and we know every term
matches it.
In this thesis, top-like types include certain form of function types, and function types are
disjoint if their return types are. In contrast, a more restricted de�nition of top-like types only
include > and intersections composed by >. Consequently, a merge cannot contain more than
one function. This is because we can always construct a common supertype A1 & B1 ! > forany two function types A1 ! A2 and B1 ! B2 . Note that such types are supertype of > inBCD-style subtyping.

16

2.4.2

Calculi with Disjoint Intersection Types

Via the disjointness restriction on types, ambiguous terms are avoided, therefore the original_8 calculus [OSA16] obtains a type-safe and coherent elaboration semantics. That is, an expression corresponds to an unique result after translation and evaluation. Besides the introduction
rule for merges, it also enforces disjointness via type well-formedness. Intersections are always
restricted not to overlap. For example, 1 : Int & Int is rejected by the type system. Because ofthis restriction, the proof of coherence in the original _8 is still relatively simple.
Likewise, in the following work on the F8 calculus [AOS17], which extends _8 with disjoint
polymorphism that allows universal quanti�ed types with a disjointness constraint, all intersections must be disjoint. However, the disjointness restriction causes di�culties because it
breaks stability of type substitutions. Stability in a polymorphic type system ensures that if apolymorphic type is well-formed then any instantiation of that type is also well-formed. F8 canonly prove a restricted version of stability, which makes its metatheory non-trivial.
Disjointness of all well-formed intersections is only su�cient but not necessary restriction
to ensure an unambiguous semantics. The _8+ calculus [BOS18] relaxes the restriction without
introducing ambiguity. 1 : Int & Int is allowed, as _8+ employs the disjointness restriction only
on merges, but otherwise allows unrestricted intersections. Unfortunately, this comes at a cost:
it is much harder to prove the coherence of elaboration. Both _8+ and F8+ [Bi+19] (a calculus
derived from F8 that allows unrestricted intersections) deal with this problem by establishingcoherence using contextual equivalence and a logical relation [Tai67; Plo73; Sta85]. The proof
method, however, cannot deal with non-terminating programs. In fact, none of the existing
calculi with disjoint intersection types supports recursion, which is a severe restriction.
Let us take a closer look of the coherence property, taking the elaboration semantics of theoriginal F8+ as an example. Expressions in F8+ are translated into F2> , which has no subtyping
or intersection types, and it has a conventional operational semantics. Coherence states that
although the semantics depends on type derivation, all valid derivations produce equivalent
results. For example, the two possible elaborations for the same F8+ source expression into F2>
are contextually equivalent:
1 : Int & Int : Int
1 : Int & Int : Int

fst (1, 1)

snd (1, 1)

Two typing derivations lead to two elaborations in this example, which pick di�erent sides ofthe merge. However, both elaborated expressions will be reduced to 1 eventually.

17

2.5

Application of the Merge Operator: CP Examples

Compositional Programming [ZSO21] is a recently proposed modular programming paradigm.
CP is a prototype language for Compositional Programming. The semantics of CP and its
notion of traits is de�ned via an elaboration to the core calculus F8+ [Bi+19]: a polymorphic corelanguage with a merge operator and disjoint intersection types. The merge operator naturally
enables a form of multiple inheritance, and a powerful form of dynamic inheritance where
inherited implementations can be parameterized, by integrating record concatenation andsubtyping.
Next we will introduce the basic reusable unit in CP: traits, which are usually type-checkedagainst compositional interfaces. And we will show a modular solution to the Expression
Problem, which illustrates some key features in Compositional Programming.

2.5.1

Typed First-Class Traits

Traits in Object-Oriented Programming provide a model of multiple inheritance. Both traits andmixins [BC90; FKF98] encapsulate a collection of related methods to be added to a class. The
main di�erence between traits and mixins has to do with how con�icts are dealt with. Mixins
use the order of composition to determine which implementation to pick in the case of con�icts.
Traits require programmers to explicitly resolve the con�icts instead, and reject compositions
with con�icts. In essence, this di�erence is closely related to the choice of a symmetric or
asymmetric model for the merge operator. Symmetric merges with disjoint intersection types
are closely related to traits because merges with con�icts are rejected, and the compositionis associative and commutative (just like the composition for traits). Asymmetric merges arecloser to mixins, giving preference to one of the implementations in the case of con�icts. We
point the reader to Schärli et al. paper for an extensive discussion of the qualities of the trait
model and a comparison with the mixin model [Sch+03].
The CP language supports �rst-class traits [BO18]. It essentially adopts the original trait
model, but traits in CP are statically typed and support dynamic inheritance. The merge
operator in F8+ is key for CP to model trait composition. Our examples next are adapted from
Bi, Oliveira, and Schrijvers [BOS18].
A simple trait in CP is:
type Editor = {on_key : String ! String;
do_cut : String;show_help : String};
type Version = {18version : String};
editor = trait [self: Editor & Version] ) {on_key (key : String) = Pressing++ key;do_cut= on_key C-x ++show_help= Version:for cutting text ;++ self.version ++Basic usage...

};

A trait can be viewed as a function taking a self argument and producing a record. In thisexample, the record, which contains three �elds, is encoded as a merge of three single �eldrecords. Because all the �elds have distinct �eld names, the merge is disjoint and the de�nitionis accepted. Methods in CP can be dynamically dispatched, as usual in OOP languages. For
instance, in the trait editor, the do_cut method calls the on_key method via the self reference
and it is dynamically dispatched. Moreover, traits in CP have a self type annotation similar to
Scala [Ode+04]. In this example, the type of the self reference is the intersection of two record
types Editor and Version. Note that show_help is de�ned in terms of an unde�ned version
method. Usually, in a statically typed language like Java, an abstract method is required, making
editor an abstract class. Instead, CP encodes abstract methods via self-types. The requirements
stated by the type annotation of self must be satis�ed when later composing editor with othertraits, i.e. an implementation of the method version should be provided.
First-class traits and dynamic inheritance. The interesting features in CP are that traitsare �rst-class and inheritance can be dynamic. The next example shows such features:type Spelling = {check : String};
spell (base : Trait<Editor & Version ) Editor>) = trait [self : Editor &Version] implements Editor inherits base ) {override on_key (key : String) =Process

check = super.on_key C-c

for spelling check++++ key ++on spell editor ;};The spell function takes a trait as an argument and returns a trait as a result. Thus, since
traits can be passed as arguments and returned as results they are �rst-class (just like lambda
functions in functional programming). The new trait adds a check method and overrides theon_key method of the base trait. The argument base is a trait of type Trait<Editor & Version) Editor>, where the two types denote trait requirements and functionality respectively. As
we can see from its de�nition, trait editor matches that type. Note that unlike mainstream
OOP languages like Java, the inherited trait (which would correspond to a superclass in Java)is parameterized, thus enabling dynamic inheritance. In CP the choice of the inherited trait (i.e.

19the superclass) can happen at run-time, unlike in languages with static inheritance (such as
Java or Scala).
Multiple inheritance. The following trait illustrates multiple inheritance in CP:
version = trait ) {version = 0.2};
spell_editor = trait [self : Editor & Version & Spelling] inherits spell editor ,version ) {}(new spell_editor).check --> Pressing C-c for spelling check

The trait spell_editor inherits from both spell editor and version. The latter de�nes animplementation for the �eld version. Finally an object editor1 can be created from the trait
spell_editor.

2.5.2

Expression Problem

To demonstrate the capabilities of Compositional Programming, we show how to solve a variantof the Expression Problem [Wad98] in the CP language. The Expression Problem is a classic
challenge about the extensibility of a programming language. In the expression problem, a data
type of expressions is de�ned, with several cases (literals and additions in the following code)
associated with some operations (e.g. evaluation). There are two directions to extend the data
type: adding a new case and adding a new operation. In a solution both extensions should be
independently de�ned, and it should be possible to combine them to close the diamond. In atypical OOP language, class inheritance makes it easy to add a new case to the data type, while
extending in the other direction in a modular and type-safe way remains hard.
Our solution is adapted from the original one by Zhang et al. [ZSO21]. In this variant, in
addition to the usual challenge of extensibility in multiple directions, we also consider the
problem of context evolution [LHJ95; SO11], so the interpreter may require di�erent contextual
information for di�erent features of the interpreter.
Examples are based on a simple expression language, and the goal is to perform various
operations over it, such as evaluation and free variable bookkeeping. The expression language
consists of numbers, addition, variables, and let-bindings. Besides CP code, we also provide
analogous Haskell code in the initial examples so that readers can connect them with existing
concepts in functional languages.
Compositional interfaces First, we de�ne the compositional interface for numeric literals
and addition. The compositional interface at the top of Figure 2.2a is similar to Haskell’s
20

type NumSig<Exp> = {Lit : Int ! Exp;
Add : Exp ! Exp ! Exp;};

data Exp where
Lit :: Int ! Exp
Add :: Exp ! Exp ! Exp

type Eval Ctx = { eval : Ctx ! Int };evalNum Ctx = trait implements NumSig<Eval
Ctx> ) {(Litn).eval _= n;(Add e1 e2).eval ctx =e1.eval ctx + e2.eval ctx;};

type Eval ctx = ctx ! Inteval :: Exp ! Eval ctx
eval ( Litn) _ = neval ( Add e1 e2) ctx =eval e1 ctx + eval e2 ctx(b) Haskell counterpart.

(a) CP code.

Figure 2.2: Initial expression language: numbers and addition.

algebraic data type at the top of Figure 2.2b. Exp is a special kind of type parameter in CP
called a sort, which serves as the return type of both constructors Lit and Add. Sorts will be
instantiated with concrete representations later. Internally, sorts are handled di�erently fromnormal type parameters [ZSO21]. In accordance with the compositional interface, we can thende�ne how to evaluate the expression language.
Polymorphic contexts As shown in the middle of Figure 2.2a, the type Eval declares amethod eval that takes a context and returns an integer. Ctx is a type parameter that canbe instantiated later, enabling particular traits to assume particular contextual information
for the needs of various features. The technique is called polymorphic contexts [ZSO21] inCompositional Programming.
Compositional traits The trait evalNum in Figure 2.2a is parametrized by a type parameter
Ctx. Note that, in CP, type parameters always start with a capital letter, while regular parameters
are lowercase. The trait evalNum implements the compositional interface NumSig by instantiating
it with the sort Eval Ctx. In this trait, we use a lightweight syntax called method patterns tode�ne how to evaluate di�erent expressions. Such a de�nition is analogous to pattern matchingin Figure 2.2b. Since Lit and Add do not need to be conscious of any information in the context,
the type parameter Ctx is unconstrained. The only thing that we can do to the polymorphic
context is either to ignore it (like in Lit) or to pass it to recursive calls (like in Add).
More expressions Adding more constructs to the expression language is awkward in Haskell
because algebraic data types are closed. However, language components can be modularly
declared in CP. Two new constructors, Let and Var, are declared in the second compositional
interface VarSig, as shown in Figure 2.3. Then the two traits implement VarSig using method21

type VarSig<Exp> = {Let : String ! Exp ! Exp ! Exp;
Var : String ! Exp;};
type Env = { env : String ! Int };evalVar (Ctx*Env) = trait implements VarSig<Eval (Env&Ctx)> ) {(Let s e1 e2).eval ctx = e2.eval{ ctx with env = insert s (e1.eval ctx) ctx.env };(Vars).eval ctx = lookup s ctx.env;};
Figure 2.3: Adding more expressions: variables and let-bindings.

patterns for the new constructors. Since the two new expressions need to inspect or update
some information in the context, we expose the appropriate Env part to evalVar, while theremaining context is kept polymorphic. This is achieved with the disjointness constraint [AOS17]
Ctx*Env in evalVar. A disjointness constraint denotes that the type parameter Ctx is disjoint to
the type Env. In other words, types that instantiate Ctx cannot overlap with the type Env. Also
note that the notation { ctx with env = ... } denotes a polymorphic record update [CM91].
In the code for let-expressions, we need to update the environment in the recursive calls toextend it with a new entry for the let-variable.
Intersection types Independently de�ned interfaces can be composed using intersection
types. For example, ExpSig below is an intersection of NumSig and VarSig, containing all of thefour constructors:
type ExpSig<Exp> = NumSig<Exp> & VarSig<Exp>;--= { Lit : ...; Add : ...; Let : ...; Var : ... };More operations Not only can expressions be modularly extended, but we can easily add
more operations. In Figure 2.4, a new trait fv modularly implements a new operation thatrecords free variables in an expression. Here, union and delete are two library functions forarrays. It is very similar to de�ning a new function by pattern matching in Haskell as before.
The modular de�nition of fv is quite natural in functional programming, but it is hard intraditional object-oriented programming. We have to modify the existing class de�nitions andsupplement them with a method. This is typical of the well-known Expression Problem. In
summary, we have shown that Compositional Programming can solve both dimensions of thisproblem: adding expressions and operations.
Dependency injection Besides the Expression Problem, Figure 2.4 also shows anothersigni�cant feature of CP: dependency injection. In evalWithFV, a new implementation of22

type FV = { fv : [String] };fv = trait implements ExpSig<FV> ) {(Litn).fv = [];(Adde1 e2).fv = union e1.fv e2.fv;(Let s e1 e2).fv = union e1.fv (delete s e2.fv);(Vars).fv = [s];};evalWithFV (Ctx*Env) = trait implements ExpSig<FV ) Eval (Env&Ctx)> ) {(Litn).eval _= n;(Add
e1 e2).eval ctx = e1.eval ctx + e2.eval ctx;
(Let s e1 e2).eval ctx = if elem s e2.fv
then e2.eval { ctx with env = insert s (e1.eval ctx) ctx.env }else e2.eval ctx;
(Vars).eval ctx = lookup s ctx.env;};
Figure 2.4: Adding more operation: free variable bookkeeping and another version of evaluation.

evaluation is de�ned with a dependency on free variables. The method pattern for Let will
check if s appears as a free variable in e2. If so, it evaluates e1 �rst as usual; otherwise, we do
not need to do any computation or update the environment since s is not used at all. Note thatthe compositional interface ExpSig is instantiated with two types separated by a fat arrow ())() was originally denoted by % in Zhang et al.’s implementation of CP). FV on the left-handside is the dependency of evalWithFV. In other words, the de�nition of evalWithFV depends onanother trait that implements ExpSig<FV>. The static type checker of CP will check this fact
later at the point of trait instantiation. With such dependency injection, we can call e2.fv evenif evalWithFV does not have an implementation of fv. In other words, evalWithFV depends only
on the interface of fv (the type FV), but not any concrete implementation.
Self-type annotations Before we show how to perform the new version of the evaluation
over the whole expression language, we want to create a repository of expressions for later
use. We expect that these expressions are unaware of any concrete operation, so we use apolymorphic Exp type to denote some abstract type of expressions. The code that creates therepository of expressions is1 :repo Exp = trait [self : ExpSig<Exp>] ) {num = Add (Lit 4) (Lit 8);var = Letx

(Lit 4) (Lety(Lit 8) (Add (Var x ) (Var y )));};

To make constructors available from the compositional interface, we add a self-type annotation
1 In Zhang et al.’s original work [ZSO21], the new operator must be added before every constructor. But the

new implementation [SDO22] implicitly insert new.

23

to the trait repo. The self type annotation [self : ExpSig<Exp>] imposes a requirement thatthe repo should �nally be merged with some trait implementing ExpSig<Exp>. This requirement
is also statically enforced by the static type checker of CP. This is the second mechanism inCompositional Programming to modularly inject dependencies.
Nested trait composition With the language components ready, we can compose themusing the merge operator, which in the CP language is denoted as a single comma (,). First, weshow how to compose the old version of the evaluation:
exp = new repo @(Eval Env) , evalNum @Env , evalVar @Top;exp.var.eval { env = empty }-! 12

Since the context has evolved after we add variables, we pass di�erent type arguments to thetwo traits to make the �nal context consistent. The �nal context type is Env, so we pass Env
to evalNum and Top to evalVar. Type arguments are pre�xed by @ in CP. A more interesting
example is to merge the new version of evaluation with free variable bookkeeping:exp= new repo @(Eval Env & FV) , evalWithFV @Top , fv;

exp .var.eval { env = empty }-! 12

After the trait composition, both operations (eval and fv) are available for expressions thatare built with the four constructors (Lit, Add, Let, and Var). Note that here fv satis�es thedependency of evalWithFV. If no implementation of the type FV is present in the composition,
there would be a type error, since the requirement for evalWithFV would not be satis�ed. The
composition of the three traits is nested because the two methods nested in the four constructors
are composed, as visualized in Figure 2.5.
This is allowed because with BCD-style subtyping [BCD83] type constructors, like functions
or records distribute over intersections. Since traits in CP are in essence records of functions,such distributivity enables a view in Figure 2.5: components that are nested inside the traits
being composed are themselves recursively composed.
With nested trait composition [BOS18], the Expression Problem is elegantly solved in
Compositional Programming. Moreover, we allow context evolution using a relatively simple
way with polymorphic contexts.
Impredicative polymorphism In ML-like type systems, there is usually a predicativity
restriction imposed on polymorphism. It means that a type variable cannot be instantiated as apolymorphic type. While the original formulation of F8+ also has this restriction, our variant of
F8+ supports impredicative polymorphism. Therefore, CP supports the creation of objects withpolymorphic methods, similar to most OOP languages with generics where classes can contain
polymorphic methods (like Java). For example:
type Poly = { id : forall A. A ! A };24

Figure 2.5: Visualization of nested composition.
idTrait = trait implements Poly ) { id = ⇤A. \(x:A) ! x };(new idTrait).id @Poly-- impredicative

25

26

Part I
Distributive Subtyping

27

CHAPTER 3

D��������� S�������� A��������� ���
I����������� T���� ���� D�������������
Subtyping relations for intersection types can vary in expressive power. Compared with thebasic subtyping we have seen in last chapter, advanced relations usually include distributive
rules. A typical example is the signature rule in the subtyping relation of Barendregt, Coppo,
and Dezani-Ciancaglini [BCD83] (BCD subtyping).
OS�����A��(A ! B) & (A ! C) 6 A ! B & C
Here the function type constructor is distributive over intersection. In BCD-style subtyping, if
more type constructors exist, intersections usually distribute over them as well, like record
types. Especially, if union types are involved, there can be more distributivity rules, as we will
see in the next chapter.
Although known to be decidable [KT95; RU11; Sta15], distributivity makes it hard to design
a simple algorithm for BCD subtyping. In particular, in previous work [BOS18; Pie89; Bes+16;
BRD19; Sie19], the distributivity rule leads to non-modular algorithmic formulations where
many standard subtyping rules have to be changed due to distributivity.
We propose a modular and algorithmic BCD formulation. The key idea is to use the novel
notion of splittable types, which are types that can be split into an intersection of two simpler
types. We show basic properties of our formulation, including transitivity and inversion lemmas,
and conclude that it is sound and complete with respect to the declarative BCD subtyping. Of
particular interest is our transitivity proof. This proof is remarkably simple in comparison withother proofs in the literature due to a semantic characterization of types using splittable andordinary types, which is used as the inductive argument for transitivity.

29

A, B, C ::= Int | A ! B | A & B | >

)~?4
A6B

(Declarative Subtyping)S�����

S����

A6A

A6>

S������
B1 6 A1A2 6 B2

A1 ! A2 6 B1 ! B2
S����R
A1 & A2 6 A2

S������
A6B

A <: B(Conventional Subtyping)CS����

CS������
B1 <: A1

Int <: Int

A1 ! A2 <: B1 ! B2

S����LCS����

CS����
A <: B1

A1 & A2 6 A1

A <: >

B6C

A6C

S����
A 6 B1A 6 B2A 6 B1 & B2

A2 <: B2

A <: B2

A <: B1 & B2

CS����L
A1 <: B

CS����R
A2 <: B

A1 & A2 <: B

A1 & A2 <: B

Figure 3.1: The conventional algorithmic subtyping with intersections (without distributivity), comparedwith the declarative rules.

3.1

Background: Transitivity Elimination

To design an algorithmic system for the declarative subtyping relation (discussed later in
Section 7.2.2), the key challenge is to eliminate the transitivity rule. In this section, we �rst
discuss how the explicit transitivity rule is avoided in the simple subtyping relation withintersection types and no distributivity, and then discuss where this approach fails whena distributive law is included. We follow the convention that intersections have a higher
precedence than unions, and arrows have the lowest precedence.

3.1.1

Conventional Subtyping with Intersection Types

A subset of the BCD subtyping is shown at the left of Figure 3.1. After we exclude the tworules related to distributivity, it is equivalent to the simple subtyping on its right. It has atransitivity rule (S������). For any given goal A 6 C, there is no restriction and no clue for theintermediate type B. A direct implementation may enumerate all possible types, and never ends
when the goal is unprovable. Especially, if it always tries S����� immediately after S������, B
will be uni�ed to be A, and the goal does not change. Such an in�nite loop happens even foradmissible goals.
Compared with the declarative rules, the algorithmic system, at the right of Figure 3.1,
has no explicit transitivity rule, and the re�exivity rule is specialized to the primitive type Int.
Re�exivity is straightforward to obtain for any form of types, including the top type, function
types, and intersection types. In the remaining rules, only CS����L and CS����R are changed,
which can be viewed as the rule S����L and the rule S����R with transitivity built-in. For30

example, use S����L to construct the �rst premise in S������, we can get CS����L.
S����LS������

A1 & A2 <: A1

A1 <: C

A1 & A2 <: CCS����L)

A1 <: C
A1 & A2 <: C

In this case, such an algorithmic formulation follows from a common strategy for transitivity
elimination: pushing transitivity into other rules.
However, one question still remains: why does not transitivity also extend to other positions
like the following rule?
S����LS������

A <: C1 & C2

C1 & C2 <: C1

A <: C1)

CS����L����

A <: C1 & C2
A <: C1

The answer is because such a rule is admissible in the system: Rule CS���� is the only rule thatcan be used to prove the premise of rule CS����L����, and it already implies the conclusion.
Besides, adding rule CS����L���� would break the subformula property and lead to a nonalgorithmic system.

3.1.2

Adding Distributivity: the Simple Approach to Transitivity Elimination Fails

Next we show the two rules that we omitted from BCD subtyping in Figure 3.1.
OS�����A��

OS����A��(A ! B) & (A ! C) 6 A ! B & C>6>!>The second rule implies > 6 A ! >, as we have explained in Section 2.1.
Let us add rule OS�����A�� back to the declarative system. Following the same method, it
seems that we can obtain an algorithmic formulation by directly pushing transitivity into therules. That is, by adding the following two rules.
CS�����A��R����

CS�����A��R������

C <: (A ! B1 ) & (A ! B2 )A ! (B1 & B2 ) <: CC <: A ! (B1 & B2 )(A ! B1 ) & (A ! B2 ) <: C

Rule CS�����A��R���� enables, for instance, arrows with a di�erent input type to unify �rst,

31

and then applying distributivity on the result:CS����LCS������
CS����LCS����

A1 <: A1
A1 & A2 <: A1

B1 <: B1

A1 ! B1 <: A1 & A2 ! B1

(A1 ! B1 ) & (A2 ! B2 ) <: A1 & A2 ! B1...
... <: A1 & A2 ! B2

CS����R(A1 ! B1 ) & (A2 ! B2 ) <: (A1 & A2 ! B1 ) & (A1 & A2 ! B2 )CS�����A��R����(A1 ! B1 ) & (A2 ! B2 ) <: A1 & A2 ! B1 & B2

For simpli�cation, we end at re�exivity in the derivation above. Meanwhile, rule CS�����A��R�
����� can apply distributivity to nested arrows:
B ! C1 & C2 <: B ! C1 & C2

CS������
CS�����A��R������

A <: A(B ! C1 ) & (B ! C2 ) <: B ! C1 & C2

CS�����A��R������A ! (B ! C1 ) & (B ! C2 ) <: A ! B ! C1 & C2

(A ! B ! C1 ) & (A ! B ! C2 ) <: A ! B ! C1 & C2

Unfortunately, that is not enough. Transitivity can extend to both sides of the distributivity
rule together. Consequently, the declarative system (Figure 4.1 extended by rule S�����A��R)
can apply distributivity to nested arrows with di�erent input types, as the following example
shows.
(A1 ! B ! C1 ) & (A2 ! B ! C2 )

6 (A1 & A2 ! B ! C1 ) & (A1 & A2 ! B ! C2 ) by rule S����, rule S������, and other rules
6 A1 & A2 ! (B ! C1 ) & (B ! C2 )by rule S�����A��R

6 A1 & A2 ! B ! C1 & C2

by rule S������ with rule S�����A��R

An attempt at providing an equivalent algorithmic formulation with rule CS�����A��R����and rule CS�����A��R������ fails to accept such subtyping statement. The derived result only
matches rule CS����L and rule CS����R, but both of them drop part of the subtype, making it
impossible to reach the result. Without losing expressive power, we cannot extend the system
directly in this way.

32

, ⌫ , ⇠ ::= Int | > | A ! ⌫$A38=0A~ C~?4
B

A⇤C

(Splittable Types for BCD)
����S�������
B1 B ⇤ B2

����S�����
A&B ⇤ BA

A ! B1

A ! B ⇤ A ! B2
(Top-Like Types)

eAd
TL����

TL������
eBd

TL����
eAd
eBd
eA & Bd

eA ! Bde>d
A <: B(Modular BCD Subtyping)����AS����Int <: Int
����AS����B1 B ⇤ B2

����AS����e⌫ d
A <: ⌫

A <: B1

A <: B2

A <: B

����AS������
B1 <: A1A2 <: ⌫ 2
A1 ! A2 <: B1 ! ⌫ 2
����AS����L
A1 <: ⌫

����AS����R
A2 <: ⌫

A1 & A2 <: ⌫A1 & A2 <: ⌫Figure 3.2: The algorithmic BCD subtyping with intersection types and distributivity.

3.2

A Simple and Modular Formulation of BCD with Splittable Types

Luckily there are other ways to interpret the distributivity rules. In this section, we will
present the algorithmic formulation in Figure 3.2. It is equivalent to the declarative rules forthe conventional subtyping in Figure 3.1 plus the two distributivity rules (OS�����A�� andOS����A��). As a step towards transitivity elimination, we decompose any type A that isequivalent to an intersection type B & C into two conjuncts B and C. If such treatment ispossible, we call A splittable; otherwise A is ordinary.
Ordinary types. Conventionally, ordinary types are types that are not intersections, including
all function types [DP00]. When there is no distributivity, an intersection is a subtype of an
ordinary type only if an ordinary component of the intersection is a subtype of the ordinary
type. Therefore the subtyping rules can be viewed as two parts: one tears intersection types
apart; the other only deal with ordinary types. However, in the presence of rule OS�����A��,33

(A ! B1 ) & (A ! B2 ) is a subtype of A ! B1 & B2 while neither part of it is a subtype: thatis both A ! B1 6 A ! B1 & B2 and A ! B2 6 A ! B1 & B2 do not hold in general. To �x
the broken property and maintain the boundary of intersection types and ordinary types, wetighten the de�nition: a function type is ordinary only if its return type is ordinary. Types likeA ! B1 & B2 are treated like intersections.
Splittable types. The type splitting relation, also shown in Figure 3.2, can be viewed as taking
an input type A, and returning two types B and C, such that B & C is equivalent to A. The relation
extends the decomposition of intersections to types that are equivalent to intersections via
distributivity rules. According to rule OS�����A��, we know that an arrow type can split if its
result type can (rule ����S�������). The other direction A ! B1 & B2 6 (A ! B1 ) & (A ! B2 )is derivable even without the distributive law. The following lemma provides some justi�cation
for type splitting. It is proven by a routine induction on the splittable premise.
Lemma 3.1 (Type splitting loses no information). If B

A ⇤ C then A ⌘ B & C.

Three important properties related to ordinary and splittable types are:Lemma 3.2 (Ordinary types do not split). For any ordinary type A, A is not splittable.
Lemma 3.3 (Types are ordinary or splittable). For any type A, either A is ordinary or
splittable, and it is decidable.
Lemma 3.4 (Splitting is deterministic). For any splittable type A, if B1
then B1 = B2 and C1 = C2 .

A ⇤ C1 and B2

isA ⇤ C2 ,The modular BCD subtyping algorithm The main idea for the algorithmic formulation ofsubtyping, shown at the bottom of Figure 3.2, is that the right-hand side type B keeps splitting
until it becomes ordinary. When it splits, rule ����AS���� is applied, which works in the same
way as rule CS���� when B is an intersection type. The most interesting case is when B isa splittable function type, for example, B := B1 ! B2 & B3 . Type B can be split into B1 ! B2
and B1 ! B3 . Therefore, the premises of A <: B are A <: B1 ! B2 and A <: B1 ! B3 ,or equivalently, A <: (B1 ! B2 ) & (B1 ! B3 ). Thus we are able to conclude A <: B with a
combination of rule S������ and rule S�����A��R in declarative subtyping. That is to say, while
rule ����AS���� combines rule S������ and rule S����, it also takes rule S�����A��R into
consideration implicitly. The ordinary-type conditions eliminate some overlapping between
the rules: we can see that when B is splittable, only rule ����AS���� can be applied, sincerule ����AS����L and rule ����AS����R require B to be ordinary. However, dropping suchconditions does not alter the expressive power: it leads to an equivalent system (but with more
overlapping).
The previous failed example can now be derived, as its right-hand side type, although
not matched by rule S�����A��R, is captured by type splitting. Due to space limitations, we
34

omit the type (A1 ! B ! C1 ) & (A2 ! B ! C2 ), which is unchanged across the applicationof rule ����AS����, in its premises. We also employ the rules without the ordinary-typeconditions in the derivation for simpli�cation. The main derivation is:
����AS����������AS������...

...
����AS����L
����AS����

A1 ! B ! C1 <: A1 & A2 ! B ! C1... <: A1 & A2 ! B ! C1... ! C2 <: ... ! C2⇡... <: ... ! C2

����AS����R(A1 ! B ! C1 ) & (A2 ! B ! C2 ) <: A1 & A2 ! B ! C1 & C2

The missing subderivation ⇡ for type splitting is:����S�����
����S�������
����S�������C1

B ! C1A1 & A2 ! B ! C1

C1 & C2 ⇤ C2

B ! C1 & C2 ⇤ B ! C2

A1 & A2 ! B ! C1 & C2 ⇤ A1 & A2 ! B ! C2

Top-like types. As suggested by its name, a top-like type is both a supertype and a subtypeof >. They can be easily distinguished by the rules in the middle of Figure 3.2. Besides >,top-like types contain intersection types like > & >. Notably, rule TL������ allows arrow
types to be top-like when their return types are top-like. This enlargement is to cope withrule OS����A��. Rule ����AS���� says that a top-like type is a supertype of any type. It canbe justi�ed by the following theorem.
Theorem 3.1 (����AS���� in declarative BCD). If eBd, then A 6 B.

3.2.1

Modularity

A more declarative (and modular) formulation of subtyping is to omit each ordinary-typecondition in Figure 3.2. Note that here we employ the term “modularity” to mean that existing
subtyping rules do not need to be changed because of a new feature (in this case distributivity).
Our �rst observation is that omitting the ordinary-type conditions does not change expressiveness.
Lemma 3.5 (Modular ����AS����). If eBd, then A <: B.
Lemma 3.6 (Modular ����AS������). If B1 <: A1 , A2 <: B2 , then A1 ! A2 <: B1 ! B2 .
Lemma 3.7 (Modular ����AS�����). If A <: C, then A & B <: C.
Lemma 3.8 (Modular ����AS�����). If B <: C, then A & B <: C.
35

With these lemmas, the two formulations (with and without ordinary-type conditions) areproved to be sound and complete with respect to each other. Thus, compared to the conventional
simple subtyping relation at the right of Figure 3.1, the modular BCD subtyping relation only
replaces rule CS���� by rule ����AS����, and replaces rule CS���� by rule ����AS���� toenable BCD distributivity. The new subtyping rules generalize the previous ones.
It is possible to have an equivalent alternative approach for adding BCD distributivity(rule ����AS����) without modifying the existing rules. One just needs to keep the oldrule CS���� and add rule ����AS��������:CS����

A <: B1

����AS��������

A <: B2

C1

A <: B1 & B2

B2 ⇤ C2

A <: B1 ! C1

A <: B1 ! C2

A <: B1 ! B2

Similarly, an alternative to rule ����AS���� and the top-like relation (eAd) is to use thefollowing two rules:
CS����

A <: >

����AS������������

> <: CA <: B ! C

The �rst rule is just the standard rule for top types, while the second rule is a special rule
which deals with top-like function types.
Both alternative approaches replace one rule in our modular subtyping relation by two,
while keeping the expressiveness of subtyping unchanged. Rule ����AS���� and rule ����AS�
��� in our modular BCD subtyping are generalizations of the designs that would use 2 rules
instead, which is why we choose them to be in our system.
It is also worth mentioning that our algorithmic relation keeps the simple judgment form
A <: B, thus the system is easier to extend with orthogonal features, which have been presented
with a subtyping relation of that form. Some BCD subtyping formulations require a di�erent
form to the subtyping relation [BOS18; Pie89; Bes+16; BRD19].

3.3

Metatheory of Modular BCD

A bene�t of our new formulation of BCD subtyping is that the metatheory is remarkably simple.
The metatheory of BCD subtyping has been a notoriously di�cult topic of research.
Inversion lemmas. Given that our algorithmic relations are not entirely syntax-directed,
several inversion lemmas indicate that the algorithm and the declarative system behave similarly.
Lemma 3.9 (Inversion on left split). If A <: ⌫ and A1

36

A ⇤ A2 then A1 <: ⌫ or A2 <: ⌫ .

`& A(Proper Types)

RTY����

RTY����

`& Int`& >RTY����F��
`& A
`& ⌫
`& A ! ⌫RTY������
B A⇤C

`& B

`& A

`& C

Figure 3.3: Proper types.

Lemma 3.10 (Inversion on right split). If A <: B and B1

B ⇤ B2 then A <: B1 and A <: B2 .

Both lemmas are easily proven by induction on the subtyping premises.

Transitivity. Since the transitivity rule is eliminated in algorithmic systems, we need toshow that the transitivity lemma holds. This property is critical but di�cult for any BCD
formulation without the transitivity axiom built-in.
Lemma 3.11 (Transitivity of modular BCD). If A <: B and B <: C then A <: C.
To prove the transitivity lemma, one might try at �rst to proceed by induction on ⌫. However,that does not succeed, since our algorithm is not entirely syntax-directed. In particular, thebehavior of the subtyping algorithm is determined by whether the type on the right is ordinaryor splittable (but not simply the syntax form of the type). For example, in the case where A <: B
is derived by rule ����AS����, B can be split into two parts B1 B ⇤ B2 , yet B1 and B2 cannot
be applied to the induction hypothesis, simply because they may not be components of type B.
On the other hand, assuming one does induction on the two subtyping derivations, it is a tricky
case when A <: B is derived by rule ����AS���� and B <: C is derived by rule ����AS������.
The former splits type B while the latter decomposes it as a function type, and they do notmatch.
To overcome this problem we would like to treat any splittable type similarly to an intersection type 1 . Therefore, we need a proper characterization of the type structure, so that theinduction hypothesis on splittable types is always as desired. The relation de�ned in Figure 3.3
de�nes the so-called proper types. Proper types act as an alternative inductive de�nition fortypes, distinguishing types based on whether they are ordinary or splittable. The following
lemma shows that the de�nition is general: any type is a proper type.
Lemma 3.12 (Types are proper types). For any type , `& A.
With the new de�nition for types, we are ready to prove the transitivity lemma. Induction
is performed on the relation `& B which is obtained easily on type ⌫ through Lemma 3.12. The
induction then breaks into several cases:
1An alternative approach is to de�ne a size measure for types and do induction on the sum of the sizes of types.

37• Int and > are easy base cases.
• When ⌫ is a function type constructed by rule RTY����F��, a nested induction on thepremise B <: C gives three sub-cases.
– Sub-cases rule ����AS���� and rule ����AS���� are easy to prove by induction
hypothesis.
– Sub-case rule ����AS������ is then able to �nish by another nested induction on
the other premise A <: B.
• The last case is when B is a splittable type (B1 B ⇤ B2 ), where we know that A <: B1
and A <: B2 by Lemma 3.10. Let us do induction on `& C.
– If ⇠ is an ordinary type, by Lemma 3.9, either B1 <: C or B2 <: C holds. In bothcases, applying the induction hypothesis of ⌫ �nishes the proof.
– Otherwise, assuming C1 C ⇤ C2 , we apply Lemma 3.10 to B <: C and get B <: C1
and B <: C2 . Via the induction hypothesis of ⇠ we can obtain A <: C1 and A <: C2
and reach the goal by rule ����AS����.
Equivalence to declarative BCD. Thanks to the simple judgment form used in our algorithm,
the soundness and completeness theorems are stated directly as follows.
Theorem 3.2 (Soundness of modular BCD). If A <: B then A 6 B.
The soundness theorem only relies on Lemma 3.1 and Theorem 3.1.
The completeness theorem is also easy to show with the help of transitivity (Lemma 3.11),
by induction on the premise.
Theorem 3.3 (Completeness of modular BCD). If A 6 B then A <: B.
To sum up, our novel formulation of BCD subtyping adds the function distributivity feature
in a modular way, and the metatheory is straightforward to establish with the notion of proper
types.

3.4

Implementation

Finally, in Figure 3.4, we present a Haskell implementation of the subtyping rules in
Figure 3.2. We model types as:
data Type = TInt | TTop | TArrow Type Type | TAnd Type Type38

-- ordinary typeordinary :: Type ! Bool
ordinary a = split a == Nothing-- split typesplit :: Type ! Maybe (Type, Type)
split (TAnd a b) = Just (a, b)
split (TArrow a b)
| Just (b1, b2) <- split b= Just (TArrow a b1, TArrow a b2)
split _ = Nothing-- Bsp-and-- Bsp-arrow-- check whether the given type is top-likecheckTopLike :: Type ! BoolcheckTopLike TTop
= TruecheckTopLike (TArrow a b) = checkTopLike b
checkTopLike (TAnd a b)
= checkTopLike a && checkTopLike b
checkTopLike _= False-- subtyping
checkSub :: Type ! Type ! BoolcheckSub TInt TInt = True
checkSub a b| checkTopLike b == True = True
| Just (b1, b2) <- split b= checkSub a b1 && checkSub a b2
checkSub (TAnd a1 a2) b= checkSub a1 b || checkSub a2 b
checkSub (TArrow a1 a2) (TArrow b1 b2)= checkSub b1 a1 && checkSub a2 b2
checkSub _ _ = False-- TL-top-- TL-arrow-- TL-and-- bcd-AS-int-- bcd-AS-top-- bcd-AS-and-- bcd-AS-andL bcd-AS-andR-- bcd-AS-arrow

Figure 3.4: Haskell implementation of BCD subtyping.

A type is either ordinary or splittable. The split function in Figure 3.4 is based on the de�nitionof the type splitting relation. It returns the split results if the input type is splittable. The
ordinary function makes use of the fact that the set of ordinary types is complementary to theset of splittable types. It can also be implemented by analyzing the form of the type.
The checkSub function takes two types and decides whether the �rst input is a subtypeof the second one. The �rst two cases correspond to rule ����AS���� and rule ����AS����.
Then the case corresponding to rule ����AS���� handles all cases of which the second input issplittable. Since the code executes sequentially, the second input is guaranteed to be ordinary
after that. Following are the cases corresponding to rule ����AS����L and rule ����AS����R.
When the �rst input is an intersection type, it is necessary to try both rules before returning
False. In the end, both types must be arrow types and must satisfy rule ����AS������ if thesubtyping holds.
39

Summary In this chapter we presented a subtyping algorithm design that uses a typesplitting operation to convert types to an equivalent intersection type. The subtyping algorithm
uses type splitting whenever an intersection type is expected in the conventional algorithm forsubtyping without distributivity, and therefore handles distributivity smoothly and modularly.
Later we will extend this algorithmic formulation to record types for the _8+ calculus (Chapter 6)
and to universal quanti�ed types with disjoint polymorphism for the F8+ calculus (Chapter 7).

40

CHAPTER 4S�������� ���� U���� T����In this chapter, we will see how the ideas of splittable types can be extended into a more
complex setting with union types and additional distributivity rules. Then, using anothertechnique called duotyping, we will exploit the fundamental dualities between intersection
and union types to further unify the rules in the system. In the end, we will present a compact
functional implementation of the subtyping algorithm. Along the way, we show various results
regarding the metatheory of the system, including soundness, completeness and decidability.

4.1

Overview

Subtyping relations with intersections and unions have deep connections to logic, which
follow from the Curry-Howard isomorphism [How80]. Types can be interpreted as propositions:intersections are interpreted as conjunctions, unions as disjunctions and functions types as
implications. Furthermore, from the perspective of logic, the subtyping problem is essentiallythe problem of determining logical entailment: does a logical statement follow from anotherone? Where in logic one may write % ` & for logical entailment, with subtyping one writes% <: & to denote that & is a supertype of (or follows from) %. Naturally, algorithms for deciding
logical entailment have applications to other areas, such as theorem proving [Sto19]. One
particular subtyping relation of practical interest for programming languages is closely related
to the basic positive logic B+ of Routley and Meyer [RM72]. The connection to programming
languages is due to Bakel et al. [Bak+00], who have shown a type assignment system that
corresponds to the B+ logic. Logic B+ is also called the minimal relevant logic since it is
the minimal (or the weakest) relevant logic system that is complete for the Routley-Meyer
ternary relational semantics. In the minimal relevant logic B+, there are two axioms thatcan be interpreted as the two distributivity rules above. Languages that have some form of
distributivity rules include Ceylon, CDuce, Julia and Scala 3 (or Dotty). The subtyping relations
used in Ceylon and CDuce, for instance, include all the rules of the minimal relevant logic.

41

In this chapter, we continue with the idea of splittable types. With it extended to union
types, we obtain a novel algorithmic formulation of a powerful subtyping relation with union
and intersection types that is based on the minimal relevant logic. Unlike many normalizationbased algorithms, our new subtyping algorithm works directly on source types. In other words,
there is only one step in our algorithm without any pre-processing phase. Besides, we employ
another recent idea duotyping [OCR20], which provides a generalization of subtyping witha mode. This mode allows exploiting fundamental dualities between union and intersection
types and their subtyping rules. This leads to a consistent and symmetrical design for the rules,
and also bene�ts both metatheory and implementation. We will �rst present the subtyping
based on minimal relevant logic then we show how it is derived straightforwardly from the
duotyping formulation.

4.2

Subtyping based on Minimal Relevant Logic

In this section, we show two equivalent subtyping relations (one declarative and anotheralgorithmic) for a variant of minimal relevant logic subtyping [RM72; Bak+00]. The mainnovelty over the BCD subtyping relation presented in Chapter 3 are the addition of union types,
and extra distributivity rules. We show that the idea of splittable types smoothly extends todeal with those features. The algorithmic formulation is derived from a formulation basedon duotyping that will be presented in Section 4.3, but the presentation in this section isunderstandable independently of duotyping.

4.2.1

Declarative subtyping

The declarative subtyping rules in Figure 4.1 extend the rules on the left of Figure 3.1. The
addition of union types (A | B) and the bottom type (?) brings the following new rules.
1. Rule S����, similarly to rule S����, de�nes the bottom type as the lowermost boundamong types. ? has no inhabited values. In other words, it is the empty type from the
set-theoretic view of types. In a system where arrow types are interpreted as logicalimplications, the bottom type can be used to encode negation as A ! ?.
2. Rule S���, rule S���L, and rule S���R de�ne basic subtyping for unions, similarly tothe three intersection rules. In a language with union types, a term of type A can betransformed into any union type containing A. From the point of view of proof theory,
having the proof of either A or B is enough to construct a proof of A | B. That is to say,a union type is a supertype of its components. Moreover, a union type is a subtype ofsome type if both its components are subtypes of that type.

42

A, B, C ::= Int | A ! B | A & B | (A | B) | > | ?

)~?4
A6B

(Declarative Subtyping Extension)
S����

?6A

S���

A1 6 BA2 6 B

A1 | A2 6 B

S���L

S���R

B1 6 B1 | B2

B2 6 B1 | B2

S�����A��R

S�����A��R����(A ! B1 ) & (A ! B2 ) 6 A ! B1 & B2

A ! B1 & B2 6 (A ! B1 ) & (A ! B2 )S�����A��LS�����A��L����(A1 ! B) & (A2 ! B) 6 A1 | A2 ! B

A1 | A2 ! B 6 (A1 ! B) & (A2 ! B)

S�����O�

S�����A��

(A1 | B) & (A2 | B) 6 (A1 & A2 ) | B(A1 | A2 ) & B 6 (A1 & B) | (A2 & B)

Figure 4.1: Declarative subtyping rules (extends the left part of Figure 3.1).

3. The remaining six rules are related to the distributivity of intersections and unions overother constructs. Rule S�����A��R is part of the BCD subtyping. Along with rule S�����A��L, the two rules distribute arrows over intersections and unions, respectively.
These two rules have two corresponding reversed rules (rule S�����A��R���� and rule S�����A��L����). Note that the latter two rules are not necessary since they can be derived
from other rules, but we present them here because in Section 4.3.1 they will play a role inour reformulation of the subtyping relation using duotyping [OCR20]. Rule S�����A��R���� and rule S�����A��L����, in combination with the previous two rules, illustrate thatthe two types in the subtyping relation are isomorphic (i.e. they are subtypes of eachother).
4. The interaction between intersection types and union types is described by the rule S�����O� and the rule S�����A��. They can distribute over each other. The reversed rules
are derivable and therefore omitted. To be noted, it would not a�ect the whole system todrop one of the two rules (either rule S�����O� or rule S�����A��): in the presence of
one of the two rules, the other rule can be derived from the other subtyping rules.
Remark It is should be noted that, in combination with transitivity, more general subtyping
rules become derivable. For instance, an intersection of any two arrow types has a supertype43

that is a combination of them:S�����A������

(A1 ! A2 ) & (B1 ! B2 ) 6 A1 & B1 ! A2 & B2
In other words, rule S�����A������ is not restricted to types that share the same input type
(as the rule S�����A��R). Similarly, the subtype of an intersection of two arrow types can beobtained from an arrow type that takes the union of the input types of the arrow types:
S�����A����������

A1 | B1 ! A2 & B2 6 (A1 ! A2 ) & (B1 ! B2 )4.2.2

Algorithmic Subtyping: Adding Union Types and More Distributivity

Now we are ready to move on to the design of algorithmic subtyping for Figure 4.1. We�rst cover the extended de�nitions of ordinary and splittable types here, in which the initialde�nition is revised, and a dual version is de�ned for union types.
Intersection-ordinary and intersection-splittable types With union types and the bottom
type taken into consideration, we need to revise the previous de�nitions. Firstly we rename
them as intersection-ordinary types (A , top of Figure 4.2) and intersection-splittable types(B A ⇤ C, in the middle of Figure 4.2). Originally, “ordinary” was used to describe the lack of“intersections”, and “splittable” meant a type that has two parts connected by an intersection.
Now we make this explicit in the names. Intersection-ordinary types include (non-splittable)
union types, but exclude intersection types at the top level (although intersection types canappear in some nested positions inside the types). In contrast, intersection-splittable types
include top-level intersections and some union types. Mainly, there are four changes in the
new de�nition.
1. The bottom type is ordinary like the top type.
2. Due to the distributivity of union over intersections (rule S�����O� and rule S�����A��),
some unions are also isomorphic to intersections, for example the type (A1 & A2 ) | B is
isomorphic to (A1 | B) & (A2 | B). That is to say, the former can be split into A1 | B and
A2 | B. Splitting the union type A | B, �rst tries to split A by rule S�I���L, and only moves
to B if A cannot be split (rule S�I���R). Thus only unions whose components are bothordinary can be treated as ordinary types.
3. Rule S�I������L is brought by rule S�����A��L and rule S�����A��L����: if its input
type is a union, an arrow type can be converted into an intersection type, and therefore it
44

Intersection-Ordinary Types
Union-Ordinary Types
Double-Ordinary Types

B

A⇤C(Intersection-Splittable Types)
S�I������R

S�I����

A, ⌫ , ⇠ F Int | > | ? | • ! ⌫ | ( | ⌫ )• • •, ⌫ , ⇠ F Int | > | ? | A ! B | A & B•, ⌫ •, ⇠ • F Int | > | ? | • ! ⌫B1

A&B ⇤ B

A ! B1S�I���L

A1

A1 | B
B⇣A⌘CS�U���

A⇣A|B⌘B

S�I������LB ⇤ B2

A ! B ⇤ A ! B2

A1 ! ⌫S�I���R

A ⇤ A2

B1

A | B ⇤ A2 | B

A1 ⇣ A ⌘ A2

A ! ⌫ ⇤ A2 ! ⌫B ⇤ B2

| B1

|B⇤

| B2

(Union-Splittable Types)
S�U����L

A1 ⇣ A ⌘ A2

A1 & B ⇣ A & B ⌘ A2 & B

S�U����R•

B1 ⇣ B ⌘ B2

& B1 ⇣

•

&B ⌘

•

& B2

Figure 4.2: Ordinary and splittable types.

is not ordinary. In the ordinary rule for arrow types, the new version has more restrictions:the input type of an intersection-ordinary arrow type must not be a union-like type, i.e.
it is a union-ordinary type (Figure 4.2).
4. To be noted, a side condition B is added in rule S�I������L to ensure that the relation
can be used as a deterministic function, like in rule S�I���R. Although we prioritize
rule S�I���L and rule S�I������R here, we believe some other arrangements are also
feasible.
Union-ordinary and union-splittable types Figure 4.2 also presents the de�nition ofunion-ordinary types (A ) and union-splittable types (B ⇣ A ⌘ C). A union-splittable type isisomorphic to the union of its split results, and union-ordinary types are those that cannot be
split. Such a de�nition is almost the dual of the intersection- rules: just exchange intersection
and union, and switch intersection- and union- judgments.
The key di�erence is that no arrow types are union-splittable and they are all unionordinary. Correspondingly, splitting union types lacks arrow-related rules, and all function
types are union-ordinary. The source of the di�erence is that both of the two distributivity

45

arrow rules in the declarative system (rule S�����A��R and rule S�����A��L) relate arrow
types with intersection types but not union types. To have an exact dual, the union-ordinary
and union-splittable types de�nitions would lead to the following two rules:
S�����A��R������

S�����A��L������

A ! B1 | B2 6 (A ! B1 ) | (A ! B2 )A1 & A2 ! B 6 (A1 ! B) | (A2 ! B)

However, such rules do not lead to valid coercions from the coercive subtyping point of view
where unions are interpreted as sums and intersections are interpreted as products. If we added
these two rules, then some arrow types could be union-splittable.
While a type must be either intersection- (union-) ordinary or intersection- (union-) splittable, the two sets of ordinary (and splittable) de�nitions are overlapping. We use A to denote
types that are both intersection-ordinary and union-ordinary. The following table presents
some examples of each of the four kinds of types:

Ordinary

Splittable

Intersection-

Union-

Int, >, ?
Bool & String ! Int | CharInt | Char
A&B
Int ! A & B

Int, >, ?
Bool & String ! Int | CharInt & Char
A|B
Int ! A | B

A A&B ⇤ B
A | Int (A & B) | Int ⇤ B | Int
A | B (A | B) & Int ⇤ Int
Int ! A Int ! A & B ⇤ Int ! B

A⇣A|B⌘B
A & B ⇣ (A & B) | Int ⌘ Int
A & Int ⇣ (A | B) & Int ⌘ B & Int
Int ! A ⇣ Int ! A | B ⌘ Int ! B

The examples using a strikeout font represent negative examples: that is types that do notconform to the de�nition. For instance, in the �rst cell, Int | Char is intersection-ordinary,
while A & B is not. Types that are ordinary from both perspectives include Int, >, ?, and allintersection-ordinary arrow types. Such arrow types can contain intersections in negative
positions, or unions in positive positions, like Bool & String ! Int | Char. In contrast, only someunion types and intersection types are both intersection- or union- splittable, as demonstrated
by the second and third lines in the cell of the splittable types. Once we have A1 A ⇤ A2
and B1 ⇣ A ⌘ B2 , we know that A is isomorphic to A1 & A2 and B1 | B2 . Via the subtyping
rules in Figure 4.1, we can obtain 8 6 ⌫ 9 (8, 9 = 1, 2). The last examples for splittable types
correspond to the last examples for ordinary types. They emphasize the asymmetry between
intersection-splittable types and union-splittable types, while other examples highlight the46

(Algorithmic Subtyping for B+ Logic)

A <: B
���AS�I��

���AS����

���AS����

Int <: Int

A <: >? <: A���AS����
B1 B ⇤ B2

A <: B1•
1 !

���AS���
⌘1⇣

A <: ⌫•

A1 <: ⌫

A <: ⌫

A2 <: ⌫

���AS���L⌫1 ⇣ ⌫ ⌘ ⌫2•
2 <: ⌫ 1 ! ⌫ 2

���AS����L
A1 A ⇤ A2

A <: B2

A <: B

���AS����R
A1 A ⇤ A2

���AS������
⌫ 1• <: •1
2 <: ⌫ 2•

2

1 <: ⌫<: ⌫���AS���R⌫1 ⇣ ⌫ ⌘ ⌫2<: ⌫ 1•<: ⌫2 <: ⌫•<: ⌫ 2<: ⌫Figure 4.3: Algorithmic subtyping rules.

symmetric parts.
Algorithmic subtyping Compared to the modular BCD subtyping in Figure 3.2, we have arule ���AS���� for the bottom type, and three more rules for union-splittable types (rule ���AS���, rule ���AS���L, and rule ���AS���R) in our algorithmic system in Figure 4.3. Similarly tothe modular BCD subtyping, the three distributivity rules in the declarative system in Figure 4.1(rule S�����A��R, rule S�����A��L, and rule S�����O�), are covered with the rule ���AS����
by splitting the supertype. Besides this, rule ���AS����L and rule ���AS����R generalize
the subtype to an intersection-splittable type, while the modular BCD subtyping uses anintersection type. That is because rule ���AS������ is restricted to only handle ordinary
types with the two intersection-ordinary premises, and intersection-splittable types need help
from other rules. In rule ���AS���L and rule ���AS���R, the subtype in the conclusion is not
splittable in either way. Compared to the rules for intersection-splittable types, the three rules
have additional restrictions on types to avoid overlapping with them. These restrictions on
ordinary types divide rules into groups and make an order among them, except for rule ���AS�
��� and rule ���AS����, which can still overlap with other rules. Such pre-conditions help
to implement an algorithm with less backtracking, but we can drop them and the subtyping
system would remain equivalent in terms of expressive power.

47

Example Let us demonstrate the algorithmic formulation with an example.
���AS����
���AS���R
���AS����R
���AS����

Int <: Int•

Int <:
(

•

...

3

| Int

2

| ⌫ • ) & Int <:(The missing subderivation

•
•

•

2

| Int

1

| ⌫ • ) & Int <:

•

(

•

| ⌫ • <:| ⌫ • ) & Int <:| (Int & ⌫ • )

•
•

|⌫ •

|⌫ •

���AS���
���AS����L

1 for type splitting is:S�I����
S�I���R

Subderivations

2 and

Int
•

•

| Int

3 are:S�I����
•|⌫ •Int & ⌫ • ⇤ ⌫ •| (Int & ⌫ • ) ⇤

•

|⌫ •

S�U���(•| ⌫ • ) & Int ⇤ Int

•

⇣

•

| Int ⌘ Int

In the next section, we will see the duality of intersection and union types more clearly.

4.3

Duotyping Based on Minimal Relevant Logic

The algorithmic subtyping relation in Section 4.2.2 was not designed from �rst principles.
Instead, it is derived (in a straightforward way) from another de�nition that exploits the duality
between unions and intersections (as well as top and bottom). The approach that exploits
duality is the so-called duotyping [OCR20]. The key idea is to generalize the subtyping relation
with a third argument, which is the mode of the relation (subtyping or supertyping). Then
many dual rules can be expressed as a single rule in the duotyping relation, and the dual rules
are ensured (by construction) to be designed in a consistent way. In turn, this leads to an
implementation approach that can exploit duotyping and modes, to reduce the number of cases,de�nitions and code. Our implementation in Section 4.4 will use duotyping.
This section shows the duotyping de�nitions from which the subtyping relations in Figure 4.3 were derived, and discusses the respective metatheory, including transitivity as wellas various soundness and completeness theorems among the di�erent relations. We opted topresent the traditional formulation of subtyping �rst because the formulation of duotyping,while more compact, is also more abstract and can be harder to grasp than the more concrete
subtyping formulation. We �rst reformulate declarative subtyping in terms of duotyping,48

and then exploit the duotyping structure found in the declarative formulation to design thealgorithmic formulation.

4.3.1

Declarative Duotyping

Before developing the algorithmic version of duotyping we �rst show a duotyping version ofdeclarative subtyping. Duotyping is particularly useful when the types in the language havemultiple dual constructs, which is precisely the case here: we have both intersections andunions, as well as top and bottom types. Thus, understanding the subtyping relation from thepoint of view of duotyping can shed new light over the various rules used in subtyping, andgive us some hints regarding the design of an algorithmic version.
The key idea of duotyping The key idea in duotyping is to have a generalization of thesubtyping relation that takes an extra mode as an argument:
3 ::=

">34

|

The mode can either be subtyping ( ) or supertyping ( ). A duotyping judgement A 3 B cantherefore be interpreted as both A is a subtype of B (A B), and A is a supertype of B (A B),
depending on which mode is chosen. This extra mode is helpful to generalize dual rules fordual constructs.
Auxiliary functions Before we dive into the duotyping rules, some auxiliary de�nitions
need to be introduced. At the top of Figure 4.4, we restate some of the auxiliary functions as
described in the original duotyping work. For example, to combine the conventional subtyping
rules for top and bottom (rule S���� and rule S����), a function e3d parameterized by themode 3 is necessary. The intersection and union constructors are also dual, and they can beselected using the function (A 3? B). Finally, there is a �ip function to invert the mode.
Declarative duotyping With these helper functions, the declarative duotyping relation
is de�ned in the bottom part of Figure 4.4. For instance, using e3d we can capture the two
subtyping rules for top and bottom with the following duotyping rule:D��������

A 3 e3dSome rules (rule D�������, rule D�������� and rule D��������) are direct generalizations
from the original subtyping rules in Figure 3.1 and Figure 4.1, since those rules are reversible(i.e. they work in both modes). One unique rule in the duotyping formulation is the duality

49

e
e

d = >

(A

d = ?

A3B

(A

? B)

= A&B

=

? B)

= A|B

=

(Declarative Duotyping)D�������
B3A
A3B

D������
A3B
A3C
A 3 (B 3? C)

D�������
A3A

D�������A��L

D��������
A3B
B3C
A3C

D��������
A 3 e3dD��������
A1 3 B1A2 3 B2

A1 ! A2 3 B1 ! B2

D������LD������R

D�������A��R(A 3? B) 3 A(A 3? B) 3 B(A ! B) & (A ! C) 3 A ! B & C(A ! C) & (B ! C) 3 A | B ! C

D�������O�((A1 3? B) 3? (A2 3? B)) 3 ((A1 3? A2 ) 3? B)

Figure 4.4: Declarative duotyping and auxiliary functions (top).

rule (rule D�������), which transforms a subtyping judgement into a supertyping one, or viceversa. The remaining rules match with two original subtyping rules: rule D������, rule D���
���L, and rule D������R unify the three intersection rules and three union rules (rule S����,rule S����L, rule S����R, rule S���, rule S���L, and rule S���R). Rule D�������A��R andrule D�������A��L are for distributing arrows over unions and intersections. As mentioned in
Section 7.2.2, their dual rules are absent, therefore cannot be further uni�ed. The rule D���
����O� is the generalization of rule S�����O� and rule S�����A��. Compared to the rules in
Figure 4.1, the duotyping version is pleasingly more compact (11 rules versus 17 rules). More
importantly, the dual relationship between various rules in Figure 4.1 is now made explicit in
the formalization.

4.3.2

Algorithmic Duotyping

The rules for the algorithmic duotyping system are presented in Figure 4.5.

50

Ordinary3 A(Ordinary Types)

����O����������O����������O����������O��������U

Ordinary3 >Ordinary3 ?

Ordinary3 Int

Ordinary A ! B

����O��������I
Ordinary A
Ordinary B

����O�����
Ordinary3 A

Ordinary3 (A 3? B)

Ordinary A ! B
B

A3 ⇤ C(Splittable Types)
����S�������R
B1 B ⇤ B2

����S�����
A

Ordinary3 B(A 3? B) 3 ⇤ B

A ! B1

����S����LA1(A1 3? B)

����S�������L
Ordinary B
A1

A ! B ⇤ A ! B2

����S����R
Ordinary3 A

A 3 ⇤ A2

(A 3? B) 3 ⇤ (A2 3? B)

A 30 B

A1 ! B(A 3? B1 )A ⇤ A2

A ! B ⇤ A2 ! B

B1

B 3 ⇤ B2

(A 3? B) 3 ⇤ (A 3? B2 )(Algorithmic Duotyping)����AS��������AS������

Int 30 Int

A 30 e3d

����AS�����
Ordinary3 A

Ordinary3 B
A 30 B

����AS������
Ordinary A1 ! A2
A1 30 B1

Ordinary B1 ! B2
A2 30 B2

A1 ! A2 30 B1 ! B2

����AS����B1 B 3 ⇤ B2

B 30 A

����AS����L
Ordinary3 B
A1 A 3 ⇤ A2
A1 30 BA 30 B1

A 30 B

����AS����R
Ordinary3 B
A1 A 3 ⇤ A2
A2 30 BA 30 BA 30 B

Figure 4.5: Algorithmic duotyping.

51

A 30 B2

Ordinary and splittable types By parametrizing over the mode 3, the two ordinary types
in Figure 4.2 can be merged. Instantiated 3 by subtyping, Ordinary A de�nes the intersectionordinary relation, which characterizede�ned on the top of Figure 4.2. Its supertyping
dual, Ordinary A, matches with the previously de�ned union-ordinary types • . A similaruni�cation applies to splittable types. B A ⇤ C is for intersection-splittable types, while
B A ⇤ C is for union-splittable ones. Only arrow-related rules (rule ����O��������I,
rule ����O��������U, rule ����S�������R, rule ����S�������L) are speci�c to a particularmode (subtyping or supertyping), but otherwise, all the other rules are generic on the mode.
Duotyping In total there are 7 rules in the algorithmic duotyping system, compared to 10 inthe subtyping system in Figure 4.3.
Duotyping reorganizes and uni�es the rules in a more abstract style. All rules, except
rule ����AS����, rule ����AS������ and rule ����AS����� unify a pair of subtyping rules.
In essence one of the pairs is simply the result of �ipping arguments and the mode. For
instance, rule ���AS���� �ips rule ���AS���� (and vice-versa), rule ���AS����L �ips rule ���AS���L (and vice-versa) and so on. While the de�nition of type splitting is extended, thesubtyping rules are very similar to the modular BCD subtyping rules in Figure 3.2. Besides
the generalization of mode, the key di�erence is that the left-hand side type in rule ����AS�
���L and rule ����AS����R is splittable rather than being restricted to intersections. As aconsequence, rule ����AS������ has an additional condition.
Strictly speaking, the inclusion of the duality rule (rule ����AS�����) means that the system
is not fully algorithmic. A naive implementation could apply the duality rule inde�nitely, thus
resulting in a non-terminating function. However, the set of rules with the duality rule ismorally algorithmic. As illustrated by Oliveira, Cui, and Rehman [OCR20], in implementation
we can use a Boolean �ag to prevent repeated �ipping with a case similar to the duality rule.
We will see this approach in Section 4.4 when we illustrate our Haskell implementation.
From duotyping to subtyping: deriving the subtyping rules. As we have mentioned,
the algorithmic subtyping rules can be derived from the duotyping formulation by specializing
the mode. Take rule ����AS����L as an example:
����AS����L����

Ordinary B

A1

A1

0 B

A

A ⇤ A20 B

A1

A ⇤ A2A1

0 B

����AS����L������

Ordinary B

A

0 B

52

The rules above are the result of specializing rule ����AS����L to subtyping and supertyping,respectively. To make them compatible with the subtyping style, all judgments in supertyping
mode need to be �ipped via the duality rule. After that, each instances agree with rule ���AS����L and rule ���AS���L respectively. Note that rule ���AS���L has more restrictions(Ordinary A and Ordinary B) than rule ����AS����L������. These two conditions are essentially the ordinary conditions that arise from the use of the duality rule to convert supertyping
into subtyping.
The order of rules Except for rule ����AS���� and rule ����AS������, other rules have
duotyping judgements as premises, which means the algorithm will search further after itmatches its goal with the rule. Without the gray-highlighted conditions, it is possible for one
duotyping judgement to satisfy multiple rules at the same time, i.e. rule ����AS���� andrule ����AS����� for A1 | A2 0 B1 & B2 . Thus we use the ordinary-type conditions in gray tomake these recursive rules disjoint and sort them in the following order: 1) rule ����AS����;2) rule ����AS����L and rule ����AS����R; 3) rule ����AS����� and rule ����AS������.
Then a subtyping (or supertyping) judgement cannot match later rules once it satis�es theconditions of one rule (regardless of the satisfaction of the subtyping premises). For example,
rule ����AS����� cannot be used to �ip A1 | A2 0 B unless Ordinary B. In that case, rule ����AS���� will be applied to the �ipped goal B 0 A1 | A2 , as A1 A1 | A2 ⇤ A2 . To justify theorder, we prove the following lemmas:
Lemma 4.1 (Inversions on Splittable Types). Assuming A 30 B,• if B1• if A1• if A1B 3 ⇤ B2 then A 30 B1 and A 30 B2 .

A 3 ⇤ A2 and Ordinary3 B then A1 30 B1 or A2 30 B2 .
A 3 ⇤ A2 then A1 30 B and A2 30 B.

• if Ordinary3 A and B1

B 3 ⇤ B2 then A 30 B1 or A 30 B2

An inversion lemma tells us that it is safe to prioritize certain rule in some cases. The �rst
one is for rule ����AS����: if a subtyping (or supertyping) judgement holds, and its right-handside type is splittable under the mode, then it must satisfy rule ����AS����. The second one isfor rule ����AS����L and rule ����AS����R. It has an extra condition Ordinary3 B, whichmeans the judgement does not meet the conditions of rule ����AS����. The next two are forthe rule ����AS�����, with it we can unfold the duotyping rules by mirroring rule ����AS����, rule ����AS����L and rule ����AS����R with extra conditions. For instance, the dual53

rule of rule ����AS���� would be:����AS����������

A1

Ordinary3 A
A 3 ⇤ A2

Ordinary3 B

A1 30 B

A30 B

A2 30 BIn short, there are two principles: rule ����AS���� before rule ����AS����L and rule ����AS����R; the dual of rule ����AS���� before the dual of rule ����AS����L and rule ����AS����R.
Since the order we choose obeys the principle, we can prove the duotyping system with the grayconditions is equivalent to the system without such conditions. The same applies to the derived
subtyping system (Figure 4.3). Violating the principles may lead to false-negative results (i.e.
an incomplete implementation with respect to the algorithmic speci�cation). For example, if
an algorithm tries rule ����AS����L and rule ����AS����R before rule ����AS����, it will
reject Int & Char 0 Int & Char because both rule ����AS����L and rule ����AS����R fail.

4.3.3

Metatheory

Here we present some theorems that connect the two systems in subtyping style (introducedin Section 7.2.2) with the two systems in duotyping style.
Theorem 4.1 (Equivalence of Declarative Systems). For any type A B,
• if A 3 B, then 3 =• if A 6 B, then A

and A 6 B, or 3 =B and Band B 6 A.

A.

The �rst property in the above theorem states the declarative duotyping system (Figure 4.4)
is sound with respect to the declarative subtyping (Figure 4.1), no matter whether the judgement
is in subtyping or supertyping mode. The second property is the completeness of the duotyping
system.
After proving that the declarative subtyping relation is equally transformed into duotyping,
we show that the algorithmic duotyping system can be mapped into the subtyping in Figure 4.3
as well. Firstly, the de�nitions of ordinary and splittable types are equivalent to the intersectionand union- ordinary types and splittable types de�ned in Figure 4.2.
Lemma 4.2 (Equivalence of Ordinary and Splittable Types). For any type A,• 9⌫ , A = ⌫ if and only if Ordinary A.
• 9⌫ • , A = ⌫ • if and only if Ordinary A.
• B1

A ⇤ B2 if and only if B1

A ⇤ B2 .
54• B1 ⇣ A ⌘ B2 if and only if B1

A ⇤ B2 .

Then the soundness and completeness of the algorithmic subtyping (Figure 4.3) regarding
to the algorithmic duotyping (Figure 4.5) can be established.
Theorem 4.2 (Equivalence of the Algorithmic Systems). For any type A B,
• if A <: B, then A

0 B and B• if A 30 B, then 3 =0 A.

and A <: B, or 3 =and B <: A.

Properties for the algorithmic system With a set of duotyping rules, one can reason
about not only subtyping and supertyping, but also two modes together, which helps to unify
theorems and proofs. Here we build the theorems on the two duotyping systems. Thanks to theequivalence between subtyping and duotyping systems, these theorems justify the algorithmic
subtyping system (Figure 4.3) with respect to the declarative subtyping system (Figure 4.1) as
well.
One of the key properties that validate the algorithmic system is the equivalence to thedeclarative system.
Theorem 4.3 (Soundness and Completeness of Algorithmic Duotyping). A 30 B if and only if
A 3 B.
To establish it, re�exivity and transitivity are a must.

Theorem 4.4 (Re�exivity of the Algorithmic Duotyping). A 30 A.

During the proof we need to consider whether a type can be split or not. The process relies
on two facts: First, types can be divided into ordinary types and splittable ones under any
mode. Second, type splitting produces unique results.
Lemma 4.3 (Types are Either Ordinary or Splittable). For any type A and any mode 3,• Ordinary3 A or B

• Ordinary3 A and B

A 3 ⇤ C for some type B and C.
A 3 ⇤ C cannot both hold.

Lemma 4.4 (Determinism of Type Splitting). If A1
and B1 = B2 .

A 3 ⇤ A2 and B1

A 3 ⇤ B2 then A1 = A2

With re�exivity, the soundness of type splitting can be obtained directly. This suggests thatthe intersection (or union, according to the mode) of the splitting results is isomorphic to theoriginal type.
Lemma 4.5 (Soundness of Splitting). If B1

A 3 ⇤B2 then A 30 (B1 3? B2 ) and (B1 3? B2 ) 30 A.
55

Table 4.1: Summary of the proof scripts.

File

SLOC Description

TypeSize.v
De�nitions.v
Duotyping.v
Equivalence.v
Subtyping.v
DistAnd.v
DistSubtyping.v

Total

55 De�nes the size of type for induction measures.
397 Contains de�nitions for all relations. It is generated by the tool
Ott [Sew+07].
966 Contains Lemma 4.1, Theorem 4.3, Theorem 4.4, Lemma 4.3,
Lemma 4.4, Lemma 4.5, and Theorem 4.5.
159 Relates the two declarative systems and the two algorithmic systems, respectively. It contains Theorem 4.1, Lemma 4.2, and Theorem 4.2.
663 Contains some lemmas about the two subtyping systems. Three ofthem are used in the proof of Theorem 4.2
28 Justi�es one statement in the paper. It shows that the rule S�����A�� (in Figure 4.1) is omittable.
832 A stand-alone �le, which contains the two subtyping systems in
Section 7.2.2, as well as related proofs that algorithmic subtyping(Figure 4.3) is decidable and equivalent to the declarative system(Figure 4.1).
3,100 (2,240 excluding the last two �les)Compared with re�exivity, transitivity is straightforward since the ordinary conditions
eliminate most overlapping.
Theorem 4.5 (Transitivity of the Algorithmic Duotyping). If A 30 B and B 30 C then A 30 C.
Decidability is the other key property. Its proof replays the algorithm in duotyping style.

Theorem 4.6 (Decidability of the Algorithmic Duotyping). It is decidable whether A 30 B.

4.3.4

Coq Formalization and Proof Statistics

All the lemmas and theorems are formalized and veri�ed in the Coq proof assistant [Coq21]. We
use !81) 02C82B.E from the TLC Coq library [CP], which de�nes a collection of general-purpose
tactics. In the formalization, a variant of algorithmic duotyping in Figure 4.5 is formalized
where the rule ����AS����� is eliminated and dual rules are made explicit. The two variants(with and without dual rules) are proved to be equivalent in Coq, and some of the lemmas ofalgorithmic duotyping are proved using this variant. We also provide a stand-alone �le for thetwo subtyping systems in Section 7.2.2. The proof scripts include 3,100 lines of code. Table 4.1
provides a brief summary of the �les in the formalization, their number of source lines of code
(SLOC), and a brief description of the content.

56split :: Mode ! Type ! Maybe (Type, Type)
split MSub (TArrow a b)
| Just (b1, b2) <- split MSub b= Just (TArrow a b1, TArrow a b2)
split MSub (TArrow a b)
| Just (a1, a2) <- split MSuper a= Just (TArrow a1 b, TArrow a2 b)
split mode (TOp m a b)
| mode == m
= Just (a, b)
split mode (TOp m a b)
| Just (a1, a2) <- split mode a= Just (TOp m a1 b, TOp m a2 b)
split mode (TOp m a b)
| Just (b1, b2) <- split mode b= Just (TOp m a b1, TOp m a b2)
split _ _ = Nothing-- duo-Sp-arrowR-- duo-Sp-arrowL-- duo-Sp-and-- duo-Sp-orL-- duo-Sp-orR

Figure 4.6: Haskell implementation of splittable types in the algorithmic duotyping system

4.4

A Functional Implementation in Haskell

After working out through splittable types and duotyping, we now show the Haskell
implementation of the algorithmic duotyping formulation presented in Figure 4.5. Our implementation exploits the extra ordinary-type conditions in the duotyping rules to avoid too muchbacktracking, and thus result in a more e�cient implementation.

4.4.1

Abstract Syntax and Modes

The datatype de�nitions for the implementation are:data Mode = MSub | MSuper
deriving (Eq, Show)
data Type = TInt | TTop | TBot | TArrow Type Type | TOp Mode Type Typederiving (Eq, Show)

The datatype Mode models the two modes, which stand for the two directions of duotyping
judgements: MSub for subtyping; and MSuper for supertyping. The datatype Type models theabstract syntax of types. The �rst four constructors directly correspond to the integer, top,bottom and arrow types. In the last constructor, we make use of the mode to unify intersection
and union types. Speci�cally, TOp MSub A B means A & B, and TOp MSuper A B means A | B.

57

4.4.2Type Splitting

Figure 4.6 shows the implementation of type splitting. The type splitting function follows
the formalization directly. The mode speci�es whether it is for intersection- (MSub) or union(MSuper) splittable types. The function splits the given type when possible and returns Nothing
if the type is ordinary and cannot be split. The actual implementation makes interestinguse of pattern guards [EP00]. For instance, in the �rst case we have to analyse the result of
split MSub b to decide whether to execute the code on the right side of = or fail and move tothe next case. If the pattern Just (b1,b2) does not match the result then we fail and move tothe next case. Regarding the order of cases, we can divide them (denoted by the corresponding
rules) into three groups based on the form of the split type: 1) rule ����S�������R andrule ����S�������L; 2) rule ����S�����; 3) rule ����S����L and rule ����S����R. While
the order inside the group is restricted by the rules, the order across groups does not matter.
Actually, the precedence among rules is merely assigned to avoid non-determinism of the split
result, and the order itself is insigni�cant.

4.4.3

Duotyping and Subtyping

Figure 4.7 shows the implementation of duotyping. The code uses auxiliary functions for�ipping modes and selecting > or ? by mode, which are trivial to implement:
flipmode :: Mode ! Modeflipmode MSub = MSuper
flipmode MSuper = MSubselect :: Mode ! Typeselect MSub

= TTopselect MSuper = TBot

The main function check takes two types and a mode as inputs (following the duotyping
judgment A 30 B), and one additional Boolean �ag. The output is a Boolean which denotes if
the judgement holds. The mode is �ipped when it does not �t with the code corresponding torule ����AS����, rule ����AS������, rule ����AS����, rule ����AS����L, and rule ����AS����R, according to rule ����AS�����. In such a case we recheck the resulting judgement,
which is equivalent to check the initial judgement by the dual of the above rules. A Boolean
�ag is used to make sure such �ipping only happens at most once for one judgement. This
implementation approach for duotyping follows the approach proposed by Oliveira, Cui, andRehman [OCR20]. The arrow rule is the last one to be checked because �ipping the goal does
not a�ect it. At that point, we know that types on both sides are fully ordinary, and both ofthem are not Int. Thus, if rule ����AS������ fails, a negative result will be returned. Finally,
to obtain a function that checks the subtyping of two types we can simply have:58

check :: Mode ! Type ! Type ! Bool ! Boolcheck _ TInt TInt _ = True-- duo-AS-int
check mode _ t _-- duo-AS-bound| select mode == t
= Truecheck mode a b _-- duo-AS-and| Just (b1, b2) <- split mode b= (check mode a b1 False) && (check mode a b2 False)
check mode a b _-- duo-AS-andL
duo-AS-andR| Just (a1, a2) <- split mode a= (check mode a1 b False) || (check mode a2 b False)
check mode a b False = check (flipmode m) b a True-- duo-AS-dual
check mode (TArrow a1 a2) (TArrow b1 b2) _-- duo-AS-arrow= (check (flipmode m) a1 b1 False) && (check mode a2 b2 False)
check _ _ _ _ = False
Figure 4.7: Haskell implementation of the duotyping checking algorithm
sub :: Type ! Type ! Bool

sub a b = check MSub a b False

4.4.4

Eliminating Backtracking

Note that no backtracking is employed during the process, except for the rule ����AS����Land rule ����AS����R: both rules need to be considered if the �rst attempt fails. The lackof other forms of backtracking is justi�ed by our duotyping rules with ordinary conditions,which follows Lemma 4.1. Rules that involve no recursion are put at the start of the function.
Rule ����AS������ only returns a positive result so it is always safe to prioritize it among
overlapping rules. Rule ����AS����� overlaps with rule ����AS������, but in that case, after
rule ����AS�����, the �ipped goal only matches with rule ����AS������, which makes nodi�erence to directly applying rule ����AS�����. Meanwhile, with the current order that weuse, the ordinary-type conditions are guaranteed by previous rules which handle splittabletypes, and therefore not appear in the code.
An alternative implementation is to check rule ����AS������ and its dual (for > and?) and rule ����AS������ before the rules for splittable types (regardless of the ordinary
conditions), which can potentially save some space and time. It can be justi�ed by the following
inversion lemma:
Lemma 4.6 (Inversion of ����AS������). If A1 ! A2 30 B1 ! B2 then A1 30 B1 and A2 30 B2 .
If both types in a duotyping judgment are arrow types, their input types and output types
must satisfy the duotyping relation respectively as required by the rule ����AS������. Thatmeans it is safe to put the arrow case before others in the Haskell implementation.
59

Summary This chapter shows a new algorithm for deciding subtyping (and logical entailment) in the presence of union types, intersection types and distributivity rules. Such algorithms
are known to be challenging to implement and formalize. Most previous work has addressedsimilar problems using a pre-processing step to transform types into a normal form, before
comparing types for subtyping. Here we present a new algorithm that directly compares source
types for subtyping, without a pre-processing phase.
Splittable types are key to our algorithm. From the last chapter to this one, we illustratethat splittable types can scale up to systems with union types and additional distributivity
rules. Moreover, duotyping proposed by Oliveira, Cui, and Rehman helped in designing avery symmetric formulation of algorithmic subtyping. One interesting aspect revealed by
duotyping is that minimal relevant logic is not fully symmetric from the point of view of duality.
As discussed in Section 4.2.2, minimal relevant logic lacks some “dual” axioms, making thesubtyping rules not completely dual. This was a surprise to us. Although the absence of bottom
types in minimal relevant logic created an obvious imbalance with respect to duality (whichis easy to correct), we only detected the later issue with the duotyping design. Nonetheless,duotyping was still helpful to organize many of the other rules and relations, and leads to an
implementation that can exploit duality to avoid extra code for dual cases. Overall we believethat both splittable types and duotyping are helpful in the design of expressive subtyping
relations, and hope that this work encourages further exploration and use of both ideas.

60

Part II
Calculi with the Merge Operator

61

CHAPTER 5

T�� B���� S�����: _8 ��� ���T����D������� O���������� S��������
This chapter presents the type system and the operational semantics of the _8 calculus. It
captures the basic functionality of the merge operator with a simple subtyping relation ofintersection types, similar to the subtyping in Figure 3.1. This calculus is a variant of the original_8 calculus [OSA16] (which is inspired by the calculus of Dun�eld [Dun14]) with �xpoints andexplicitly annotated lambdas instead of unannotated ones. Explicit annotations are necessary
for the type-directed operational semantics of _8 to preserve determinism. The TDOS can handle
non-terminating programs, while some calculi using elaboration and coherence proofs [BOS18;
Bi+19] do not support non-terminating programs. Dun�eld’s calculus supports recursion, but
its elaboration semantics is incoherent.

5.1

Overview

A key advantage of the merge operator is its generality and the ability to model various
programming language features, which we have seen in Section 2.5. However, there arechallenging problems arising from the merge operator. In particular, the combination of themerge operator and subtyping is problematic. In this section, we revisit those challenges.

5.1.1

A Type-Driven Semantics for Type Preservation

As we have discussed in Section 2.2, the direct semantics of merges proposed by Dun�eld is
non-deterministic and lacks type safety. An essential problem is that the semantics cannot
ignore the types if the reduction is meant to be type-preserving. Dun�eld notes that “For typepreservation to hold, the operational semantics would need access to the typing derivation”. To
avoid run-time type checking, we design an explicitly typed calculus _8 and use contextual

63type information like annotations to guide reduction. Nevertheless, it is easy to design source
languages that infer some of the type annotations and insert them automatically to create valid_8 terms as we will see in Section 8.2.1. We discuss the main challenges and key ideas of thedesign of _8 next.
Annotations and type-driven reduction. A merge like 1 ,, true has multiple meanings
under di�erent types (e.g. Int or Bool). Eventually, we have to extract some components via theelimination of merges, which is a key issue when designing a direct operational semantics fora calculus with the merge operator. A non-deterministic semantics could allow e1 ,, e2 õ! e1
and e1 ,, e2 õ! e2 without any constraints.
1 ,, true1

1 ,, truetrue

To obtain a non-ambiguous and type-safe semantics, we uses (up)casts to ensure that values
have the right form during reduction. One can use an explicit type annotation to select someparticular components from a term. While both the above reductions are valid in Dun�eld’ssemantics, in _8 they are only triggered when the expected type of the context is explicit, like:(1 ,, true) : Int õ! 1

(1 ,, true) : Bool õ! true

Casting can be viewed as a type-guided version of Dun�eld’s operational semantics. The
type information “�lters” reductions that are invalid due to a type mismatch and lead to a
deterministic result.
(1 ,, true) : Int 6õ! true

(1 ,, true) : Bool 6õ! 1

Note that in _8 the expression 1 ,, true without any type annotation is a value and does not
reduce.
Casting in action. Written as v õ!A v 0, the casting relation takes a value v and a type A as
inputs, and produces a value v 0 of A as output. Casting is used when we want some value tomatch a type. Speci�cally, we consider two contexts: [·] : A and (_x. e : A ! B) [·].
S���������

v õ!A v

0v : A õ! v 0S��������

v õ!A v 0(_x. e : A ! B) v õ! (e[x 7! v 0]) : B

We have seen that when reduction meets a value E with a type annotation , it further
reduces E against the type . Consider a simple merge of primitive values 1 ,, true ,, ‘c’ with an64

annotation Int & Char. Using rule S���������, casting is invoked, resulting in:
1 ,, true ,, ‘c’ õ!Int & Char 1 ,, ‘c’
We can also cast the same value by an equivalent type but where the two types in the intersection
are interchanged:
1 ,, true ,, ‘c’ õ!Char & Int ‘c’ ,, 1
The two valid reductions illustrate the ability of casting to create a value that matches exactlywith the shape of the type.
Casting enables us to drop certain parts from a term. Very often, it is necessary for us to do
so to satisfy the disjointness constraint and obtain an unambiguous merge.
Consider a function _x : Int. x ,, false. For its body to be well-typed, x cannot contain aboolean. Hence, when the function is applied to 1 ,, true, we cannot directly substitute theargument in (which leads to (1 ,, true ,, false) : Int & Bool). Instead, it is cast to Int to resolve thepotential con�ict.
((_x : Int. x ,, false) : Int & Bool ! Int & Bool) (1 ,, true)õ!

(1 ,, false) : Int & Boolõ! 1 ,, false

Note that, even an identity function could change its input value.
(_x. x : Int ! Int) (1 ,, ‘c’) õ! 1 : Int
That may look strange from the view of the subtyping models used in conventional OOP languages, where upcasting has no runtime impact. However, instead of the inclusive semantics,
we employ the coercive semantics of subtyping like the language Forsythe [Rey88]. The subtyping relation of two types does not imply the subset relation between their set interpretations(the set of its inhabited values), but rather corresponds to an implicit conversion function. A
value of a subtype cannot be directly used as a value of its supertype, only after conversion it
becomes a value of the supertype.
Previous work on intersection types with the merge operator [Dun14; OSA16; AOS17;
BOS18; Bi+19] employ an elaboration semantics with coercive subtyping: subtyping triggers
coercions, and such coercions are used by elaboration to transform values. For example, amerge is translated into a pair, and the coercion from Int & Char to Int is a projection on thepair which takes the �rst component. Our casting reduction also re�ects the operational e�ectof subtyping and changes the underlying value.

655.1.2The Challenges of Functions

Some of the hardest challenges in designing the semantics of _8 involve functions.
Return types matter. Unlike primitive values, we cannot tell the type of a function by its
form. Although the input type annotation of lambdas helps beta reduction, it is not enough todistinguish among multiple functions in a merge (e.g. (_x. x + 1) ,, (_x. true)) without run-time
type checking. To be able to select the right function from a merge, in _8 , all functions areannotated with both the input and output types. With such annotations we can deal with
programs like:((_f . f 1 : (Int ! Int) ! Int)) ((_x. x + 1 : Int ! Int) ,, (_x. true : Int ! Bool))In this program we have a lambda that takes a function 5 as an argument and applies it to 1.
The lambda is applied to the merge of two functions of types Int ! Int and Int ! Bool. We
select the wanted function by comparing their type annotations to the target type in casting.
Otherwise runtime type checking would be necessary to recover the full type of functions.
Annotation re�nement. Subtyping of intersection types leads to selecting and dropping
components from merges. On the other hand, the subtyping of arrow types requests for typere�nements on lambda expressions. Consider a single function _x. x ,, false : Int ! Int & Bool to
be cast by type Int & Bool ! Int. To let the function return an integer when applied to a mergeof type Int & Bool, we must change either the lambda body or the embedded annotation. Since
reducing under a lambda body is not allowed in call-by-value, _8 adopts the latter option, andtreats the input and output annotations di�erently. The input annotation should not be changed
as it represents the expectation of the function and helps to adjust the input value before substitution. The next example demonstrates that re�ning the input type annotation could resultin ambiguity (having both true and false in one merge), which we prevent using rule S��������.

õ!
õ!

(_x. x ,, false : Int ! Int & Bool : Int & Bool ! Int) (1 ,, true){ wrong step here: not keeping the input annotation in casting }(_x. x ,, false : Int & Bool ! Int) (1 ,, true){ by rule S�������� }(1 ,, true ,, false) : Int(Does not type-check!)

The output annotation, in contrast, must be replaced by Int, representing a future reduction
to be done after substitution. The output of the application then can be thought of as an integer
and can be safely merged with another Boolean. The next example illustrates how _8 correctly
deals with annotation re�nements:

66

õ!
õ!
õ!

((_x. x ,, false : Int ! Int & Bool : Int & Bool ! Int) (1 ,, true)) ,, true
{ keep the input annotation and change the output one }((_x. x ,, false : Int ! Int) (1 ,, true)) ,, true
{ by rule S�������� }(1 ,, false) : Int ,, true
{ by rule S��������� }1 ,, true

This example is similar to the previous one but, additionally, we merge the expression withtrue to demonstrate that the output type after beta-reduction, will �lter the resulting merge.
Some calculi avoid the problem of function annotation re�nement by treating annotatedlambdas as values. For example, the target language of the original _8+ [BOS18] does not reduce
a value wrapped by a coercion in a function form. In the blame calculus [WF09], a value with acast from an arrow type to another arrow type is still a value.

5.1.3

Disjoint Intersection Types and Consistency for Determinism

Even if the semantics is type-directed and it rules out reductions that do not preserve types, it
can still be non-deterministic. To solve this problem, we employ the disjointness restriction thatis used in calculi with disjoint intersection types [OSA16] and the novel notion of consistency.
Both disjointness and consistency play a fundamental role in the proof of determinism.
Disjointness. Two types are disjoint (written as A ⇤ B), if any common supertypes that they
have are top-like types (i.e. supertypes of any type; written as eC d).
De�nition 5.1 (Disjoint speci�cation). A ⇤ B , 8⇠ if A 6 C and B 6 C then eC d
If two types are disjoint (e.g. (Int & Char) ⇤ Bool), their corresponding values do not overlap(e.g. 1 ,, ‘c’ and true). The only exceptions are top-like types, as they are disjoint with any
type [AOS17]. Since every value of a top-like type has the same e�ect, casting uni�es them
to a �xed result. Thus the disjointness check in the following typing rule guarantees that e1
and e2 can be merged safely, without any ambiguities. For example, this typing rule does not
accept 1 ,, 2 or true ,, 1 ,, false, as two subterms of the merge have overlapped types (in this case,the same type Int and Bool, respectively).
T��������

` e1 ) A` e2 ) B` e1 ,, e2 ) A & B

A⇤B

Note that in this rule, ) denotes the synthesis mode in bidirectional typing. In typing judgementswith such a mode, types are synthesized from the term, rather than provided to be checked.
67Consistency. Recall the rule DS��������� in Dun�eld’s semantics: ee ,, e. It duplicatesterms in a merge. Similar things can happen in our casting relation if the type has overlapping
parts, which is allowed, for example, in an expression 1 : Int & Int. Note that in this expression
the term 1 can be given type annotation Int & Int since Int 6 Int & Int. During reduction, castingis eventually used to create a value that matches the shape of type Int & Int by duplicating the
integer:
1 õ!Int & Int 1 ,, 1Note that the disjointness restriction does not allow sub-expressions in a merge to have thesame type: 1 ,, 1 cannot type-check with rule T��������. To retain type preservation, there is a
special typing rule for merges of values, where a novel consistency check is used (written asv1 ⇡B?42 v2 ):T���������

· ` v1 ) A· ` v2 ) B` v1 ,, v2 ) A & B

v1 ⇡B?42 v2This rule is not designed to accept more programs written by users. Instead, it takes care of
expressions like 1 ,, 1 that may appear at runtime. Mainly, consistency allows values to haveoverlapped parts as far as they are syntactically equal. For example, 1 ,, true and 1 ,, ‘c’ areconsistent, since the overlapped part Int in both of merges has the same value. true and ‘c’ areconsistent because they are not overlapped at all. But 1 ,, true and 2 are not consistent, as they
have di�erent values for the same type Int. When two values have disjoint types, they must
be consistent. For merges of such values, both rule T��������� and rule T�������� can beapplied, and the types always coincide. In _8 , consistency is de�ned in terms of casting: 1
De�nition 5.2 (Consistency). Two values E 1 and E 2 are said to be consistent (written v1 ⇡B?42 v2 )if, for any type , the casting result for the two values is the same.
v1 ⇡B?42 v2 , 8A if v1 õ!A v10 and v2 õ!A v20 then E 10 = E 20
Although the speci�cation of consistency is decidable and an equivalent algorithmic de�nition
exists, an algorithmic de�nition is not required. In practice, in a programming language
implementation, the rule T��������� may be omitted, since, as stated, its main purpose isto ensure that run-time values are type-preserving. On the other hand, after preservation isproved in metatheory, run-time values are guaranteed to be well-typed and therefore there isno need to employ run-time type checking.
Note that the original _8 [OSA16] is stricter than our variant of _8 and forbids any intersection
types which are not disjoint. That is to say, the term 1 : Int & Int is not well-typed because theintersection Int & Int is not disjoint. In the original _8 [OSA16] calculus disjointness checking
1A similar restriction was proposed by Reynolds but was not used in Forsythe’s type system [Rey88].

68

is done by de�ning type well-formedness and forbidding all intersections of two non-disjoint
types. However this approach is more conservative and less expressive.
The idea of allowing unrestricted intersections, while only having the disjointness restriction for merges, was �rst employed in the original _8+ calculus [BOS18]. _8 follows such an ideaand 1 : Int & Int is well-typed in _8 . Allowing unrestricted intersections adds extra expressive
power. For instance, in calculi with polymorphism, unrestricted intersections can be used
to encode bounded quanti�cation [CW85], whereas with disjoint intersections only such an
encoding does not work [Bi+19; Xie+20]. Various authors, including Pierce and Castagna have(informally) observed that some form of bounded quanti�cation can be encoded via (unrestricted) intersection types [Pie91; CX11]. Xie et al. formalize this encoding precisely [Xie+20].
For further details on this encoding, as well as to why unrestricted intersections are needed,
we refer to their work.

5.2

Syntax, Subtyping and Typing

This section presents the type system of _8 .

5.2.1

SyntaxThe syntax of _8 is:
Types
Expressions
ValuesContexts
Typing modes

,⌫
4
E
,

::=
::=
::=
::=
::=

Int | > | A ! B | A & B
x | i | > | e : A | e1 e2 | _x. e : A ! B | e1 ,, e2 | �x x : A. e
8 | > | _x. e : A ! B | v1 ,, v2· | , x :A)|(

Types. Meta-variables A and B range over types. Two basic types are included: the integer
type Int and the top type >. Function types A ! B and intersection types A & B can be used toconstruct compound types.
Expressions. Meta-variable 4 ranges over expressions. Expressions include some standard
constructs: variables (G); integers (8); a canonical top value >; annotated expressions (e : A); andapplication of a term 4 1 to term 4 2 (denoted by 4 1 4 2 ). Lambda abstractions (_x. e : A ! B) musthave a type annotation A ! B, meaning that the input type is and the output type is ⌫. The
expression e1 ,, e2 is the merge of expressions 4 1 and 4 2 . Finally, �xpoints �x x : A. e (which also
require a type annotation) model recursion.
Values, contexts, and typing modes. Meta-variable v ranges over values. Values include
integers, the top value >, lambda abstractions, and merges of values. Typing context tracks
69

A <: B

(Subtyping in _8 )S����S������

S��������

A <: B

A1 ! A2 <: B1 ! B2

B1 <: A1eBd

Int <: Int
S�������1S�������2

A1 & A2 <: A3

A1 & A2 <: A3

A1 <: A3A2 <: B2

S�������

A2 <: A3A1 <: A2A1 <: A3A1 <: A2 & A3
(Top-Like Types)

eAd
TL������

TL����

TL����

eBd

eAd

eA & Bd

eA ! Bde>deBd

A ⇤0 B(Algorithmic Disjointness)D����LD����R> ⇤0 A

A ⇤0 >

D����LA1 ⇤0 BA2 ⇤0 B

A1 & A2 ⇤0 B

D����R

A ⇤0 B1

A ⇤0 B2

A ⇤0 B1 & B2

D�I��A��Int ⇤0 A1 ! A2

D����A��

D����I��A2 ⇤0 B2

A1 ! A2 ⇤0 Int

A1 ! A2 ⇤0 B1 ! B2

Figure 5.1: Subtyping, top-like types, and disjointness of _8 .

bound variables (x) with their type A. , stands for the mode of a bidirectional typing judgment:) is the synthesis mode; ( is the checking mode. They di�er on whether the type is an
output (inferred) or an input (to be checked). The details of bidirectional type checking will be
discussed in Section 5.2.3.

5.2.2

Subtyping and Disjointness

Subtyping. The subtyping rules are shown at the top of Figure 5.1. Here we follow theformalization by Davies and Pfenning, except that we generalize rule S������ to allow any
top-like types to be supertypes of any type. The original subtyping relation is known to bere�exive and transitive [DP00]. We proved the re�exivity and transitivity of the extended
subtyping relation as well.

70Top-like types and arrow types. As suggested by its name, a top-like type is both asupertype and a subtype of >. Besides >, top-like types contain intersection types like > & >.
In the middle of Figure 5.1 is its formal de�nition. Notably, rule TL������ allows arrow
types to be top-like when their return types are top-like. This enlargement of top-like types is
inspired by the following rule in BCD-style subtyping [BCD83]:>6>!>

BCD�������

We will come back to our motivation for allowing such top-like types in Section 5.2.3.
Disjointness. Section 5.1.3 presented the speci�cation of disjointness. Such a speci�cation
is a liberal version of the original de�nition in _8 . In our de�nition A and B can be top-liketypes, which was forbidden in _8 . An equivalent algorithmic de�nition of disjointness (A ⇤0 B)
is presented on the bottom of Figure 5.1, which is the same as the de�nition in the original _8+
calculus.
Lemma 5.1 (Disjointness properties). Disjointness satis�es:
1. A ⇤ B if and only if A ⇤0 B.
2. if A ⇤ (B1 ! C) then A ⇤ (B2 ! C).
3. if A ⇤ B & C then A ⇤ B and A ⇤ C.

5.2.3

Bidirectional Typing

We use a bidirectional type system for _8 to avoid a general subsumption rule, which causes
ambiguity in the presence of a merge operator. A bidirectional type system has two kinds oftyping judgements, each associated with one mode. The checking judgement ` e ( A saysthat in the typing environment the expression 4 can be checked against type , while thesynthesis judgment ` e ) A infers the type A from and e. Unlike the original type systemof _8 (Figure 8.2), types have no well-formedness restriction; and expressions like 1 : Int & Int
are allowed. This generalization is inspired by the original _8+ calculus [BOS18], which is the�rst to introduce unrestricted intersections to a calculus which supports disjoint intersection
types.
In Figure 5.2, most typing rules directly follow the bidirectional type system of the original_8 , including the merge rule T��������, where disjointness is used. When two expressions
have disjoint types, any parts from each of them do not overlap in the types. Therefore, theirmerge does not introduce ambiguity. With this restriction, rule T�������� does not accept
expressions like 1 ,, 2 or even 1 ,, 1. On the other hand, the novel rule T��������� allows
71

A⇤B

(Applicative Distribution)`e , A

T������`> ) >

T������
` e1 ) C
T�������`e ( A` (e : A) ) A

AD����

AD����A��

A!B⇤A!B>⇤>!>(Bidirectional Typing in _8 )T������
x:A2

T������
` i ) IntC⇤A!B

` e1 e2 ) B`x ) A

T������`e ) A` e2 ) B` e1 ,, e2 ) A & B

T���������
· ` v1 ) A` �x x : A. e ) A` _x. e : A ! B ) A ! B

T��������
` e1 ) A` e2 ( AT������
, x :A ` e ( AT������
, x :A ` e ( B· ` v2 ) B` v1 ,, v2 ) A & B

A⇤B

v1 ⇡B?42 v2

A <: B`e ( B

Figure 5.2: Typing of _8 .

consistent values to be merged regardless of their types. It accepts 1 ,, 1 while still rejecting
1 ,, 2. The consistency speci�cation used in rule T��������� is given in De�nition 5.2. It isfor values only, and values are closed. Therefore the premises should have an empty context(denoted by ·). As discussed in Section 5.1.3, together the two rules support the determinism
and type preservation of the TDOS, and rule T��������� does not need to be included in an
implementation. The type system with the remaining rules is algorithmic. The rule T������ is
new and allows �xpoints. In addition, two rules are revised: rule T������ and rule T������.
Since lambdas are now fully annotated in the current system, rule T������ is changed fromchecking to synthesis mode. Next, we will discuss how rule T������ is generalized with theapplicative distributivity relation.
Applicative distribution and rule T������. The top of Figure 5.2 shows the applicative
distribution relation, which relates a type with one of its arrow supertypes. Applicative
distribution is used in rule T������, where a term is expected to play the role of a function.
Therefore a term of type > can be used as if it has type > ! >, and be applied to any terms.
For example, > 1 is allowed and it evaluates to >.

72

Top-like types and merges of functions. We can �nally come back to the motivation toallow arrow types in top-like types and depart from Dun�eld’s calculus. If no arrow types are
top-like, two arrow types A1 ! A2 and B1 ! B2 are never disjoint in terms of De�nition 5.1, as
they have a common supertype A1 & B1 ! >. Consequently, we can never create merges withmore than one function, which is quite restrictive. For Dun�eld this is not a problem, because
she does not have the disjointness restriction. So her calculus supports merges of any functions(but its elaboration semantics is incoherent). In the original _8 an ad-hoc solution is proposed,by forcing the matter and employing the syntactic de�nition of top-like types in Figure 5.1 indisjointness, while keeping the standard rule A 6 > in subtyping. However this means that
top-like function types are not supertypes of >, which contradicts the intended meaning of a
top-like type. In contrast, the approach we take in _8 is to change the rule S������ in subtyping.
Now > 6 (A1 & B1 ! >) is derivable and A1 & B1 ! > is genuinely a top-like type. In turn,this makes merges of multiple functions typeable without losing the intuition behind top-liketypes.
Checked subsumption. Unlike many calculi where there is a general subsumption rule that
can apply anywhere, _8 employs bidirectional type checking, where subsumption is controlled.
The subsumption (rule T������) is in checking mode only. The checking mode is explicitly
triggered by a type annotation, either via the rule T�������, rule T������ or rule T������. The
annotation rule T������� acts as explicit subsumption and assigns supertypes to expressions,providing a suitable type annotation.
Calculi with a merge operator are incompatible with a general subsumption rule because it
cancels disjointness checking.
For example, with a general subsumption rule, we can directly use 1 ,, true as a term of typeInt since Int & Bool 6 Int. Then, merging 1 ,, true with the term false would type-check sincedisjointness simply checks whether the static types of merging terms are disjoint, and Int isdisjoint with Bool. But now, the merge contains two booleans, which would lead to ambiguity
if later we wish to extract a boolean value from the merge without access of typing derivation.
We should also remark that this issue of incompatibility with a general subsumption rule is
not unique to calculi with a merge operator. It shows up, for instance, in calculi with gradualtyping [ST07] and calculi with record concatenation and subtyping [CM91].
Typing properties. The bidirectional type-checking system has some properties that areimportant for the type soundness proof presented in Section 5.3. Firstly, each term has only one
synthesized type. Secondly, any well-typed term has a synthesized type, which is the principal
type. Thirdly, the type in a checking judgement can be replaced by a supertype.
Lemma 5.2 (Synthesis uniqueness). If` e ) A and73` e ) B , then= ⌫.

, ⌫ , ⇠ ::= Int | > | A ! B$A38=0A~ C~?4v õ!A v 0

(Casting in _8 )C�������

C�������

C���������

v õ!

_x. e : B1 ! B2 õ! (A1 !A2 ) _x. e : B1 ! A2ei õ!Int idC�����������

v1 õ!

v1 ,, v2 õ!

¬eA2 d>C�����������

v10

v20

v2 õ!

v10

v1 ,, v2 õ!

v20

A1 <: B1
C�������

v õ!A v1

B2 <: A2

v õ!B v2

v õ!A & B v1 ,, v2

Figure 5.3: The de�nition of casting in _8 .

Lemma 5.3 (Synthesis principality). If
and B 6 A.

` e ( A then there exists type B, s.t.

Lemma 5.4 (Checking subsumption). If` e ( A and A 6 B, then

5.3`e ) B` e ( B.

A Type-Directed Operational Semantics for _8

This section introduces the type-directed operational semantics for _8 . It makes use of thecontextual type information arising from type annotations to cast values in the reduction
process, forcing the value to match the type structure. We show that reduction is deterministic
and type sound. That is to say, there is only one way to reduce an expression according to thesmall-step relation, and the process preserves types and never gets stuck.

5.3.1

Casting of Values

The casting relation v õ!A v 0 reduces the value v under type A, producing a value v 0 that has
type A. It arises when given a value v of some type, where A is a supertype of the type of v,
and v needs to be converted to a value compatible with the supertype A.
In _8 , values and types have a strong correspondence. If a value is well-typed, its principal
type can be told directly by looking at its syntactic form. Casting gives a runtime interpretation
to subtyping, and the rules of are aligned in a one-by-one correspondence with the subtyping
formulation. While subtyping states what kind of conversions are valid at the type level, castinggives an operational meaning for such conversions on values.
Figure 5.3 shows the casting relation. Rule C������� expresses the fact that a top-like type
is the supertype of any type, which means that any value can be reduced under it. The top-liketype is restricted to be ordinary, to avoid overlapping with the rule C�������. In this basic
74

system, our de�nition of ordinary types is the same as the one given by Davies and Pfenning:types that are not intersections are ordinary.
The rule C������� indicates that under such a type, any value reduces to the top value >.
Recall that the top-like de�nition in Figure 5.1 includes arrow types whose return type is toplike, thus the rule C������� covers values with such top-like arrow types as well. Rule C�������
expresses that an integer value reduced under the supertype Int is just the integer value itself.
Rule C��������� states that a lambda value _x. e : A1 ! A2 , under a non-top-like type B1 ! B2 ,evaluates to _x. e : A1 ! B2 if B1 <: A1 and A2 <: B2 . The restriction that B1 ! B2 is not
top-like avoids overlapping with rule C�������. Importantly rule C��������� changes thereturn type of lambda abstractions, and keeps the input type, since it is needed at run-time (byrule S�������� which is discussed in Section 5.3.3).
Intersections and merges. In the remaining rules, we �rst decompose intersections. Then
we only need to consider ordinary types. We take care of the value by going through every
merge, until both the value and type are in a basic form. Rule C����������� and rule C����������� are a pair of rules for reducing merges under an ordinary type. Since the type is not
an intersection, the result contains no merge. Usually, we need to select between the left partand right part of a merge according to the type. The values of disjoint types do not overlap
on non-top-like types. For example, 1 ,, (_x. x : Int ! Int) õ!Int 1 selects the left part. For
top-like types, no matter which rule is applied, the reduction result is determined by the typeonly, as the rule C������� suggests.
Rule C������� is the rule that deals with intersection types. It says that if a value E canbe reduced to v1 under type A, and can be reduced to v2 under type B, then its reduction
result under type A & B is the merge of two results v1 ,, v2 . Note that this rule may duplicate
values. For example 1 õ!Int & Int 1 ,, 1. Such duplication requires special care, since the merge
violates disjointness. The specially designed typing rule (rule T���������) uses the notion of
consistency (De�nition 5.2) instead of disjointness to type-check a merge of two values. Notealso that such duplication implies that sometimes it is possible to use either rule C�����������
or rule C����������� to reduce a value. For example, 1,, 1 õ!Int 1. The consistency restriction
in rule T��������� ensures that no matter which rule is applied in such a case, the result isthe same.
Example. A larger example to demonstrate how casting works is:(_x. (x ,, ‘c’) : Int ! Int & Char) ,, (_x. x : Bool ! Bool) ,, 1

õ!Int & (Int!Int) 1 ,, (_x. (x ,, ‘c’) : Int ! Int)

The initial value is the merge of two lambda abstractions and an integer. The target type is
Int & (Int ! Int). Because the target type is an intersection, casting �rst employs rule C����
75��� to decompose the intersection into Int and Int ! Int. Under type Int the value reduces to
1, and under type Int ! Int it will reduce to _x. x ,, ‘c’ : Int ! Int. Therefore, we obtain themerge 1 ,, (_x. x ,, ‘c’ : Int ! Int) with type Int & (Int ! Int).
Basic properties of casting. Some properties can be proved directly by induction on thederivation of casting. First, when casting against a top-like type, the result only depends on
the type, as a top-like type is isomorphic to the unit type. Second, casting produces the same
result whenever it is done directly or indirectly. Assume v has type C, then the conversion
from C to B has an equivalent e�ect as the composition of the conversion from C to A and theconversion from A to B. This corresponds to the coherence property of subtyping. Third, if awell-typed value can be cast by some type, its synthesized type must be a subtype of that type.
The three properties are formally stated next:
Lemma 5.5 (Casting against top-like types). If eAd, v1 õ!A v10 , and v2 õ!A v20 then E 10 = E 20 .
Lemma 5.6 (Commutativity of casting). If v õ!A v1 , and v1 õ!B v2 , then v õ!B v2 .
Lemma 5.7 (Up-casting only). If v õ!A v 0 and · ` v ) B, then B 6 A.
Note that Lemma 5.7 relates casting and subtyping.

5.3.2

Consistency, Determinism and Type Soundness of Casting

Consistent values, as speci�ed in De�nition 5.2, introduce no ambiguity in casting. If two
consistent values both can reduce under a type, they should produce the same result. The
consistency restriction ensures that duplicated values in a merge type-check, but it still rejects
merges with di�erent values of the same type. A value of a top-like type is consistent with anyother value. It can only be cast by top-like types, which leads to a �xed result decided by thetype.
Relating disjointness and consistency. Assuming that the synthesized types of two values
are disjoint, from Lemma 5.7, we can conclude that when the two values both cast by a type,that type must be a common supertype of their principal types, which is known to be top-like.
Furthermore, Lemma 5.5 implies that their reduction results are always the same under such
top-like types, so they are consistent. The above discussion concludes that values with disjoint
types evaluate to the same result under the same type, i.e. they are consistent. This is capturedby the following lemma:
Lemma 5.8 (Consistency of disjoint values). If A ⇤ B, · ` v1 ) A, and · ` v2 ) B thenv1 ⇡B?42 v2 .

76

Determinism of casting. The merge construct makes it hard to design a deterministic
operational semantics. Disjointness and consistency restrictions prevent merges like 1 ,, 2, andbring the possibility to deal with merges based on types. Casting takes a well-typed value,
which, if it is a merge, must be consistent (according to Lemma 5.8). When the two casting
rules for merges (rule C����������� and rule C�����������) overlap, no matter which one ischosen, either value reduces to the same result due to consistency. Indeed our casting relation
always produces a unique result for any legal combination of the input value and type. This
serves as a foundation for the determinism of the operational semantics.
Lemma 5.9 (Determinism of casting). For every well-typed v (that is there is some type B
such that · ` v ) B), if v õ!A v1 and v õ!A v2 then E 1 = E 2 .
Runtime subtyping. While most casting rules produce values of the target type (in synthesismode), two rules are more relaxed. Rule C������� o�ers > for any top-like types. Rule C��������� keeps the original input annotation in the reduced lambda abstraction:(_x. x ,, 2 : Char ! Char & Int) õ! (Char & Int!Char) _x. x ,, 2 : Char ! CharWe use runtime subtype to characterize the relation between the synthesized type of the casting
result and the casting type. De�ned in Figure 5.4, runtime subtyping is a restricted form ofsubtyping. Roughly, it only allows subtyping in contravariant positions except for top-liketypes.
Runtime subtyping is introduced because we need to �nd a middle point between equality
and subtyping to describe how casting preserves the reduction type (Lemma 5.11). If A is the
reduction type and B is the type of the output value in the casting relation, we cannot simply
say that ⌫ = . But knowing only that B <: A is not enough. The initial value already has asubtype of A, so this does not even prevent directly using it as the result. In fact, for runtime
subtyping, we expect the inclusive semantics: a value of subtype can be directly treated as avalue of its supertype. Runtime subtyping ensures that the casting result behaves like a termof the casting type, and it keeps transitivity as well. Thus after multiple steps of reduction,
the ultimate result still has a runtime subtype in terms of the type of the initial expression.
Therefore the preservation property of _8 is safely relaxed, to allow the expression type tobecome more and more speci�c during reduction.
Type soundness of casting. Via the transitivity lemma (Lemma 5.6) and the determinism
lemma (Lemma 5.9), we obtain the following property: any reduction results of the given value
are consistent.
Lemma 5.10 (Consistency after casting). If v is well-typed, and v õ!A v1 , and v õ!B v2 thenv1 ⇡B?42 v2 .
77

A⌧BRS����

A⌧A(Runtime Subtyping)RS������

B1 <: A1

RS������

A2 ⌧ B2A1 ⌧ B1A2 ⌧ B2

A1 & A2 ⌧ B1 & B2

A1 ! A2 ⌧ B1 ! B2

RS������eAd>⌧A

Figure 5.4: Runtime subtyping of _8 .

The lemma shows that the reduction result of rule C������� is always made of consistent values,
which is needed in type preservation via the typing rule T���������. Then a (generalized)
type preservation lemma on casting can be proved.
Lemma 5.11 (Preservation of casting). If · ` v ( A and v õ!A v 0, then 9⌫, · ` v 0 ) B andB ⌧ A.
In general, this lemma shows that casting produces well-typed values: it shows that if a value ischecked by type A and it can be cast by A then the reduced value is always well-typed, and its
synthesized type B is a runtime subtype of A. What is more, casting is guaranteed to progressfor a given value and a type it can be checked against. That is to say, from a well-typed value,
we can derive the existence of a casting judgement and the well-typedness of the reduction
result.
Lemma 5.12 (Progress of casting). If · ` v ( A, then 9E 0, v õ!A v 0.
Fewer checks on casting. In rule C��������� (in Figure 5.3), the premise A1 <: B1 isredundant for reduction. Since we only care about well-typed terms being reduced, such acheck has already been guaranteed by typing. Therefore an actual implementation could omitthat check. The reason why we keep the premise is that casting plays another role in our
metatheory: it allows us to de�ne consistency. Consistency is de�ned for any (untyped) values,
and the extra check there tightens up the de�nition of consistency. With the premise, casting
directly implies a subtyping relation between the type of the reduced value and the reduction
type. (See Lemma 5.7: If v õ!A v 0, and · ` v ) B, then B 6 A).
One could wonder if this property is unnecessary because it may be derived by typepreservation of reduction. Note that whenever casting is called in a reduction rule, the subtyping
relation can be obtained from the typing derivation of the reduced term. For example, reducingv : A will cast v under A. If v : A is well-typed, then we could in principle prove that the type ofv is a subtype of A. Unfortunately, the above proof is hard to attain in practice. Because typepreservation depends on consistency, and consistency is de�ned by casting. Once the subtyping
property relies on type preservation, there is a cyclic dependency between the properties.

78

e õ! e0

(Reduction)

S�������

S��������

> v õ! >(_x. e : A ! B) v õ! (e[x 7! v 0]) : B

v õ!A v 0

S���������

S��������

v : A õ! v 0

e1 e2 õ! e10 e2

v õ!A v 0e1 õ! e10

S��������

S����������

S����������

S��������

v1 e2 õ! v1 e20

e1 ,, e2 õ! e10 ,, e2

v1 ,, e2 õ! v1 ,, e20

e : A õ! e0 : A

e2 õ! e20

e1 õ! e10

e2 õ! e20

e õ! e0S�������

(�x x : A. e) õ! (e[x 7! (�x x : A. e)]) : A
Figure 5.5: Call-by-value reduction of _8 .

5.3.3

Reduction

The reduction rules are presented in Figure 5.5. Recall that rule T������ is generalized using
applicative distribution. Correspondingly, the top value consumes every input it meets using rule S�������. Pierce and Ste�en employ a similar rule in a calculus with higher-ordersubtyping [PS97]. Rule S�������� and rule S��������� are the two rules relying on casting.
Rule S�������� casts the argument value before substitution. The rule S��������� interprets
the annotation that wraps a value as type casting.
We choose to allow > act like an applicative term (rule S�������) because we want a uni�edresult for casting under any top-like type, for determinism purpose. For example, since we
accept programs like v1 : (Int ! >) 1, v1 will be reduced to > at runtime, and �nally > 1 to >.
Corresponding, in typing we convert > to > ! > (rule AD����A�� to accept > 1, keeps typepreservation.
Metatheory of reduction. When designing the operational semantics of _8 , we want it
to have two properties: determinism of reduction and type soundness. That is to say, there is
only one way to reduce an expression according to the small-step relation, and the process
preserves types and never gets stuck. Similar lemmas on casting were already presented, which
are necessary for proving the following theorems, mainly in cases related to rule S���������
and rule S��������.
Theorem 5.1 (Determinism of õ!). If · ` e ( A, e õ! e1 , e õ! e2 , then 4 1 = 4 2 .
The preservation theorem states that during reduction, the program is always well-typed, andthe reduced expression can be checked against the original type.
Theorem 5.2 (Type preservation of õ!). If · ` e , A, and e õ! e0 then · ` e0 ( A.
79This theorem is a corollary of the following lemma:
Lemma 5.13 (Generalized type preservation of õ!). If · ` e , A, and e õ! e0 then 9⌫,· ` e0 , B and B ⌧ A.
The lemma has a similar structure to Lemma 5.11: the type of the reduced result is a runtime
subtype (Figure 5.4) of the target type. Note that , in this and the following lemmas is ameta-variable for typing mode. It means both checking and synthesis mode work for it, as longas the conclusion and the premise have the same mode. To prove Lemma 5.13, the substitution
lemma has to be adapted. The substituted term is allowed to have a runtime subtype of the
expected type. The type of the result, accordingly, is a subtype of the initial type. For example,
a lambda of type Int ! Int can be used when a term of Int & Char ! Int is expected. It canbe viewed as a combination of type narrowing via runtime subtyping and the conventional
substitution lemma.
Lemma 5.14 (Substitution preserves types). For any expression 4, if 1 , x : B , 2 ` e1 , A and
0 0
002 ` e2 ) B , B ⌧ B, then 1 , 2 ` e1 [x 7! e2 ] , A and A ⌧ A.
Finally, the progress theorem promises that reduction never gets stuck. Its proof relies on the
progress lemma of casting.
Theorem 5.3 (Progress of õ!). If · ` e ( A, then 4 is a value or 94 0, e õ! e0.
Summary In this work, we showed how a type-directed operational semantics allows us toaddress the ambiguity problems of calculi with a merge operator. Therefore, with the TDOS
approach, we can answer the question of how to give a direct operational semantics for both
the general merge operator in a setting with intersection. Next we will extend the system tosupport record concatenation and more advanced subtyping.

80

CHAPTER 6

T�� N����� C���������� C������� _8+
In this chapter, we will introduce the _8+ calculus, which extends _8 with distributivity rules
for subtyping and nested composition1 . Like _8 , the _8+ calculus is essentially a TDOS variantof the calculus with the same name introduced by Bi, Oliveira, and Schrijvers. In the original_8+ calculus the semantics is de�ned by elaboration [BOS18]. The subtyping relation for _8+ isbased on the subtyping relation of Barendregt, Coppo, and Dezani-Ciancaglini [BCD83], which
is presented in Chapter 3. _8+ has record types and supports record concatenation via the merge
operator. While it is quite similar to the _8 calculus, BCD subtyping empowers _8+ so that amerge of functions can act as a function, and a merge of records can act like a record. We will
see how this behavior leads to changes in the typing and reduction rules.

6.1

Overview

Although the subtyping of _8 allows multiple functions in a merge, it lacks the distributive
subtyping rule for intersection types that we have seen in Chapter 3. Distributivity in a calculus
with a merge operator is interesting because it enables nested composition, which essentiallyre�ects the distributivity seen at the type level into the term level. For instance, the distributive
property of functions over intersections enables subtyping statements such as:(A1 ! A2 ) & (B1 ! B2 ) 6 A1 & B1 ! A2 & B2
Therefore, a merge of two functions can be treated as a single function where the inputs andoutputs of the two original functions have intersection types.
1The application of nested composition was discussed in Section 2.5.2.

81

Revisiting the examples with merges and subtyping. Recall the �rst example presented
in Section 2.3, rewritten here to use a lambda abstraction instead of a let expression:(_x. (2 ,, x) + 3 : Bool ! Int) (true ,, 1)As argued in Section 2.3, in the inclusive semantics of subtyping, examples like the above areproblematic since they can lead to non-disjoint merges appearing at runtime. In _8 , with the
TDOS approach, the full reduction steps for this example are:

õ!
õ!
õ!

(_x. (2 ,, x) + 3 : Bool ! Int) (true ,, 1)((2 ,, true) + 3) : Int
5 : Int
5

by rule S��������
reduction for +by rule S���������

Firstly, the input value is �ltered by casting against the input type Bool. Importantly, only theselected part true is substituted in the body of the lambda during beta-reduction. Then, theexpression (2 ,, true) + 3 evaluates to 5. In the process, + acts like a lambda with annotation
Int ! Int ! Int. Finally, the return type Int �lters the result, which does not change it in thiscase.
The second example in Section 2.3 with records is slightly more involved. Especially because
multi-�eld records are encoded as merges, and such a merge can be directly projected. We willshow the reduction of that example by the end of this section.
Splittable arrow types. Without distributivity, if an arrow type is a supertype of an intersection of multiple types, then it must be a supertype of one of those types. Conversely, whencast a merge by an arrow type, we will obtain a single function (one of the components of themerge) as a result. However, in _8+ , we are now faced with the following kind of casting due tothe change in subtyping:(_x. x : Int ! Int) ,, (_x. true : Int ! Bool) ,, (_x. ‘c’ : Int ! Char)

õ!Int ! Int & Char (_x. x : Int ! Int) ,, (_x. ‘c’ : Int ! Char)

Even though we are doing casting under an arrow type, we do not obtain a function as a result.
Instead what we have is a merge of two functions. This is because, with the distributivity ofarrow types, multiple components present in a merge can contribute to the �nal result. For
instance, in the reduction above both the �rst and the last lambdas must be present to ensurethat the resulting value “behaves” as a function of type Int ! Int & Char.
Parallel application. One consequence of allowing merges to be a normal form of arrow
types is that a beta reduction for applications is not enough, since merges of functions can also82

be applied to values. We use a relation called the parallel application to deal with applications ofmerges to another value. Parallel application distributes the input to every lambda in a merge,
and beta reduces them in parallel. From the point of view of the small-step semantics, theparallel application process, like casting, is �nished in a single step, like the following example.
(_x. x + 1 : Int ! Int ,, (_x. true : Int ! Bool ,, _x. ‘c’ : Int ! Char)) 2

õ! (2 + 1) : Int ,, (true : Bool ,, ‘c’ : Char)

Generalized consistency. In _8+ , a merge of function values, once applied to an argument,
can step to a merge of expressions. In the previous example, for instance, one of the components
in the resulting merge is (2 + 1) : Int, which is an expression but not a value. This raises achallenge to the consistency de�nition employed in _8 , which can only relate values (but notarbitrary expressions). Therefore we have to extend the de�nition of consistency in _8+ toinclude such expressions. Intuitively, two expressions can be safely merged if their reduction
result is the same, like (2 + 1) : Int or 3 ,, (2 + 1). However, there are some di�culties regarding
how to reason about expressions like the latter one. Consider two non-terminating programs,comparing them may never end. Instead we model consistency with a syntactic de�nition,
which is less powerful in the sense that it does not allow 3 ,, (2 + 1). But such a de�nitionis enough to accept the terms generated by parallel application, which keeps the syntactic
equivalence among the components of merges.
Records. Together with BCD subtyping, single-�eld records and record types are added into
_8+ . There is a distributivity rule in subtyping for records as well: {l : A} & {l : B} 6 {l : A & B}. A
merge of several records can be used as a single record, as long as the records have the same�eld name. This is similar to function application where functions in one merge share one
input. In reduction, we treat record projection like function application. That is to say, theparallel application relation not only applies functions in a merge in parallel but also projects
records in a merge at the same time.
({l = true} ,, {l = 2}).l õ! true ,, 2
Despite the similarity of projection and application, usually not every part in a multi-�eldrecord has the same label. Thus when projecting a merge we extract the �elds from all matchedcomponents and ignore the rest.
Here we show the full reduction steps for the example with records. In this example,
a function that expects a record of Bool takes a merge of two records. Only the one withthe expected label and �eld is selected via casting. In parallel application, the projection is
distributed into the merge, but only the valid results will be kept.

83

õ!
õ!
õ!
õ!

6.2

(_x. (({m = 2} ,, x)).m + 3 : {l : Bool} ! Int) ({m = 1} ,, {l = true}){ by rule S������������ and casting}((({m = 2} ,, {l = true})).m + 3) : Int{ by rule S������������� and parallel application }(2 + 3) : Int{ reduction for + }5 : Int{ by rule S������������� }5

Syntax and Typing

The syntax of _8+ is:
Types
Expressions

,⌫
4

::=
::=

ValuesContexts
Typing modes

E

::=
::=
::=

,

Int | > | A ! B | A & B | {l : A}
G | 8 | > | 4 : | 4 1 4 2 | _G .4 : ! ⌫ | e1 ,, e2 | �x x : A. e
| {l = e} | 4.;
8 | > | _G .4 : ! ⌫ | v1 ,, v2 | {l = v}
· | , x :A)|(

Records and record types. {l = e} stands for a single-�eld record whose label is l and its
�eld is e. Projection e.l selects the �eld(s) from e with label l. In a record type {l : A}, A is thetype of the �eld. A merge of single-�eld records can be thought of as a multi-�eld record, andtherefore can be used, for example, to model objects. Multi-�eld record types are desugared tointersections of single-�eld ones, and multi-�eld records are also desugared to merges:{; 1 :

1 ; . . . ; ;= := } , {; 1 :1 } & · · · & {;= :=}{; 1 = 4 1 ; . . . ; ;= = 4= } , {; 1 = 4 1 } ,, . . . ,, {;= = 4= }Splittable types and subtyping. Figure 6.1 shows the subtyping-related de�nitions. It isbased on the algorithmic formulation of subtyping present in Chapter 3, and uses the splittabletypes to characterize the distributivity of function types and record types over intersection.
For a splittable type, its syntactical structure guarantees that it has an equivalent intersection
type according to the subtyping. So it can be decomposed into two parts, while ordinary
types cannot. Compared with the de�nitions present in Figure 3.2, for each relation, a rule forrecord types is added in a modular way. The record rule is often similar to the arrow type rule,especially if we interpret the type {l : A} as {; } ! A, a function type that takes a �rst-classlabel.

84

, ⌫ , ⇠ ::= Int | > | A ! ⌫ | {l : ⌫ }$A38=0A~ C~?4
(Top-Like Types)

eAd

B

TL����eAd
eBd

TL����

TL������
eBd
eA ! Bd(Splittable Types)
S�������
C1

S�����

eA & Bd

e>d

A⇤C

A

A&B ⇤ B

S�����
C1

TL����
eBd{l : C1 }e{l : B}d

A <: B

A ! B ⇤ A ! C2

B ⇤ C2{l : B} ⇤ {l : C2 }(Modular BCD Subtyping)S����������
Int <: Int

A ! C1B ⇤ C2S����������
eBd
A <: B

S����������
C1 B ⇤ C2

A <: C1
A <: BA <: C2S�����������
A <: CA & B <: CS�����������
B <: CS������������
B1 <: A1A2 <: B2

S����������
A <: B

A & B <: C

A1 ! A2 <: B1 ! B2

{l : A} <: {l : B}

Figure 6.1: Subtyping rules.

Disjointness. The disjointness de�nition is presented on Figure 6.2. It might be a bit surprising that, except for the new record-related rules, the remaining rules are the same as_8 ’s disjointness de�nition. The two systems both respect the speci�cation of disjointness(De�nition 5.1), from which we know that if type A is not disjoint with type B, then it is not
disjoint to any subtypes of B. Since types in _8+ can have more supertypes, its disjointnessde�nition is expected to be stricter than _8 . However, in _8 , for arrow types, disjointness only
cares about output types. In other words, the set of all output types in an intersection of arrow
types decides the set of its disjoint types. For (A ! B) & (A ! C), if a type is disjoint to it,
the type cannot contain B or C in the return type of any its components. The same criterion
applies to types disjoint from (A ! B & C). Therefore, for (A ! B) & (A ! C), the additional
supertype A ! B & C introduced by the distributivity rule in BCD subtyping, brings no extra
non-disjoint type to it. Thus the disjointness de�nition does not change. What is more, theextended de�nition also has the following properties:
Lemma 6.1 (Disjointness properties). Disjointness satis�es:
1. A ⇤ B if and only if A ⇤0 B.
2. if A ⇤ (B1 ! C) then A ⇤ (B2 ! C).
85

A ⇤0 B

(Algorithmic Disjointness)D����LD����R> ⇤0 A

A ⇤0 >

D����I��
A1 ! A2 ⇤0 Int

D����LA1 ⇤0 BA2 ⇤0 B

A1 & A2 ⇤0 B

D����A��A2 ⇤0 B2

A1 ! A2 ⇤0 B1 ! B2

D����R��

D����A��

A1 ! A2 ⇤0 {l : A}{l : A} ⇤0 A1 ! A2

D����R
A ⇤0 B1

A ⇤0 B2

A ⇤0 B1 & B2

D�I��A��Int ⇤0 A1 ! A2

D����R��

D����I��

Int ⇤0 {l : A}{l : A} ⇤0 Int

D����E�A ⇤0 B{l : A} ⇤0 {l : B}

D����N��l1 < l2{l1 : A} ⇤0 {l2 : B}

Figure 6.2: De�nition of disjointness in _8+ (extends _8 ’s de�nition in Figure 5.1).

3. if A ⇤ B & C then A ⇤ B and A ⇤ C.
Pre-values and consistency. As shown in Section 6.1, merges like e : A ,, e : A, could be
produced during reduction, since merged functions both take the input. To type check suchmerges, we use pre-values to denote a sort of terms including values, annotated terms, andmerges composed by them, and generalize consistency to pre-values. A pre-value’s type, if it is
not a merge or record, can be told directly from its form without analyzing its structure. The
principal type of a term is the most speci�c one among all of its types, i.e. it is the subtype ofevery other type of the term. The top of Figure 6.3 shows the syntax-directed de�nition ofprincipal types for pre-values. Its correctness is justi�ed as follows.
Lemma 6.2 (Principal types). For any pre-value u,
1. if u : A and · ` u ) B, then= ⌫.

2. if · ` u ) A then u : A.
Recall that the intuition of consistency is to allow two terms in a merge if they have disjoint types
or their overlapped parts are equal. In _8 , only values can be consistent, and the speci�cation of
consistency relies on casting, which is hard to extend to expressions. To extend consistency to
pre-values, we now use an inductive relation to de�ne consistency, where principal types areused to simplify the de�nition. Consistency is showed on the bottom of Figure 6.3. Notably, forvalues, the de�nition is sound and complete with respect to the speci�cation (De�nition 5.2).
Lemma 6.3 (Soundness and completeness of consistency de�nition). For all well-typed value
v1 and v2 , v1 ⇡ v2 if and only if v1 ⇡B?42 v2 .

86

u ::= v | e : A | u1 ,, u2 | {l = u}Pre-values

u:A(Principal Type of Pre-Values)PT����

PT����

PT����

PT�����

>:>i : Int(_x. e : A ! B) : (A ! B)

(e : A) : A

PT������
u1 : Au2 : B

PT����
u:A(u1 ,, u2 ) : (A & B)

{l = u} : {l : A}

u1 ⇡ u2(Consistency)

C����

C����

C�����

i⇡i_x. e : A ! B1 ⇡ _x. e : A ! B2

e:A ⇡ e:B

C���������
u1 : Au2 : Bu1 ⇡ u2

A ⇤0 B

C�������
u1 ⇡ uu2 ⇡ uu1 ,, u2 ⇡ uC����
u1 ⇡ u2{l = u1 } ⇡ {l = u2 }C�������u ⇡ u1u ⇡ u2u ⇡ u1 ,, u2

Figure 6.3: De�nition of principal types and consistency in _8+ .

Typing and applicative distribution. Figure 6.4 presents the extension of typing andapplicative distribution. The typing rules of application and projection rely on applicative
distribution. It extends the initial de�nitions of _8 in two dimensions. One is about the
distributive rule of function type constructors over intersections, where rule AD��������A��
now supports intersection of function-like types. Assuming that a term e1 of type (Int !
Int) & (Bool ! Bool) is applied to term e2 , via this relation, we can derive that e2 should bechecked against type Int & Bool. The other dimension is to treat record types as one of theapplicative forms. The additional relation l ` A ⇤ B computes the projection result of type A onlabel l. Rule ADR���� combines both dimensions and enables the intersection of record-liketypes. For function application, it is required that the argument type matches with every
function’s parameter type. Di�erently, we employ a more �exible semantics on projection:
records with incompatible labels can appear in the merge. But they produce empty results likethe top type. An auxiliary function meet is used to drop the > type from the results so thatthe type of {l1 = 1 , l2 = 2 , l3 = 3}.l1 is computed as Int rather than Int & > & >. Although >can behave like > ! > or {l : >} when a function or record type is required, we do not extend
this implicit conversion to other types. This is to avoid programs like projecting a function(_x. x : Int ! Int).l or applying an integer to an argument (1 true). Since projecting a top

87

A⇤B

(Applicative Distribution)

AD��������

AD��������A��

A!B⇤A!B>⇤>!>l ` A ⇤ B (Applicative Distribution on Record Projection)

AD��������A��A ⇤ A1 ! A2
B ⇤ B1 ! B2

ADR����R��

ADR����l `>⇤>l ` {l : A} ⇤ A

ADR����N��
l1 < l2

l1 ` {l2 : A} ⇤ >A & B ⇤ A1 & B1 ! A2 & B2meet(A, B)=

A

meet(A, >)=A`e , Al ` B ⇤ B0l ` A & B ⇤ meet(A0, B0 )(De�nition of the meet function on types)

meet(>, A)meet(A, B)

ADR����l ` A ⇤ A0

= A & B when neither A and B is >(Bidirectional Typing)T����������

T����������`> ) >` i ) Int

T����������
` e1 ) AA⇤B!C` e1 e2 ) C

T����������
x:A2

T�����������`e ) A` e2 ( BT������������
` e1 ) A

T����������
, x :A ` e ( AT�������������· ` u1 ) A· ` u2 ) B` �x x : A. e ) A` _x. e : A ! B ) A ! B`x ) A

T����������`e ) A` {l = e} ) {l : A}

T����������
, x :A ` e ( B` e.l ) C

` e2 ) B` e1 ,, e2 ) A & B` u1 ,, u2 ) A & B

l `A⇤C

A ⇤0 Bu 1 ⇡ u2T�����������`e ( A` e:A ) A

T����������`e ) A

A <: B`e ( B

Figure 6.4: Typing and applicative distributivity of _8+ (extends Figure 5.2).

value (>.l) is accepted, we also allow {l1 = e}.l2 when l1 di�ers from l2 . When there is no label
matched, the projection always has type >.
Besides the changes due to records, rule T������������� is generalized from values topre-values. Thus, merges like e : A ,, e : A are well-typed in _8+ .

6.3

Operational Semantics

Casting. Compared with _8 , the new casting reduction has one more rule for records, and two
rules that change, as shown in Figure 6.5. We now need to make sure that rule C�������������
only applies to ordinary arrow types, as we will generate merges for splittable arrow types. The88

v õ!A v 0(Casting in _8+ )i õ!Int iv õ!

C�����������
¬e d
v õ!
{l = v} õ! {l:C�������������
¬e⌫ 2 dB1 <: A1

C�����������
e dC������������

}v0{l = v 0 }A2 <: ⌫ 2

_x. e : A1 ! A2 õ! (B1 !⌫2 ) _x. e : A1 ! ⌫ 2>C���������������
v1 õ! v10
v1 ,, v2 õ!

C�����������B A⇤Cv õ!B v1

v10

C���������������
v2 õ! v20
v1 ,, v2 õ!

v20

v õ!C v2

v õ!A v1 ,, v2

Figure 6.5: Casting of _8+ (extends Figure 5.3).

condition is unnecessary in _8 because every arrow type there is ordinary. Rule C�����������
mimics the arrow rule. Rule C����������� works on splittable types, so now it needs to takecare of more types than just intersections. Although we choose to merge the two results ofthe split types, there are some other alternative options. One possible design is to construct a
lambda from the results. Therefore, we could prevent merges from being the inhabitants ofarrow types. However, it is hard to maintain the commutativity of casting (Lemma 5.6) while
manipulating the lambda body. In our reduction semantics, a merge of functions behaves thesame as one function. So it is safe to not convert such merges to one lambda abstraction. We
will review this issue in our later discussion about runtime subtyping and type soundness.
Reduction. In the reduction rules of _8+ , presented in Figure 6.6, rule S������������ replaces
the original beta-reduction rule and rule S�������. Rule S�����������, rule S������������,and rule S������������� are added for records and record projection. The rules for merges arechanged to reduce components in parallel.
Parallel application. To align record projection with the function application, we de�nearguments which abstract expressions, and record labels (at the top of Figure 6.6). The distributivity rule in BCD subtyping indicates that a merge of functions can be applied. Instead of
converting the merge to a lambda abstraction, we chose to perform the application directly. An
intuitive solution is to have a rule that distributes the input value, like
(v1 ,, v2 ) v õ! v1 v ,, v2 v

89

Arguments

arg ::= v | {l}meet(v1, v2 )(De�nition of the meet function on values)meet(>, v)=v

meet(v, >)=v= v1 ,, v2 when neither v1 and v2 is >meet(v1, v2 )v • 0A6 õ! e

(Parallel Application)P�������

P�������

P���������A��
v1 • v õ! e1
v2 • v õ! e2

v õ!A v 0_x. e : A ! B • v õ! (e[x 7! v 0 ]) : B> • 0A6 õ! >v1 ,, v2 • v õ! e1 ,, e2P��������

P�������N��
l1 < l2P�������P���{l = v} • {l} õ! v

{l1 = v} • {l2 } õ! >_x. e : A ! B • {l} õ! >P���������P���
v1 • {l} õ! e1

v2 • {l} õ! e2

v1 ,, v2 • {l} õ! meet(e1, e2 )e õ! e0(Small-Step Semantics)

S������������
v1 • v2 õ! e
v1 v2 õ! e

S�������������
v • {l} õ! v 0
v.l õ! v 0S�������������
v õ!A v 0

S������������
e1 õ! e10

S������������
e2 õ! e20v : A õ! v 0

e1 e2 õ! e10 e2

v1 e2 õ! v1 e20

S�������������
e1 õ! e10
e2 õ! e20

S��������������
e1 õ! e10

S��������������
e2 õ! e20

S������������
e õ! e0e1 ,, e2 õ! e10 ,, e20

e1 ,, v2 õ! e10 ,, v2

v1 ,, e2 õ! v1 ,, e20

e : A õ! e0 : A

S�����������

S�����������
e õ! e0S������������
e õ! e0�x x : A. e õ! e[x 7! �x x : A. e] : A{l = e} õ! {l = e0 }e.l õ! e0 .l

Figure 6.6: Parallel application and reduction of _8+ (extends Figure 5.5).

90

Assuming that v1 and v2 are consistent but not disjoint, to obtain preservation, v1 v andv2 v have to be consistent. To avoid the complexity of extending consistency to expressions
including applications, we design parallel application (Figure 6.6) to distribute and substitutethe input value in a big-step style, where a function application is divided into two parts v and
0A6, and steps to an expression e.
Consider a merge of three functions being applied to a value. Compared to adding theprevious single rule to the small-step reduction, parallel reduction helps us to “jump” from
(f1 ,, f2 ,, f3 ) v to a merge of annotated terms when reasoning about reduction. Every lambda
gets the input directly without Intermediate reduction steps such as ((f1 ,, f2 ) v) ,, f3 v. Record
projection is handled in a similar style. In this case, v is a record value, and 0A6 stands for alabel instead.
{l = 1 , l = true , l = 1 , l = > , m = 2} • {l} õ! 1 ,, true ,, 1
The above example shows how merged records are projected in parallel, and the whole term
is kept consistent. We use the meet function to drop the top values as they may be produced
by records with unmatched labels. Meanwhile, records that only contains a top value are also
ignored.
Rule P������� shows that the top value can be used as a function that returns >, or arecord which contains > in its �eld. With it, rule S������������ subsumes the rule S�������
in Figure 5.5.
Parallel reduction of merges. To maintain consistency of subterms in a merge (which
may contain non-values), as required by the typing rule T�������������, we reduce every
component in a merge simultaneously through rule S�������������. This rule is helpful topreserve consistency of pre-values during reduction, and therefore enables the type preservation
theorem. As a counter-example, if parallel reduction is not employed, we might encounter thefollowing reduction step:(1 + 1) : Int ,, (1 + 1) : Int õ! 2 : Int ,, (1 + 1) : Int
where the reduced term is ill-typed, since the subterms are not consistent any more. In contrast,
rule S������������� will keep the reduction of terms synchronized. When one of the subterms
is already a value, rule S������������� no longer applies. In that case, rule S��������������
or rule S�������������� reduces the other subterm.
Note that for systems that have no side e�ects, like _8+ , the evaluation order of merges does
not change the �nal result. This is to say, even if the reduction of merges is not conducted inparallel, a well-typed program will eventually step to a value that preserves its type. Potentially,
with an extended de�nition of consistency, we can prove type soundness for the conventional91

reduction on merges. The extended consistency should relate Kleene-equivalent terms, whichhave the same value form, like 2 and 1 + 1.
Overloading on return types. The _8+ calculus support a form of overloading on return
types. We can even merge multiple functions and apply them together to one input. Eventually,
the return value would be a combination of the outputs of all functions, and can play the roleof any single output. The following example shows how this mechanism works.

õ!
õ!
õ!
õ!

not ((_x. x + 1 : Int ! Int ,, _x. true : Int ! Bool) 1){ by S������������ and parallel application }not (2 : Int ,, true : Bool){ by S������������, S�������������, S������������� and casting }not (2 ,, true){ assuming not has type Bool ! Bool }
false : Bool{ by S������������� and casting }
false

6.4

Metatheory

6.4.1

Completeness of the type system with respect to the original_8+ '18 (or NeColus) calculus.

Besides the extra rule for consistent merges (rule T�������������), _8+ has two di�erent rules
for record projection and function application when compared with the type system of _8+ '18(NeColus) [BOS18].
`= 4 , A(_8+ '18 Typing (Selected))
N���T�����

N���T����

`= 4 1 ) A1 ! A2`= 4 2 ( A1`= 4 1 4 2 ) A2`= 4 ) {l : A}`= 4.l ) A

To show that every well-typed term in _8+ '18 can be type-checked in _8+ , we prove the following
lemmas:Lemma 6.4 (_8+ application subsumes _8+ '18’s application). For any expressions e1 and e2 , if
` e1 ) A ! B and ` e2 ( A, then ` e1 e2 ) B.
Lemma 6.5 (_8+ projection subsumes _8+ '18’s projection). For any expressions e and any label l,if ` e ) {l : A}, then ` e.l ) C.
92

(Runtime Subtyping for _8+ )A⌧BRS��������

RS������������
B1 B ⇤ B2
A1 ⌧ B1

A1 & A2 ⌧ B

A⌧ARS�����������
B1 B ⇤ B2
eB1 d
A⌧B

A ⌧ B2A2 ⌧ B2

RS����������eAd>⌧ARS����������
B1 <: A1A2 ⌧ B2
A1 ! A2 ⌧ B1 ! B2

RS�����������
B1 B ⇤ B2
eB2 d
A⌧B

A ⌧ B1Figure 6.7: Runtime subtyping of _8+ , extending the de�nition in Figure 5.4.

Then it is straightforward that _8+ '18 can be translated into _8+ . In our Coq formalization wedesigned an elaboration from _8+ '18 to _8+ and proved the completeness of _8+ ’s type system withrespect to _8+ '18.

6.4.2

Properties of the TDOS.

The TDOS of _8+ preserves determinism, progress, and subject-reduction. Most of the proof
follows _8 ’s structure. Runtime subtyping is extended, and the newly added parallel application
requires some extra lemmas.
Runtime subtyping and preservation. We have seen that any term of a subtype can becast to its supertype given explicit type annotations. But for a subset of the subtyping relation,
we directly use values of the subtype as values of its supertype. This relation is runtime
subtyping. Compared with the de�nition in _8 , _8+ ’s runtime subtyping has one rule changedfor distributivity, and three rules added for records. As a consequence of the generalizationof rule RS������ to rule RS������������, an intersection type can be a runtime subtype ofan arrow type, or other splittable types. It corresponds the use of merges as a function or arecord. Rules RS����������� and RS����������� are due to the elimination of the top value
in projection. Since a top value may stand for a top-like type, these two rules allow dropping
any top-like types in an intersection.
A key property of runtime subtyping is that it preserves the disjointness relation. We haveknow that if A is a subtype of B then any type disjoint with A is also disjoint with B. But thereverse direction only holds for runtime subtypes.
Lemma 6.6 (Runtime subtyping preserves disjointness). If A1 . A2 , then A1 ⇤ B if and only if
A2 ⇤ B.
Parallel application. For both function application and record projection, parallel reduction
preserves the original type.
93

Lemma 6.7 (Type preservation of parallel application).
• If · ` v1 v2 ) A, and v1 • v2 õ! e then · ` e ) A.
• If · ` v1 .l ) A, and v1 • {l} õ! e then · ` e ) A.

Furthermore we can prove the following determinism lemmas:
Lemma 6.8 (Determinism of parallel application).
• If · ` v1 v2 ) A, v1 • v2 õ! e1 , v1 • v2 õ! e2 then 4 1 = 4 2 .
• If · ` v1 .l ) A, v1 • {l} õ! e1 , v1 • {l} õ! e2 then 4 1 = 4 2 .

We can also prove the following progress lemmas for parallel application:
Lemma 6.9 (Progress of parallel application).
• If · ` v1 v2 ) A, then 94, v1 • v2 õ! e.
• If · ` v1 .l ) A, then 94, v1 • {l} õ! e.
Type Soundness. Finally, based on all the lemmas above, the key properties of reduction
can be derived, including type preservation with runtime subtyping:
Lemma 6.10 (Type preservation of õ! with respect to runtime subtyping). If · ` e ) A, ande õ! e0 then exists B, · ` e0 ) B and B . A.

And its corollary:

Theorem 6.1 (Type preservation of õ!). If · ` e ) A, and e õ! e0 then · ` e0 ( A.
Determinism and progress theorems are proved as well.

Theorem 6.2 (Determinism of õ!). If · ` e ) A, e õ! e1 , e õ! e2 , then 4 1 = 4 2 .
Theorem 6.3 (Progress of õ!). If · ` e ) A, then 4 is a value or 94 0, e õ! e0.

Summary From _8 to _8+ , we continue with the type-directed reduction in the call-by-value
style. Subtyping is mainly interpreted as implicit conversions on values, and de�ned by thecasting relation. Runtime subtyping is a subset of subtyping that has inclusive semantics. Bothrelations are extended for the addition of distributive rules, mainly to treat merges not only as
values of intersections, but also as values of splittable types.
_8+ supports both BCD subtyping and record concatenation. Compared with the elaboration
approach, having a direct semantics avoids the translation process and a target calculus. This
simpli�es both informal and formal reasoning. For instance, establishing the coherence ofelaboration in the original _8+ [BOS18] requires much more sophistication than obtaining thedeterminism theorem in _8+ . Furthermore, the proof method for coherence in _8+ '18 cannot deal
with non-terminating programs, whereas dealing with recursion is straightforward in _8 and
_8+ .
94

CHAPTER 7

T�� F8+ C������� ���� D�������
P����������
As we have seen in Section 2.5.2, the Compositional Programming language CP supports
multiple inheritance and solves the Expression Problem in a modular way. CP is implemented
on top of a polymorphic core language with disjoint intersection types called F8+ .
This chapter presents a new formulation of F8+ based on the type-directed operationalsemantics (TDOS) that has been employed in the previous two chapters. We extend the TDOS
approach can to languages with disjoint polymorphism and model the full F8+ calculus.
Our new formulation of F8+ di�ers from the original one in three aspects. Firstly, thesemantics of the original F8+ [Bi+19]is given by elaborating to F2> , while our semantics for F8+ is
a direct operational semantics. Secondly, our new formulation of F8+ supports recursion andimpredicative polymorphism. Finally, we employ a call-by-name evaluation strategy, motivatedby the need for lazy �xpoints to model the semantics of trait instantiation in Compositional
Programming.

7.1

Motivations and Technical Innovations

In this section, we show how CP traits elaborate to F8+ expressions and discuss the practicalissues that motivate us to reformulate F8+ as well as technical challenges and innovations.

7.1.1

Elaborating CP to F8+

The semantics of CP and its notion of traits is de�ned via an elaboration to the core calculus F8+ .
The elaboration of traits is inspired by Cook’s denotational semantics of inheritance [Coo89]. In
the denotational semantics of inheritance, the key idea is that mechanisms such as classes ortraits, which support self-references (aka the this keyword in conventional OOP languages), can95be modeled via open recursion. In other words, the encoding of classes or traits is parametrized
by a self-reference. This allows late binding of self-references at the point of instantiation andenables the modi�cation and composition of traits before instantiation. Instantiation happens
when new is used, just as in conventional OOP languages. When new is used, it essentially closes
the recursion by binding the self-reference, which then becomes a recursive reference to theinstantiated object. In the denotational semantics of inheritance, new is just a �xpoint operator.
Here we focus on the elaboration of traits, and take a closer look at the connection between CP
and F8+ expressions. We refer curious readers to the work by Zhang et al. [ZSO21] for the fullformulation of the type-directed elaboration of CP.
Elaborating traits into F8+ To use a concrete example, we revisit the trait repo de�ned in
Section 2.5.2. Both the creation and instantiation of traits are included in the de�nition of repo:
repo Exp = trait [self : ExpSig<Exp>] ) {num = Add (Lit 4) (Lit 8);var = ...
};The CP code above is elaborated to the corresponding F8+ code of the form:
repo = ⇤Exp. \_(self : ExpSig<Exp>).
let $Lit = self.Lit in let $Add = self.Add in
let $Let = self.Let in let $Var = self.Var in{ num = fix self:Exp. $Add (fix self:Exp. $Lit 4 self)(fix self:Exp. $Lit 8 self) self } ,,{ var = ... };The type parameter Exp in the repo trait is expressed by a System-F-style type lambda (⇤- . 4).
Note that CP employs a form of syntactic sugar for constructors to allow concise use of
constructors and avoid explicit uses of new. The source code Add (Lit 4) (Lit 8) is �rst
expanded into new $Add (new $Lit 4) (new $Lit 8), which inserts new operators. Next we
describe the elaboration process of creating and instantiating traits:• Creation of traits: A trait is elaborated to a generator function whose parameter is aself-reference (like self above) and whose body is a record of methods;• Instantiation of traits: The new construct is used to instantiate a trait. Uses of new areelaborated to a �xpoint which applies the elaborated trait function to a self-reference. In
the de�nition of the �eld num there are three elaborations of new. For instance, the CP
code new $Lit 4 corresponds to the F8+ code fix self:Exp. $Lit 4 self.
It is clear now that our trait encoding is heavily dependent on recursion, due to the selfreferences employed by the encoding. However, the original F8+ does not support recursion,
which reveals a gap between theory and practice.
96

7.1.2The Gap Between Theory and Practice

Our primary motivation to reformulate F8+ is to bridge the gap between theory and practice.
The original formulation of F8+ lacks recursion and impredicative polymorphism, and uses the
traditional call-by-value (CBV) evaluation strategy. However, the recent work of CP assumes adi�erent variant of F8+ that is equipped with �xpoints and the call-by-name (CBN) evaluation.
It is worthwhile to probe into the causes of such di�erences.
Non-triviality of coherence Recursion is essential for general-purpose computation inprogramming. More importantly, our encoding of traits requires recursion. For example, new e
is elaborated to fix self. e self. Unfortunately, in the original F8+ the proof technique forcoherence is based on a logical relation called canonicity [BOS18], and it does not immediately
scale to recursive programs and programs with impredicative polymorphism. A possible
solution, known from the research of logical relations, is to move to a more sophisticated stepindexed form of logical relations [Ahm06]. However, this requires a major reformulation of theproofs and metatheory of the original F8+ , and it is not clear whether additional challenges would
be present in such an extension. Thus, the lack of the two features in the theory of the original
F8+ remains a serious limitation since only terminating programs and predicative polymorphism
are considered. In other words, we cannot encode traits as presented in Section 7.1.1 in theoriginal F8+ . To get around this issue and enable the encoding of traits, Zhang et al. [ZSO21]
simply assumed an extension of F8+ with recursion and their proof of coherence for CP wasdone under the assumption that the original F8+ with recursion was coherent or deterministic.
Evaluation strategies The semantics of the F2> calculus is call-by-value (CBV) and, byinheritance, the elaboration semantics of the original F8+ has a CBV semantics as well, like mostmainstream programming languages. But in CP, the �xpoint operators must be lazy; otherwise,
self-references can easily trigger non-termination. CBN is a more natural evaluation strategy
for object encodings such as Cook’s denotational semantics of inheritance. As stated by Bruce
et al. in their work on object encodings [BCP97]:“Although we shall perform conversion steps in whatever order is convenient for thesake of examples, we could just as well impose a call-by-name reduction strategy.
(Most of the examples would diverge under a call-by-value strategy. This can be
repaired at the cost of some extra lambda abstractions and applications to delay
evaluation at appropriate points.)”
In our elaboration of traits, we adopt a similar approach to object encodings. For example,
consider the following CP expression:
type A = { l1 : Int; l2 : Int };new (trait [self : A] ) { l1 = 1; l2 = self.l1 })97

which is elaborated to the following (slightly simpli�ed) F8+ expression:�x self : A. {l1 = 1} ,, {l2 = self .l1 }The trait expression is elaborated to a function, and the new expression turns the function
into a �xpoint. Unfortunately, this expression terminates under CBN but diverges under CBV.
If evaluated under CBV, the variable self will be evaluated repeatedly, despite the fact that only
self .l1 is used:�x self : A. {l1 = 1} ,, {l2 = self .l1 }
õ!
õ!
õ!

{l1 = 1} ,, {l2 = (�x self : A. {l1 = 1} ,, {l2 = self .l1 }).l1 }{l1 = 1} ,, {l2 = ({l1 = 1} ,, {l2 = (�x self : A. {l1 = 1} ,, {l2 = self .l1 }).l1 }).l1 }···We may tackle the problem of non-termination by wrapping self-references in thunks, but CBNprovides a simpler and more natural way. In our CBN formulation of F8+ , {l = e} is already avalue (instead of {l = v}), so we do not need to further evaluate e:
�x self : A. {l1 = 1} ,, {l2 = self .l1 }{l1 = 1} ,, {l2 = (�x self : A. {l1 = 1} ,, {l2 = self .l1 }).l1 }õ!

The l2 �eld is further evaluated only when a record projection is performed:(�x self : A. {l1 = 1} ,, {l2 = self .l1 }).l2
õ!
õ!
õ!

({l1 = 1} ,, {l2 = (�x self : A. {l1 = 1} ,, {l2 = self .l1 }).l1 }).l2(�x self : A. {l1 = 1} ,, {l2 = self .l1 }).l1({l1 = 1} ,, {l2 = (�x self : A. {l1 = 1} ,, {l2 = self .l1 }).l1 }).l1

õ! 1This example illustrates how our new CBN formulation of F8+ avoids non-termination of trait
instantiation.
Our Proof Flow Our work shows that the TDOS approach can be extended to languages withdisjoint polymorphism and model the complete F8+ calculus with recursion and impredicative
polymorphism. Moreover, With a TDOS, there is no need for a coherence proof. Instead, we canprove that the semantics is deterministic. The proof of determinism uses only simple reasoning
techniques, such as straightforward induction, and is able to handle problematic features
such as recursion and impredicative polymorphism. Thus, this removes the gap between

98

Figure 7.1: Contrasting the �ow of results for CP using the original formulation, and our work.

theory and practice and validates the original proofs of correctness for the CP language.
Figure 7.1 contrasts the di�erences in terms of proofs and implementation of CP using Zhang
et al.’s original work and our own work. We formalized the TDOS variant of the F8+ calculus,
together with its type-soundness and determinism proof in the Coq proof assistant. Moreover,
we have a new implementation of CP based on our new reformulation of F8+ , available athttps://plground.org.

7.1.3

Technical Challenges and Innovations

While our reformulation of F8+ mostly follows the framework of _8+ , there are two main changes
that bring some technical challenges: the addition of disjoint polymorphism to subtyping, andthe use of call-by-name instead of call-by-value strategy in evaluation.
TDOS and function annotations In casting, values in a merge are selected based on type
information. In the absence of runtime type-checking, we need to know the type of input value
syntactically to match it with the target type. Thus, functions must be accompanied by type
annotations. In the previous system _8+ Chapter 6, functions have the form of _x. e : A ! C.
While the original argument type A is always kept during reduction, _8+ ’s casting relation may
generate a value that has a proper subtype of the requested type: _x. e : A ! C õ!B1 !B2 _x. e :A ! B2 . In F8+ we make casting more precise with a more liberal syntax in F8+ . We allow bareabstractions _x : A. e while _8+ does not. Our casting relation requires lambdas to be annotated(_x : A. e) : B, but the full annotation B does not have to be a function type. For example,(_x : Int. x ,, true) : (Int ! Int) & (Int ! Bool) still acts as a function, and is equivalent to(_x : Int. x ,, true) : Int ! Int & Bool. In beta reduction, instead of casting the argument, wewrap it by annotation for lazy evaluation.

99

Algorithmic subtyping with disjoint polymorphism F8+ extends the BCD-style distributive subtyping [BCD83] to disjoint polymorphism. A disjointness constraint can also be added
to a type variable in a System F-style polymorphic type, such as 8U ⇤Int. U & Int. 8U ⇤Int. U & Int
represents the intersection of some type U and Int assuming U is disjoint to Int. Like arrows orrecords, such universal types distribute over intersections. Hence, (8U ⇤ Int. U) & (8U ⇤ Int. Int)is a subtype of 8U ⇤ Int. U & Int. We extend the type-splitting approach introduced in Chapter 3
to disjoint polymorphic types to obtain an algorithmic formulation. Like intersections distributeover arrows and records, they distribute over universal quanti�ers as well.
Enhanced subtyping and disjointness with more top-like types Unlike previous systems
with disjoint polymorphism [AOS17; Bi+19], we add a context in subtyping judgments to trackthe disjointness assumption U ⇤0 A whenever we open a universal type 8U ⇤ A. B, similar tothe subtyping with F-bounded quanti�cation. The extra information enhances subtyping: weknow a type must be a supertype of >, if it is disjoint with ?. As an immediate result, 8U ⇤ ?. U
becomes a supertype to the greatest type >. This also �xes the following broken property inthe original F8+ , as we now have more types that are top-like.
De�nition 5.1 (Disjoint speci�cation). A ⇤ B , 8⇠ if A 6 C and B 6 C then eC d
To obtain a deterministic operational semantics, it is necessary for us to keep all thecommon supertypes of two disjoint types equivalent to > Meanwhile, we prove our subtyping
and disjointness relations are decidable in Coq. Note that in the original F8+ , the decidability ofthe two relations was proved manually, although the rest of the proof was mechanized.

7.2

The F8+ Calculus and Its Operational Semantics

This section introduces the F8+ calculus, including its static and dynamic semantics.

7.2.1

SyntaxThe syntax of F8+ is as follows:
Types
Checkable terms
Expressions
ValuesTerm contexts
Type contexts, ⌫, ⇠ ::= U | Int | > | ? | A & B | A ! B | 8U ⇤ A. B | {l : A}
? ::= _x : A. e | ⇤U . e | {l = e}
4 ::= p | G | 8 | > | 4 :| e1 ,, e2 | �x x : A. e | e1 e2 | e A | e.l

E ::= p | p : A | i | > | v1 ,, v2::= · |::= · |

, x :A, U ⇤0 A

100

Types Two kinds of types are added: the uninhabited type ? and the universal quanti�ed
type with a disjointness restriction 8U ⇤ A. B, which expresses that the type variable U is boundinside B and disjoint to type A.
Expressions We introduce two new constructs for disjoint polymorphism: ⇤U . e stands for
type abstractions, and e A is for type applications. As we will explain later with the typing
rules, some expressions do not have an inferred type (or principal type), including lambda
abstractions, type abstractions, and single-�eld records. We use metavariable p to represent
these expressions, which with optional annotations, are values. Also, note that expressions
inside record values do not have to be a value since our calculus employs call-by-name.
Contexts We have two contexts: tracks the types of term variables; tracks the disjointness
information of type variables, which follows the original design of F8+ . Although they can be
combined, keeping type and term contexts apart brings clarity to the relations which only
care about types, such as subtyping. We use ` A, ` , and ` judgments for the typewell-formedness and the context well-formedness (de�ned in Figure 7.2). For multiple typewell-formedness judgments, we combine them into one, i.e., ` A , B means ` A and ` B.

7.2.2

Subtyping

Figure 7.3 shows our subtyping relation, which extends BCD-style subtyping with disjoint
polymorphism, records, and the bottom type. Compared with the original F8+ , we add a context
to track type variables and their disjointness information. The context not only ensures thewell-formedness of types, but is also important to our new rule DS��������V��. An equivalence
relation (De�nition 7.1) is de�ned on types that are subtype of each other. These equivalent
types can be converted back and forth without loss of information.
De�nition 7.1 (Type equivalence).

`A⌘B,` A 6 B and` B 6 A.

For functions (rule DS����������) and disjoint quanti�cations (rule DS��������), subtyping
is covariant in positive positions and contravariant in negative positions. The intuition isthat type abstractions of the more speci�c type (subtype) should have a looser disjointness
constraint for the parameter type. 8U ⇤ >. A denotes that there is no constraint on U, since >is disjoint to all types. On the contrary, ? is the strictest constraint. It is useful in types like
8U ⇤ {l : ?}. A, which expresses that U does not contain any informative �eld of label l. Forintersection types, rules DS���������, DS���������, and DS�������� axiomatize that A & B is
the greatest lower bound of A and B. As a typical characteristic of BCD-style subtyping, type
constructors distribute over intersections, including arrows (rule DS���������A����), records(rule DS���������R��) and disjoint quanti�cations (rule DS���������A��).
101

`A

(Type Well-formedness)TW����

TW����

TW����

`>

`?

` Int

TW����
`A` A&B

TW����
U ⇤0 A 2

TW����
`A` {l : A}`UTW����
`A`B

TW������
`A
`B
`A!B

, U ⇤0 A ` B` 8U ⇤ A. B

(Type Context Well-formedness)`

TCW�����
``A

TCW������
`·, U ⇤0 A`(Term Context Well-formedness)`

CW�����
`CW������
`·``A, x :A

Figure 7.2: Well-formedness rules in F8+ .

Another feature of BCD subtyping, which is often overlooked, is the generalization of
top-like types, i.e. supertypes of >.
De�nition 7.2 (Speci�cation of top-like types).

`eAd ,` A ⌘ >.

Initially, top-like types include > and intersections like > & >. But the BCD subtyping
adds > ! > to it via rule DS��������A����, as well as A ! > for any type A due to thecontravariance of function parameters. Rule DS��������A���� can be viewed as a special caseof rule DS���������A���� where intersections are replaced by > (one can consider it as anintersection of zero components). Like the original F8+ , we extend this idea to universal types
and record types (rules DS��������A�� and DS��������R��).
The most important change is the rule DS��������V��. This rule means that a type variable
is top-like if it is disjoint with the bottom type. Every type B is a common supertype of B itself
and ?. If B is disjoint with ?, then it must be top-like. We proved that subtyping is decidable
via an equivalent algorithmic formulation.
The discussion about algorithmic subtyping is in Section 7.3.1.
Lemma 7.1 (Decidability of subtyping).

` A 6 B is decidable.

102

`A6B

(Declarative Subtyping)DS����������
`A6B

DS���������
`
`A
`A6A

`B6C

`A6C

DS��������
`A6B` B1 6 B2` A1 ! B1 6 A2 ! B2
DS��������
`A6B` {l : A} 6 {l : B}
DS��������` A2 6 A1`?6ADS���������`` A,B` A&B 6 A

` A&B 6 B

DS���������A����`` A,B,C` (A ! B) & (A ! C) 6 A ! B & C

DS���������R��
`` A,BDS��������A����``>6>!>DS��������R��`` {l : A} & {l : B} 6 {l : A & B}

` > 6 {l : >}, U ⇤0 A2 ` B1 6 B2

DS��������A��`, U ⇤0 A ` B1 , B2

DS��������V��U ⇤0 A 2` 8U ⇤ A1 . B1 6 8U ⇤ A2 . B2

DS���������A��
``A

DS��������
`
`A

`A6>

DS���������
`
` A,B

`A6C

` A 6 B&C

DS����������` A2 6 A1

DS��������
``A` (8U ⇤ A. B1 ) & (8U ⇤ A. B2 ) 6 8U ⇤ A. (B1 & B2 )` > 6 8U ⇤ >. >

`>6U

`A6?

Figure 7.3: Declarative subtyping rules.

Disjointness The notion of disjointness (De�nition 2.2), de�ned via subtyping, is used in
the original F8+ , as well as calculi with disjoint intersection types [OSA16]. We proved that
our algorithmic de�nition of disjointness (written as ` A ⇤ B, in Section 7.3.2) is sound to a
speci�cation in terms of top-like types.
Lemma 7.2 (Disjointness soundness). If` B 6 C we have `eC d.

` A ⇤ B then for all type C that

` A 6 C andInformally, two disjoint types do not have common supertypes, except for top-like types. Thisde�nition is motivated by the desire to prevent ambiguous upcasts on merges. That is, we wish
to avoid casts that can extract di�erent values of the same type from a merge. Thus in F8+ andother calculi with disjoint intersection types, we only allow merges of expressions whose only
common supertypes are types that are (equivalent to) the top type. For instance, consider themerge (1 ,, true) ,, (2 ,, ‘c’). The �rst component of the merge (1 ,, true) has type Int & Bool,
while the second component (2 ,, ‘c’) has type Int & Char. This merge is problematic because
Int is a supertype of the type of the merge (Int & Bool) & (Int & Char), allowing us to extract
two di�erent integers by casting the two terms to Int. Fortunately, our disjointness restriction
103

Typing modes, ::= ( | )u ::= i | > | e : A | u1 ,, u2Pre-values;`e , A(Bidirectional Typing)T����������
``T����������
``T����������
` B1 6 A; , x : A ` e ( B2;;`> ) >;` _x : A. e ( B1 ! B2

B ⇤ 8U ⇤ C1 . C2;

` e A ) C2 [U 7! A]
T������������
`A⇤B
;
;

T�������������
u1 ⇡ u2`;;`·; · ` u1 ) A` u1 ,, u2 ) A & B

T����������
; , x :A ` e ( A` �x x : A. e ) A

T�����������
`, U ⇤0 A;`e ( B;;

T����������; ` e1 ) A` {l = e} ( {l : A}

T�����������; `e ) B

x:A2` i ) Int

T����������; `e ( A;T����������
`
`

;

;

` e1 e2 ) C
T�����������; `e ) A;;` e1 ,, e2 ) A & B·; · ` u2 ) B

T�����������; `e ( A;` ⇤U . e ( 8U ⇤ A. B

A⇤B!C` A ⇤ C1

` e1 ) A`x ) A` (e : A) ) A` e2 ( BA ⇤ {l : C}

` e.l ) C

` e2 ) B

T������������; `e ( A;`e ( B` e ( A&B

T����������; `e ) A
;

;

`A6B

`e ( B

Figure 7.4: Bidirectional typing rules for F8+ .

rejects such merges since the supertype Int is not top-like.

7.2.3

Bidirectional Typing

The type system of F8+ , like the type systems we have seen in the previous two chapters, isbidirectional, with a subsumption rule triggered by type annotations.

104

A⇤B

(Applicative Distribution)
AD��������A����
A1 ⇤ B1 ! C1
A2 ⇤ B2 ! C2

AD��������R��
A1 ⇤ {l : B1 }A2 ⇤ {l : B2 }A1 & A2 ⇤ {l : B1 & B2 }A1 & A2 ⇤ B1 & B2 ! C1 & C2
AD��������A��
A1 ⇤ 8U ⇤ B1 . C1

A2 ⇤ 8U ⇤ B2 . C2

A1 & A2 ⇤ 8U ⇤ B1 & B2 . (C1 & C2 )AD���������
A⇤A

Figure 7.5: Applicative distribution rules in F8+ .

Typing As presented in Figure 7.4, there are two modes of typing: synthesis ()) and checking((). We use , as a metavariable for typing modes. ; ` e , A indicates that under typecontext and term context , the expression e has type A in mode ,. A bidirectional typesystem directly provides a type-checking algorithm. , , e are all inputs in both modes. Typesynthesis generates a unique type as the output (also called the inferred type), while typechecking takes a type as an input and examines the term.
Lemma 7.3 (Uniqueness of type synthesis). If ;A1 = A2 .

` e ) A1 and ;` e ) A2 thenChecking abstractions, type abstractions, and records To check a function _x : A. eagainst B1 ! B2 by rule T����������, we track the type of the term variable as the precise
parameter type A, and check if e can be checked against B2 . B1 must be a subtype of A toguarantee the safety of the function application. The type-checking of type abstractions⇤U . e works by tracking the disjointness relation of the type variable with the context andchecking e against the quanti�ed type B. Typing of records works similarly. Additionally,
there is a rule T������������, which checks an expression against an intersection type by
separately checking the expression against the composing two types. With this design, weallow _x : Int. x ,, true to be checked against (Int ! Int) & (Int ! Bool).
Application, record projection, and conversion of applicable types Like the _8+ calculus
in Chapter 6, we allows a term of an intersection type to directly apply, as long as the intersection
type can be converted into an applicable form. For example, (Int ! Int) & (Int ! Bool) isconverted into (Int & Int) ! (Int & Bool), which is a supertype of the former. Note that in theoriginal F8+ , this requires annotations since the expression being applied in an application musthave an inferred arrow type. When inferring the type of the application e1 e2 , rule T����������
�rst converts the inferred type of e1 into an arrow form B ! C and then checks the argument
e2 against B. If the check succeeds, the whole expression has inferred type C.

105

In F8+ , we have three applicable forms: arrow types, record types, universal types. Like
rule T����������, the typing of type application and record projection also allows the applied
term to have an intersection type, and relies on applicative distribution to convert the type.
Applicative distribution A ⇤ B (de�ned in Figure 7.5) takes type A and generates a supertype
B that has an applicable form. The �rst three rules bring all parts of the input intersection type
together. For example, assuming that we apply several merged functions whose types are A1 !
B1 , A2 ! B2 , ..., An ! Bn , the combined function type is (A1 & ... & An ) ! (B1 & ... & Bn ).
It is equivalent to the input type only when A1 , A2 , ..., and An are all equivalent. Essentially,
applicative distribution (A ⇤ B) is a subset of subtyping (A 6 B). The supertype is selected toensure that when a merge is applied to an argument, every component in the merge is satis�ed.
Unlike the design we showed in _8+ , even for record projection, incompatible conjuncts are notallowed in the applied type A. Although each one of the three �rst rules overlaps with there�exivity rule, for any given type, at most one result has an applicable form.
Since merges are treated as a whole applicable term, programmers can extend functions via
a compositional approach without modifying the original implementation. It also enables themodular extension of type abstractions and especially records, which play a core role in thetrait encoding used in Compositional Programming.
Davies and Pfenning also employ a similar design in their bidirectional type system forre�nement intersections [DP00]. Their type conversion procedure respects subtyping as well.
Instead of combining function types, it makes use of A & B 6 A and A & B 6 B to enumeratecomponents in intersections and uncover arrows.
Applicative distribution always determines:
Lemma 7.4 (Determinism of applicative distribution). For any type A,• if A ⇤ B1 ! B2 and A ⇤ C1 ! C2 , then B1 = C1 and B2 = C2 ;• if A ⇤ 8U ⇤ B1 . B2 and A ⇤ 8U ⇤ C1 . C2 , then B1 = C1 and B2 = C2 ;• if A ⇤ {l : B} and A ⇤ {l : C}, then B = C.

Typing merges with disjointness and consistency Well-typed merges always have inferred types. There are two type synthesis rules for merges, both combining the inferred
types of the two parts into an intersection. T������������ requires the two subterms to havedisjoint inferred types, like 1 ,, true. T������������� relaxes the disjointness constraint toconsistency checking (written as u1 ⇡ u2 ) to accept overlapping terms like 1,, 1. We will state theformal speci�cation of consistency in Section 7.4.1 and show how it is involved in the proofsof determinism and type soundness. Informally, consistent merges cause no ambiguity in theruntime. For practical reasons, we only consider pre-values (de�ned at the top of Figure 7.4)
in consistency checking, for which the inferred type can be told directly. The algorithms

106

Arguments

arg ::= e | A | {l}Evaluation contexts

E ::= [ ] 4 | [ ]| [ ] .; | [ ] , , E | E , , [ ] | [ ] :v • arg õ! u(Parallel Application)

PA����������
B ⇤ C1 ! C20
A e2
(e1 [x 7! e20 ]) : C2e2(_x : A. e1 ) : B • e2 õ!

PA�����������
A ⇤ {l : B}{l = e} : A • {l} õ! e : B

PA�����������

A ⇤ 8U ⇤ B1 . B2(⇤U . e) : A • C õ! (e[U 7! C]) : (B2 [U 7! C])
PA������������
v1 • arg õ! e1

v2 • arg õ! e2

v1 ,, v2 • arg õ! e1 ,, e2

e õ! e0(Small-Step Semantics)

S������������
v • e õ! uv e õ! uS�������������
v • {l} õ! uv.l õ! uS�������������
v õ!A v 0
v : A õ! v 0S�������������
v • A õ! uv A õ! uS�����������
�x x : A. e õ! e[x 7! �x x : A. e] : A

S�������������
e1 õ! e10
e2 õ! e20

S������������
e õ! e0e1 ,, e2 õ! e10 ,, e20

E[e] õ! E[e0 ]Figure 7.6: Small-step semantics rules.

for disjointness and consistency are presented in Section 7.3. In general, disjointness andconsistency avoid introducing ambiguity of merges, and enable a deterministic semantics for
F8+ .

7.2.4

Small-Step Operational Semantics

We specify the call-by-name reduction of F8+ using a small-step operational semantics in Figure 7.6. S������������, S�������������, and S������������� are reduction rules for application
and record projection. They trigger parallel application (de�ned in the middle of Figure 7.6)of merged values to the argument. Rule S����������� substitutes the �xpoint term variablewith the �xpoint expression itself. Note that the result is annotated with A. With the explicit
type annotation, the result of reduction preserves the type of the original �xpoint expression.
Through rule S�������������, values are cast to their annotated type. Such values must also
be pre-values. This is to �lter out checkable terms p including bare abstractions or records
without annotations, as p : A is a form of value itself and thus should not step.
A merge of multiple terms may reduce in parallel, as shown in rule S�������������. Only
when one side cannot step, the other side steps alone, as suggested by the evaluation context107E , , v and v , , E. Rule S������������ is the reduction rule of expressions within an evaluation
context. Since the rule can be applied repeatedly, we only need evaluation contexts of depth
one (shown at the top of Figure 7.6). Our operational semantics substitutes arguments wrappedby type annotations into function bodies, while it forbids the reduction of records since records
are values.
Parallel application Parallel application is at the heart of what we call nested composition in
CP. It provides the runtime behavior that is necessary to implement nested composition, andit re�ects the subtyping distributivity rules at the term level. A merge of functions is treatedas one function. The beta reduction of all functions in a merge happens in parallel to keep
the consistency of merged terms. For type abstractions or records, things are similar. The
parallel application handles these applicable merges uniformly via rule PA������������. To
align type application with the other two kinds of application, we extend arguments to types(at the top of Figure 7.6). In rule PA����������, the argument expression is wrapped by thefunction argument type before we substitute it into the function body. Parallel application oftype abstractions substitutes the type argument into the body and annotates the body with thesubstituted disjoint quanti�ed type. Rule PA����������� projects record �elds. Note these threerules have types to annotate the result, since in T����������, T�����������, and T����������
we only type the expression e inside in checking mode. With an explicit type annotation, theapplication preserves types.
Splittable types In Figure 7.7, we extend the type splitting algorithm of _8+ to universal types
in correspondence to the distributive subtyping rules (rule DS���������A����, rule DS�����
����R��, and rule DS���������A��). It gives a decision procedure to check whether a type issplittable or ordinary.
Lemma 7.5 (Type splitting loses no information). If `` A ⌘ B & C.

and` A and B

A ⇤ C thenExpression wrapping Rules for expression wrapping (eA u) are listed in the middle of
Figure 7.8. Basically, it splits the type A when possible, annotates a duplication of e by eachordinary part of A, and then composes all of them. The only exception is that it never uses
top-like types to annotate terms, to avoid ill-typed results like {l = 1} : Int ! >, but rather
generates a normal value whose inferred type is that top-like type, like (_x : Int. >) : Int ! >,via the top-like value generating function [[ ]], de�ned at the top of Figure 7.8.
Casting Casting (shown in Figure 7.8) is the core of the TDOS, and is triggered by theS������������� rule. Recalling that only values that are also pre-values will be cast, we canalways tell the inferred type of the input value and cast it by any supertype of that inferred108, ⌫ , ⇠ ::= U | Int | > | ? | A ! ⌫ | 8U ⇤ A. ⌫ | {l :Ordinary types
B

A⇤C

}

(Splittable Types)
S�����������
C1 B ⇤ C2
A ! C1S���������
C1 B ⇤ C2{l : C1 }A ! B ⇤ A ! C2

S���������
8U ⇤ A. C1

C1{l : B} ⇤ {l : C2 }S���������

B ⇤ C2

8U ⇤ A. B ⇤ 8U ⇤ A. C2

AA&B ⇤ B

Figure 7.7: Ordinary and splittable types in F8+ .

type. The de�nition of casting uses the notion of splittable types. In rule C�����������, thevalue is cast under two parts of a splittable type separately, and the results are put together
by the merge operator. The following example shows that a merge retains its form when castunder equivalent types.
((_x : Int. x) : Int ! Int) ,, ((_x : Int. true) : Int ! Bool)õ! (Int!Int) & (Int!Bool)
õ!Int!Int & Bool((_x : Int. x) : Int ! Int) ,, ((_x : Int. true) : Int ! Bool)((_x : Int. x) : Int ! Int) ,, ((_x : Int. true) : Int ! Bool)In the latter case, the requested type is a function type, but the result has an intersection type.
This change of type causes a major challenge for type preservation.
For ordinary types, rule C����������� casts an integer to itself under type Int. Under any
ordinary top-like type, the cast result is the output of the top-like value generator. The castingof values with annotations works by changing the type annotation to the casting (not top-like)supertype. Rule C�������������� and rule C�������������� make a selection between two
merged values. The two rules overlap, but for a well-typed value, the casting result is unique.
Example We show an example to illustrate the behavior of our semantics:

109

(Value Generator)[[A]][[{l :e[[>]] = >}]] = {l = >} : {l :[[A1 !

[[8U ⇤ A1 .

}2 ]] = (_x : >. >) : A1 !
2 ]] = (⇤U . >) : 8U ⇤ A1 .

A u

2
2

(Expression Wrapping)

EW��������· `e de[[]]

EW���������· ` ¬e⌫ d
e

⌫

e :⌫

EW��������
B1 A ⇤ B2

e
e

B1

u1

e

B2

u2

A u1 ,, u2

v1 õ!A v2(Casting)C�����������
i õ!Int iC�����������· `e d
v õ!

[[

]]

C������������· ` ¬e⌫ d·`A6⌫
e : A õ!⌫ e : ⌫C��������������
v1 õ! v10
v1 ,, v2 õ!
C�����������
B1 A ⇤ B2

v10v õ!B1 v1C��������������
v2 õ! v20
v1 ,, v2 õ!

v20

v õ!B2 v2v õ!A v1 ,, v2

Figure 7.8: Type splitting, expression wrapping and value casting rules in F8+ .

Let f := _x : Int & >. x ,, false in
õ!⇤
õ!⇤
õ!⇤

((f : (Int & > ! Int) & (Int & > ! Bool)) : Int & Bool ! Int & Bool) (1 ,, true){by rules S�������������, C�����������, and C������������}(f : Int & Bool ! Int) ,, (f : Int & Bool ! Bool) (1 ,, true){by rules S������������, EW��������, EW���������, and EW��������}(((1 ,, true) : Int ,, >) ,, false) : Int ,, (((1 ,, true) : Int ,, >) ,, false) : Bool{by rules S�������������, S�������������, C�����������, C��������������, and C��������������}1 ,, false

This example shows that a function with a splittable type will be cast to a merge of two copies
of itself with di�erent type annotations, i.e., two split results. The application of a merge offunctions works by distributing the argument to both functions. Finally, casting selects one
side of the merge under the annotated type. From this example, we can see that without the
precise parameter annotation of a lambda function (here Int & >), there is no way to �lter theargument 1 ,, true, causing a con�ict.

110

(Bottom-like Types)

cAb
BL�����
cAb

BL����

BL�����
cBb

cA & Bbc?bcA & Bb(Top-like Types)`eAd
TL��������
``e>dTL��������
`eAd

`eBd

`eA & Bd

TL����������`A`eBd

TL��������
`eBd`e{l : B}d`eA ! Bd

TL��������
`U ⇤0 A 2`eU d

TL��������
, U ⇤0 A `eBd
`e8U ⇤ A. Bd

cAb

Figure 7.9: Bottom-like type rules and top-like type rules.

7.3

Algorithmics

In Section 7.2 we have presented several relations in a declarative form, including subtyping,disjointness, and consistency. For the purposes of implementation, it is important to formulate
the corresponding algorithmic versions.

7.3.1

Algorithmic Subtyping

To obtain an equivalent algorithmic formulation of subtyping, we �rstly de�ne algorithms for
top-like types and bottom-like types inductively in Figure 7.9, then we introduce our algorithmic
subtyping and argue that it is equivalent to the declarative subtyping.
Top-like and bottom-like types Every top-like type is a supertype of all types (see De�nition 7.2), which is equivalent to >. Compared to the de�nition of top-like types in the original
F8+ [Bi+19], we add a type context in the subtyping judgment to keep track of type variables thatare disjoint to the bottom type. With type contexts, we can derive · `e8U ⇤ ?. U d by TL��������
since only top-like types are disjoint to ?. The corresponding declarative subtyping rule is thenovel DS��������V��. To eliminate the dependence of our top-like type algorithm on subtyping,
we de�ne bottom-like types as a separate relation and use cAb when ` A 6 ? is needed.
Lemma 7.6 (Equivalence of bottom-like types). If `` A 6 ?.

and` A and cAb if and only if

Then we obtain an algorithmic de�nition of top-like types (Figure 7.9) that is equivalent toDe�nition 7.2.
111

` A <: B(Algorithmic Subtyping)S��������
``US��������
`S��������
`A` Int <: Int` U <: U

S���������
`B` A <: ⇠` A & B <: ⇠S��������
` B1 <: A1

S��������
`
`

`e⌫ d

` A <: ⌫` ? <:S���������
`A` B <: ⇠S����������` A2 <: A1, U ⇤0 B1 ` A2 <: ⌫ 2

S��������
` A <: ⌫` A & B <: ⇠` 8U ⇤ A1 . A2 <: 8U ⇤ B1 . ⌫ 2S��������
B1 B ⇤ B2` A <: B1` A <: B` B1 <: ⌫ 2` A1 ! B1 <: A2 ! ⌫ 2` {l : A} <: {l : ⌫ }` A <: B2

Figure 7.10: Algorithmic subtyping rules.

Lemma 7.7 (Top-like equivalence).

`eAd if and only if` > 6 A.

Algorithmic subtyping Our subtyping algorithm is shown in Figure 7.10. This algorithm isan extension of the algorithm used in _8+ with splittable types (Chapter 3). The novel additions
are the rules involving disjoint polymorphism, which _8+ does not have. While rule S��������
requires the supertype B to be splittable, the remaining rules only apply to ordinary B. The
basic idea is to split the intersection-like right-hand-side type by rule S�������� until types
are in more atomic forms, i.e., ordinary, and then apply the remaining rules to decide whether
the left-hand-side type is a subtype of each ordinary part. For a subtyping A <: B checking tosucceed where B is splittable, we need every sub-checking of split types to succeed, as describedby the inversion lemma:
Lemma 7.8 (Inversion of the supertype in algorithmic subtyping). If B1 B⇤B2 thenif and only if ` A <: B1 and ` A <: B2 .

` A <: B

The key for the distributive subtyping rules to work is encoded in how we split types. For
example, only after we split Int ! Int & Bool into (Int ! Int) and (Int ! Bool), it becomesstraightforward to tell it is a supertype of (Int ! Int) & (Int ! Bool). Assuming that we only
have rule S��������� (see Figure 7.8) that splits intersection types, the system degenerates to theconventional intersection subtyping rules with disjoint polymorphism (like F8 ). In other words,
the ordinary-type rules (all rules except for rule S��������) are standard and the algorithm
design is modular. They are mostly the same as the declarative formulation with the additional
ordinary-type condition, except that rules S��������� and S��������� are embedded with112

A ⇤0G B(Disjointness Axioms)

D�������
B ⇤0G AA ⇤0G B

D������A����

D������R��

D������A��

D��������R��

Int ⇤0G A1 ! A2

Int ⇤0G {l : A}

Int ⇤0G 8U ⇤ A. B

A1 ! A2 ⇤0G {l : A}

D��������A��

D������A��

D������N��
l1 < l2

A1 ! A2 ⇤0G 8U ⇤ A. B

{l : C} ⇤0G 8U ⇤ A. B

{l1 : A} ⇤0G {l2 : B}

`A⇤B

(Type Disjointness)D�������
`
` A,B

`A⇤B

D����������
` A1 , A2` B1 ⇤ B2` A1 ! B1 ⇤ A2 ! B2
D���������
U ⇤0 A 2` A <: B`U ⇤B

A ⇤0G B

D���������
`B
`eAd
`A⇤B

D��������E�
`A⇤B` {l : A} ⇤ {l : B}

D���������
U ⇤0 A 2` A <: B` B⇤UD���������
B1 B ⇤ B2

D���������
`A
`eBd
`A⇤B

D��������
` A1 , A2` 8U ⇤ A1 . B1 ⇤ 8U ⇤ A2 . B2

D���������
A1 A ⇤ A2` A ⇤ B1`A⇤B

, U ⇤0 A1 & A2 ` B1 ⇤ B2

` A1 ⇤ B`A⇤B` A2 ⇤ B` A ⇤ B2

Figure 7.11: Algorithmic de�nition of disjointness in F8+ .

transitivity. For two universal types 8U ⇤ A1 . A2 and 8U ⇤ B1 . B2 , the subtyping of A1 and B1 iscontravariant, and the subtyping of A2 and B2 is covariant. When deciding the subtyping of
A2 and B2 , we add U ⇤0 B1 into the context to track the disjointness of the type variable. For
the special case of U disjoint to bottom-like types as rule DS��������V��, we have the context
to decide U to be top-like by our top-like type algorithm in rule S��������. Our algorithmic
subtyping is equivalent to the declarative subtyping and decidable:
Lemma 7.9 (Equivalence of subtyping).

` A <: B if and only if

Lemma 7.10 (Decidability of algorithmic subtyping).

113` A 6 B.

` A <: B is decidable.

u:A(Principal Type of Pre-Values)PT��������

PT��������

PT���������

PT����������
u1 : Au2 : B>:>i : Int(e : A) : A(u1 ,, u2 ) : (A & B)

u1 ⇡ u2(Consistency)C��������

C���������

i⇡ie:A ⇡ e:B

C�������������
·`A⇤B
u1 : Au2 : Bu1 ⇡ u2C�����������
u1 ⇡ uu2 ⇡ uu1 ,, u2 ⇡ uC�����������u ⇡ u1u ⇡ u2u ⇡ u1 ,, u2

Figure 7.12: Pre-value consistency rules in F8+ .

7.3.2

Disjointness

As shown in Figure 7.11, the disjointness de�nition is almost the same as the original F8+ [Bi+19].
The disjointness judgment ` A ⇤ B ensures that under the context , any common supertypeof A and B is a top-like type. Disjointness helps ensure the determinism of F8+ by forbidding
merging terms of types that are not disjoint with each other (rule T������������). Ouralgorithm of disjointness is sound with respect to our speci�cation (Lemma 7.2).
Compared to the original F8+ , there are two main novelties. Firstly, now the context may
tell us if a type variable is top-like, i.e., is disjoint to bottom-like types, and a top-like typevariable should be disjoint to any types. Secondly, in rules D��������� and D���������, we
split types instead of allowing only intersection types for the convenience of the proof. We
have an alternative disjointness de�nition in the original style proved to be equivalent in our
Coq formalization. We can prove the following properties:
Theorem 7.1 (Covariance of disjointness). If` A ⇤ B and` B <: C then

` A ⇤ C.

Theorem 7.2 (Substitution of disjointness). If, 0 [U 7! C 0] ` A[U 7! C 0] ⇤ B[U 7! C 0].

, U ⇤0 C ,0 ` A ⇤ B and` C 0 ⇤ C thenTheorem 7.1 is a generalization of rules D��������� and D���������. In short disjointness
is covariant: supertypes of disjoint types are still disjoint. Theorem 7.2 ensures the correct
behavior of the type instantiation of the type application. Disjoint types are still disjoint witheach other after instantiation.

114

7.3.3

Consistency

Rule T������������� is aimed to type merges of pre-values produced by type casting andexpression wrapping. The intention is not to accept more programs, so this rule is not supposed
to be exposed to users. The �rst question is: why are we considering the consistency of prevalues rather than values or expressions? The answer is that our system allows an expression(or a value) to be duplicated, and merged with type annotations in our dynamic semantics byrule C����������� and rule EW��������. For example,((_x : Int. x ,, false : Int ! Int & Bool) : Int ! Int & Bool) 1õ!
õ!

(_x : Int. x ,, false : Int ! Int ,, _x : Int. x ,, false : Int ! Bool) 1(1 ,, false) : Int ,, (1 ,, false) : Boolõ! 1 ,, false

Moreover, it is also allowed to produce a result of duplicated terms with the same type annotation, like 1 : Int ,, 1 : Int. Such values cannot pass disjointness checking but are harmless atruntime. To keep type preservation for the application results like the merge after the �rst andsecond steps, consistency judgments on annotated terms are necessary. In consistency checking(Figure 7.12), we take two pre-values and analyze them structurally. A merged pre-value u1 ,, u2
is consistent to another pre-value u if pre-values composing the merge are consistent with u.
Any two basic components from each term must be either disjoint (rule C�������������) or
only di�er in the annotation (except for the argument annotation of lambda abstractions inrule C���������). For instance, functions with di�erent annotations but the same body are
consistent (as the one after the �rst step in the example above), and 1 ,, true is consistent with
1 ,, ‘a’. Note that we use u : A to represent the principal type of u is A, which is a syntactical
approach to compute the types from pre-values (shown in Figure 7.12) This syntactic approachis complete with respect to our type system.
Lemma 7.11 (Pre-values have principal types). 9 A, u : A.
Lemma 7.12 (Completeness of principal types). If ; · ` u ) A then u : A.
Also note that any disjoint pre-values are also consistent. So rule T������������� is a strict
relaxation of rule T������������ on pre-values.

7.4

Type Soundness and Determinism

In this section, we show that the operational semantics of F8+ is type-sound and deterministic.
In F8+ , determinism also plays a key role in the proof of type soundness.

115

7.4.1

Determinism

A common problem with determinism for calculi with a merge operator is the ambiguityof selection between merged values. In our system, ambiguity is removed by employing
disjointness and consistency constraints on merges via typing.
Lemma 7.13 (Consistent values cause no casting ambiguity). If v1 ⇡ v2 then for all type A thatv1 õ!A v10 and v2 õ!A v20 then v10 = v20 .
Two values in a merge have no con�icts as long as casting both values under any typeleads to the same result. This speci�cation allows v1 and v2 to contain identical expressions(may di�er in annotations), and terms with disjoint types as such terms can only be cast under
top-like types, and the cast result is only decided by that top-like type.
Lemma 7.14 (Top-like casting is term irrelevant). If · `eAd and v1 õ!A v10 and v2 õ!A v20
then v10 = v20 .
This is because casting only happens when the given type is a supertype of the cast value’stype, and disjoint types only share top-like types as common supertypes (Lemma 7.2).
Lemma 7.15 (Upcast only). If ·; · ` v ) B and v õ!A v 0 then · ` B 6 A.
With consistency, casting all well-typed values leads to a unique result. The remaining reduction
rules, including expression wrapping and parallel application, are trivially deterministic.
Lemma 7.16 (Determinism of casting). If ·; · ` v ) B and v õ!A v1 and v õ!A v2 , thenv1 = v2 .
Theorem 7.3 (Determinism of reduction). If ·; · ` e ) A and e õ! e1 and e õ! e2 thene1 = e2 .

7.4.2

Progress

Annotated values trigger casting, for which the progress lemma can be directly proved, as weknow, v must have an inferred type that is a subtype of B.
Lemma 7.17 (Progress of casting). If ·; · ` v ) A and ·; · ` v ( B then there exists a v 0 suchthat v õ!B v 0.
The progress lemma for expression wrapping is more relaxed. It does not enforce that e ischecked against the wrapping type A because that is the typical situation where we need touse the relation.
Lemma 7.18 (Progress of expression wrapping). If ·; · ` e ( A and · ` B then there exists an
0expression e0 that e
B e.
116

Parallel applications deal with function application, type application, and record projection.
We use the term general application of a value v to an argument arg next to denote all of thesefor simplicity.
Lemma 7.19 (Progress of parallel application). If ·; · ` v • arg ) A then there exists a
pre-value u such that v • arg õ! u.
Finally, the progress property of reduction can be proved.
Theorem 7.4 (Progress of reduction). If ·; · ` e , A then either e is a value or there exists an
expression e0 such that e õ! e0.

7.4.3

Preservation

Proving progress is straightforward, but preservation is much more challenging. When typing
merges, we need to satisfy the extra side conditions in rules T������������ and T�������
������: disjointness and consistency. While the former only depends on types, the latter
needs special care.
Consistency Like _8+ , casting may duplicate terms. For example, 1 õ!Int & Int 1 ,, 1 byrule C�����������. We have to ensure any two merged casting results are consistent:
Lemma 7.20 (Value consistency after casting). If ·; · ` v ) C and v õ!A v1 and v õ!B v2
then v1 ⇡ v2 .
Then we need to make sure that consistency is preserved during reduction. Recall thatconsistency is de�ned on pre-values. Consider any three components from consistent merges,
since merges are reduced in parallel (rule S�������������), the sub-expression e in merges
like e : A ,, e : B ,, e : C remains the same until it is cast by A, B, and C respectively. Guarded by
the determinism theorem of reduction (Theorem 7.3) and the consistency lemma of casting(Lemma 7.20), we prove consistent pre-values are always consistent after possible reduction.
Lemma 7.21 (Reduction keeps consistency). If ·; · ` u1 ) A and ·; · ` u2 ) B and u1 ⇡ u2
then
• if u1 is a value and u2 õ! u20 then u1 ⇡ u20 ;• if u2 is a value and u1 õ! u10 then u10 ⇡ u2 ;• if u1 õ! u10 and u2 õ! u20 then u10 ⇡ u20 .
Besides, when parallel application substitutes arguments into merges of applicable terms or
projects the wished �eld, consistency is preserved as well. This requirement enforces us tode�ne consistency not only on values but also on pre-values since the application transforms avalue merge into a pre-value merge.
117

(Runtime Subtyping in F8+ )A.B
RS��������
B1 B ⇤ B2

RS���������
A.A

A1 . B1

A2 . B2

A1 & A2 . B

Figure 7.13: Runtime subtyping in F8+ .

Lemma 7.22 (Parallel application keeps consistency). If ·; · ` v1 ) A and ·; · ` v2 ) B andv1 ⇡ v2 and v1 • arg õ! u1 and v2 • arg õ! u2 then u1 ⇡ u2 when• arg is a well-typed expression;• or arg is a label;• or arg is a type C; we know A ⇤ 8U ⇤ A1 . A2 and B ⇤ 8U ⇤ B1 . B2 ; and · ` C ⇤ A1 & B1 .
Runtime subtyping In F8+ , types are not always precisely preserved by all reduction steps.
Speci�cally, when we cast a value v õ!A v 0 (in rule S�������������) or wrap a term e
A u(in rule PA����������), the context expects v 0 or u to have type A, but this is not always true.
In our casting rules shown at the bottom of Figure 7.8, most values will be reduced to resultswith the exact type that we want, except for rule C�����������. The inferred type of theresult is always an intersection, which may di�er from the original splittable type. The runtime
subtyping relation (Figure 7.13) describes the change of types during reduction accurately, If
A . B, we say A is a runtime subtype of B. Compared to _8+ , the relation is simpli�ed thanks
to the increase of type annotation in values. The following lemma shows that while the two
types in a runtime subtyping relation may be syntactically di�erent, they are equivalent underan empty type context (i.e. · ` A 6 B and · ` B 6 A).
Theorem 7.5 (Runtime subtypes are equivalent). If A . B then · ` A ⌘ B.
With runtime subtyping, we de�ne the preservation property of casting, expression wrapping, and parallel application as follows.
Lemma 7.23 (Casting preserves typing). If ·; · ` v ) A and v õ!B v 0 then there exists a typeC such that ·; · ` v 0 ) C and C . B.
Lemma 7.24 (Expression wrapping preserves typing). If ·; · ` e ( B and · ` B 6 A ande
A u then there exists a type C such that ·; · ` u ) C and C . A.
Lemma 7.25 (Parallel application preserves typing). If ·; · ` v • arg ) A and v • arg õ! uthen there exists a type B such that ·; · ` u ) B and B . A.
118

Of course, we can prove that the result of casting always has a subtype (or an equivalenttype) of the requested type instead of a runtime subtype. But it would be insu�cient for typepreservation of reduction. In summary, if casting or wrapping generates a term of type B when
the requested type is A, we need B to satisfy:• B is a subtype of A because we want a preservation theorem that respects subtyping.
• For any type C, A⇤0 C implies B ⇤0 C. This is for the disjointness and consistency checking
in rules T������������ and T�������������. Note that B 6 A is not enough for thisproperty.
• If A converts into an applicable type C, then B converts into an applicable type too.
Although the type equivalence satis�es the �rst two conditions, it breaks the last one. For
example, > is equivalent to > ! >, but one may not convert > to an applicable type by theapplicative distribution. So it is infeasible to replace the runtime subtyping with the typeequivalence.
Restricted check subsumption Conventionally, a term of type B can be checked by any
type C that is a supertype of B in a bidirectional type system. However, this property does nothold in our system when C is a top-like type. For example, although > ! > is a supertype ofany types, values like (_x : Int. x + 1) : > ! > and ({l = 1}) : > ! > are forbidden. Obviously,
when these terms are applied, for example, to >, we cannot perform beta reduction.
((_x : Int. x + 1) : > ! >) > õ! ((x + 1) [x 7! > : Int]) : >ill-typed

We want to make sure in a valid application ((_x : A. e1 ) : B) e2 , the argument e2 always
satis�es the parameter annotation A, so it can be substituted in. What is more, we do not want
the reduction result depends on B. Therefore, when two values that only di�er in annotation B
apply to the same argument, their reduction results will only di�er in the outermost annotation
too. Then the consistency is kept during parallel application (Lemma 7.22).
Therefore, our check subsumption lemma is in a restricted form.
Lemma 7.26 (Restricted check subsumption). If ;¬ `eBd then ; ` e ( B.

` e ( A and` A <: B and B and

Replacing the checked type by its supertype is safe as long as it does not have any top-likepart. Nevertheless, a function annotated with an intersection, like (_x : Int. x ,, true) : (Int !
Int) & (Int ! Bool), is still well-typed.

119Motivation of expression wrapping Before we reach the type preservation lemma of
expression wrapping (Lemma 7.27), it may not be obvious why we have to design such a new
relation to handle the argument before substituting it into a lambda body. We need expression
wrapping because other alternatives do not work. First, in CBN evaluation, the argument does
not necessarily have to be a value. And we cannot tell the shape of the argument passed in. This
is why we do not simply use the casting relation like _8+ . Another direct option is to annotate
the argument by the parameter type of the function. But it leads to ill-typed results because of
the restriction in our check-subsumption lemma.
(_x : >. e : (Int ! Int) ! Int) (_x : Int. x) õ! (e[x 7! (_x : Int. x) : >]) : Int
To overcome the incomplete check subsumption, we could annotate the argument twice, likethe following example. However, it causes severe problems in consistency.
((_x : A. e) : B1 ! B2 ,,(_x : A. e) : C1 ! C2 ) e0 õ! (e[x 7! e0 : B1 : A]) : B2 ,,(e[x 7! e0 : C1 : A]) : C2
The pair of functions are consistent since they only di�er in outermost annotation. But after
the application reduces, they turn into two annotated expressions, and the inside do not haveto be identical, and therefore may not be consistent.
Because terms like (_x : A. e) : B1 ! B2 is consistent with (_x : A. e) : C1 ! C2 , but after
application on e0, it will turned into (e[x 7! e0 : B1 : A]) : B2 and (e[x 7! e0 : C1 : A]) : C2 which do
not have to be not consistent.
Next, we show the preservation of expression wrapping and parallel application.
Lemma 7.27 (Expression wrapping preserves typing). If ·; · ` e ( B and · ` B 6 A ande
A u then 9 C that ·; · ` u ) C and C . A.
Lemma 7.28 (Parallel application preserves typing). If ·; · ` v • arg ) A and v • arg õ! uthen 9 B that ·; · ` u ) B and B . A.
Narrowing and substitution lemmas Before proving type preservation, we have to provenarrowing and substitution lemmas, including both type and term substitutions. The narrowing
lemma for typing is mainly to deal with proof cases regarding universal types. To check an
expression against a supertype, we need this property to tighten the disjointness constraint of
the type variable in the context of a typing judgment, since a supertype of a universal type has
a more tight disjointness constraint.
Lemma 7.29 (Typing narrowing). If, U ⇤0 B , 0; ` e , C.

, U ⇤0 A ,0;` e , C and` B 6 A then

The type substitution lemma for typing is necessary for the instantiation of type variables.
120

We always use types satisfying the disjointness constraint of a universal type to substitute. We
need to make sure that the typing judgment still holds after type substitution:
Lemma 7.30 (Type substitution preserves typing). If , U ⇤0 A ,then , 0 [U 7! B]; [U 7! B] ` e[U 7! B] , C [U 7! B].

0;` e , C and`A⇤B

In beta reduction or the reduction of �xpoints, we want the term substitution of theparameter inside the function body to always preserve types when the argument has a runtime
subtype of the function input type. This is di�erent from traditional term substitution lemmas.
Our expression wrapping does not necessarily produce a wrapped result with the identical
type to the wrapping type (Lemma 7.27). In addition, if we substitute a term with a runtime
subtype into an expression, the substituted result does not infer the original type: it should
infer an runtime subtype, though it can still be checked by the original checking type.
Lemma 7.31 (Term substitution preserves type synthesis). If ; , x : A , 0 ` e ) C and; ` e0 ) B and B . A then there exists a type C 0 that ; , 0 ` e[x 7! e0] ) C 0 andC 0 . C.
Lemma 7.32 (Term substitution preserves type checking). If ; , x : A ,; ` e0 ) B and B . A, then ; , 0 ` e[x 7! e0] ( C.

0 ` e

( C andFinally, with the lemmas above and runtime subtyping, we have the type preservation
property of F8+ . That is, after one or multiple steps of reduction (õ!⇤ ), the inferred type ofthe reduced expression is a runtime subtype. Therefore, for checked expressions, the initial
type-checking always succeeds.
Theorem 7.6 (Type preservation with runtime subtyping). If ·; · ` e , A and e õ!⇤ e0 thenthere exists a type B such that ·; · ` e0 , B and B . A.
Corollary 7.1 (Type preservation). If ·; · ` e , A and e õ!⇤ e0 then ·; · ` e0 ( A.
Summary In this chapter, we presented a new formulation of the F8+ calculus and showed
how it serves as a direct foundation for Compositional Programming. In contrast with theoriginal F8+ , we adopt a direct semantics based on the TDOS approach and embrace call-byname evaluation. As a result, the metatheory of F8+ is signi�cantly simpli�ed, especially due tothe fact that a coherence proof based on logical relations and contextual equivalence is notneeded. In addition, our formulation of F8+ enables recursion and impredicative polymorphism,validating the original trait encoding by Zhang et al. [ZSO21]. We proved the type-soundness
and determinism of F8+ using the Coq proof assistant. Our research explores further possibilitiesof the TDOS approach and shows some novel notions that could inspire the design of othercalculi with similar features.

121

122

CHAPTER 8

D��������� ��� R������ ����8.1

Discussion

This section provides some discussion on design choices, a comparison with elaboration
semantics as well as implementation considerations and possible extensions for future work.

8.1.1

TDOS versus an Elaboration Semantics

This dissertation proposes the use of type-directed operational semantics for modelling languages with a merge operator. Since a general form of the merge operator has a type-directedsemantics, previous work has favored an elaboration semantics. Traditionally, for languages
with type-directed semantics, elaboration has been a common choice. That is the case, forinstance, for many previous calculi with the merge operator [Dun14; OSA16; AOS17; BOS18;
Bi+19], gradual typing [ST06], or type classes [WB89; Kae88]. In the elaboration approach,the idea is that the source language can be translated via a type-directed translation into a
conventional target calculus, whose semantics is not type-directed. In the case of languages
with the merge operator, the target calculus is typically a conventional calculus (such as theSTLC) extended with pairs. The implicit upcasts that extract components from merges aremodelled by explicit projections with pairs. One very appealing bene�t of the elaboration
semantics is that it gives a simple way to obtain an implementation. Since elaboration targets
conventional languages/calculi, that means that it can simply reuse existing and e�cient implementations of languages. For example, in the case of the merge operator, a key motivationof Dun�eld was that the elaboration could just target ML-like languages, which have severale�cient implementations available. From the implementation point of view, the TDOS would
be more useful for guiding the design of a dedicated virtual machine, compiling directly to
bytecode/assembly, or having an interpreter. However, obtaining an e�cient implementation
for the latter options would require signi�cantly more e�ort than with an elaboration approach.

123

Nevertheless, the reason for designing a semantics for a language or calculus is not merely
implementation. In fact, the implementation aspects are not our primary motivation for TDOS.
Although, as we will discuss in Section 8.1.2, TDOS can provide some insights for obtaininge�cient implementations as well. Furthermore we do not view TDOS as being mutually
exclusive with elaboration: both approaches have interesting aspects and they can servedi�erent purposes. Our main motivation for the TDOS is reasoning. A semantics is supposed todescribe the meaning of the language constructs in the language. Having a clear and high-level
presentation of the semantics is then useful for language implementers to understand the
behaviour of the language. Furthermore, it is also useful to provide programmers with a mental
model of how programs are executed, and to study the properties of the language. Next, wegive more details on the advantages of a direct semantics over the elaboration semantics interms of reasoning and proof methods employed in previous work on disjoint intersection
types.
Shorter, more direct reasoning. Programmers want to understand the meaning of theirprograms. A formal semantics can help with this. With our TDOS we can essentially employ
a style similar to equational reasoning in functional programming to directly reason aboutprograms written in _8 . For example, it takes a few reasoning steps to work out the result of(_x. x + 1 : Int ! Int) (2 ,, ‘c’):
õ!
õ!
õ!

(_x. x + 1 : Int ! Int) (2 ,, ‘c’)
(2 + 1) : Int
3 : Int3by S�������� and castingby S�������� and arithmetic
by S��������� and casting

Here reasoning is easily justi�able from the small-step reduction rules and type-directed
reduction. Building tools (such as debuggers), that automate such kind of reasoning should beeasy using the TDOS rules.
However, with an elaboration semantics, the (precise) reasoning steps to determine the �nal
result are more complex. Firstly the expression has to be translated into the target language
before reducing to a similar target term. Figure 8.1 shows this elaboration process in _8 , where
an expression in the source language is translated into an expression in a target language withproducts. The source term (_x. x + 1 : Int ! Int) (2 ,, ‘c’) is elaborated into the target term(_G . x + 1) (fst (2 , ‘c’)). As we can see the actual derivation is rather long, so we skip the fullsteps. Also, for simplicity’s sake, here we assume the subtyping judgement produces the moststraightforward coercion fst. This elaboration step and the introduction of coercions into theprogram make it harder for programmers to precisely understand the semantics of a program.
Moreover while the coercions inserted in this small expression may not look too bad, in larger
programs the addition of coercions can be a lot more severe, hampering the understanding of124

T������...
T����· ` (2 ,, ‘c’) ) Int & Char
(2 , ‘c’)······S�������
_G . x p1····
Int & Char <: Int
··
·
T����
· ` (2 ,, ‘c’) ( Int
fst (2 , ‘c’)...

· ` (_x. x + 1 : Int ! Int) ) Int ! Int
··
··
··
··
··
T����
· ` (_x. x + 1 : Int ! Int) (2 ,, ‘c’) ) Int

fst(_G . x + 1) (fst (2 , ‘c’))Figure 8.1: Elaboration of (_x. x + 1 : Int ! Int) (2 ,, ‘c’) to a calculus with products.

the program.
After elaboration we can then use the target language semantics, to determine a target language
value.

õ!
õ!
õ!

(_G . x + 1) (fst (2 , ‘c’))(_G . x + 1) 2
2+1
3

reduction for application and pairs
by the beta reduction ruleby arithmetic

A �nal issue is that sometimes it is not even possible to translate back the value of the target
language into an equivalent “value” on the source. For instance in the _8+ '18 calculus [BOS18]
1 : Int & Int results in (1 , 1), which is a pair in the target language. But the corresponding source
value 1,,1 is not typable in _8+ '18. In essence, with an elaboration, programmers must understand
not only the source language, but also the elaboration process as well as the semantics of thetarget language, if they want to precisely understand the semantics of a program. Since themain point of semantics is to give clear and simple rules to understand the meaning of programs,
a direct semantics is a better option for providing such understanding.
Simpler proofs of unambiguity. For calculi with an elaboration semantics, unrestrictedintersections make it harder to prove coherence. Our _8 calculus, on the other hand, has adeterministic semantics, which implies unambiguity directly. For instance, (1 : Int & Int) : Int
only steps to 1 in _8 . But it can be elaborated into two target expressions in the _8+ '18 calculus
corresponding to two typing derivations:(1 : Int & Int) : Int(1 : Int & Int) : Int

fst (1 , 1)

snd (1 , 1)

Thus the coherence proof needs deeper knowledge about the semantics: the two di�erent
terms are known to both reduce to 1 eventually. Therefore they are related by the logical125

relation employed in _8+ '18 for coherence. Things get more complicated for functions. The
following example shows two possible elaborations of the same function. Relating them requires
reasoning inside the binders and a notion of contextual equivalence.
_x. x + 1 : Int & Int ! Int_x. x + 1 : Int & Int ! Int_x. fst x + 1_x. snd x + 1

Furthermore, the two target expressions above are clearly not equivalent in the general case.
For instance, if we apply them to (1 , 2) we get di�erent results. However, the target expressions
will always behave equivalently when applied to arguments elaborated from the _8+ '18 source
calculus. _8+ '18, forbids terms like (1 ,, 2) and thus cannot produce a target value (1 , 2). Becauseof elaboration and also this deeper form of reasoning required to show the equivalence ofsemantics, calculi de�ned by elaboration require a lot more infrastructure for the source andtarget calculi and the elaboration between them, while in a direct semantics only one calculus
is involved and the reasoning required to prove determinism is quite simple.
Not limited to terminating programs. The (basic) forms of logical relations employed
by _8+ '18 and F8+ '19 cannot deal with non-terminating programs. In principle, recursion could
be supported by using a step-indexed logical relation [Ahm06], but this is left for future work.
Our calculi smoothly handle unrestricted intersections and recursion, using TDOS to reachdeterminism with a signi�cantly simpler proof method. It also makes other features that leadto non-terminating programs, such as recursive types, feasible.

8.1.2

Implementation considerations

The TDOS for _8 , _8+ , and F8+ is implementable directly, since the relations developed in thisdissertation are all essentially algorithmic. However, a direct implementation will not be verye�cient, for multiple reasons. Next we discuss some considerations for the design of e�cient
implementations of languages with the merge operator.
Merge lookups. From the e�ciency point of view, one particularly bad aspect of the TDOS
is that run-time lookup on merges (triggered by casting) does not exploit statically known
information. For instance, if we have a program such as:
let x : A & Int & A = e ,, 2 ,, e in x + 1
extracting the number 2 from the merge currently requires blindly going through the elementsin the merge at runtime until the integer value is found. The approach in the elaboration
semantics is much better here, since during type-checking we know statically where the integer
value can be found. Therefore, when generating code in the target language we can simply
126look up the value directly at that position, thus avoiding having to search for the value in themerge at runtime. It should be possible to create optimizations for the TDOS by employing
similar ideas to the elaboration. That is, using the type system to statically determine where to�nd values. For this to work with the TDOS, we would need to extend the TDOS with explicit
projections, so that code with implicit projections could be replaced with explicit projections.
For instance, if the integer 2 is at position 5 in a merge, the code x + 1 could be replacedby G [5] + 1, where G [5] denotes the projection of the 5th element in the merge. We plan toinvestigate them for future work.
Overhead from annotations. One other source of concern for e�ciency is the overheadcaused by type annotations, and their use at runtime. Type annotations in a TDOS play avery similar role to casts in cast languages [WF09; SW10], which are used, for instance, as
targets for gradually typed languages. The problem of how to design e�cient cast languages
is an important topic in the gradual typing literature, and the overhead caused by casts havebeen a notorious challenge in that area. In particular, a main source of overhead comes fromcasting functions. In calculi such as the blame calculus, function values need to accumulate
casts to avoid raising blame too early. Thus, function values can have an arbitrary numberof casts, which also leads to space e�ciency concerns. Luckily, for _8 and _8+ , we do not needto accumulate annotations around function values. Indeed, as shown in Section 7.2, function
values are of the form _x. e : A ! B in _8 and _8+ . That is, they only contain a single annotation.
In contrast to cast calculi, the approach used in _8 and _8+ , when reduction encounters multiple
annotations around a function is to simply replace the type annotation of the value. This
process happens in the casting rule C��������� for functions:C���������

¬eA2 dA1 <: B1B2 <: A2_x. e : B1 ! B2 õ! (A1 !A2 ) _x. e : B1 ! A2
Moreover, as discussed in Section 5.3.2, the premise 1 <: ⌫ 1 is not needed at runtime, and can
be avoided in an implementation. Thus, while the overhead caused by type annotations is stilla concern, we believe that _8 and _8+ avoid some of the thornier issues that gradually typed
languages have to deal with. Moreover, annotation replacement could actually have someadvantages over an elaboration approach. Multiple annotations around functions, would resultin multiple coercions being applied to the function in an elaboration approach. In contrast
annotation replacement avoids such coercions and immediately collapses annotations, so that,
ultimately, we only need to type-reduce the argument and the result of the function one time.
Nevertheless, a proper assessment of the performance impact of annotations at runtime isoutside of the scope of this work, and left for future work.

127

Parallel application. Parallel application in _8+ may raise some concern if available inunrestricted ways to programmers. In _8+ parallel application arises as a consequence ofthe distributivity of intersections over functions. That is, the following is a valid subtyping
statement in _8+ (and BCD subtyping):( 1 ! ⌫ 1 )&( 2 ! ⌫ 2 ) <:1 & 2 ! ⌫ 1 &⌫ 2

In essence, an intersection of two functions can be viewed as a single function with theintersections of the inputs and outputs. Thus, parallel application arises naturally in thesemantics of the language in order to support such form of conversions at runtime.
The semantics for the application of merged functions is to apply all of the functions to theargument. This turns what looks like one function call into two or more function calls and could
have a signi�cant impact on the time complexity of a program. A program that looks linear-time
could in fact be exponential, due to parallel application. Therefore it is important to consider
the consequences of parallel application and how they can be mitigated. One option would beto redesign the calculus so that parallel application is avoided. This would probably require
weakening the subtyping relation to avoid type conversions like the above. However, parallel
application is an important aspect of nested composition, and dropping parallel applicationfrom the calculus would prevent important applications of nested composition. Instead webelieve that a better approach is to restrict the use of parallel application in the source languagethat targets _8+ . In the following section we will come back to this topic.

8.2

Formal Relations to Existing Calculi

In this section, we compare the basic system _8 (introduced in Chapter 5) with two closely
related work in the literature: the original _8 [OSA16] calculus and Dun�eld’s system [Dun14].

8.2.1

Completeness of _8 with Respect to the Original Type System

To disambiguate, we use _8 '16 to denote the original calculus and _8 for our variant. We provethat the type system of the new variant is at least as expressive as the _8 '16 calculus1 . The
syntax of _8 '16 (minus pairs and product types) is almost the same as _8 , except that there areno �xpoints and the lambdas do not have any type annotations. Thus lambdas can only be
typed in checked mode. Figure 8.2 presents an excerpt of the type system. The type system hasa type well-formedness de�nition and a slightly di�erent disjointness relation compared to
our variant of _8 . Also note that the rule for the merge of values (rule T���������) is absent
1 Note that the original _ includes pairs and product types. In the Coq formalization we have a variant with8
pairs and product types as well. It has all the previous properties proved in this section. For simplicity andconsistency of presentation, we use the variant without pairs and product types here.

128

|= A

(Type Well-formedness)W�����

W�����

|= >|= IntW�����
|= A

W�����|= A|= B|= A ! B|= B|= A & B

A⇤B|= e , A õ! e0(Bidirectional Typing)

IBT������

IBT������
|= e ) A õ! e0
A <: B

IBT������

|= > ) > õ! >IBT������
|= e1 ) A ! B õ! e10|= e2 ( A õ! e20|= e1 e2 ) B õ! e10 e20
IBT������|= A

IBT������
x:A2|= i ) Int õ! i|= x ) A õ! x

IBT��������
|= e1 ) A õ! e10|= e2 ) B õ! e20

A⇤B|= e1 ,, e2 ) A & B õ! e10 ,, e20, x : A |= e ( A õ! e0|= fix x. e ( A õ! �x x : A. e0

IBT������
|= A|= e ( B õ! e0
IBT�������
|= e ( A õ! e0|= e : A ) A õ! e0 : A, x : A |= e ( B õ! e0|= _x. e ( A ! B õ! (_x. e0 : A ! B)

Figure 8.2: The type system of the original _8 (extended with �xpoints). Three rules that relate withproduct types are ignored.

because the disjointness restriction in well-formedness prevents duplicated values.
Some details need to be explained before presenting the completeness theorem. Firstly,
subtyping in our variant of _8 is stronger due to top-like types. Secondly, top-like types are
disjoint to any type in our variant, while the disjointness in the original _8 '16 is restricted to
types that are not top-like. We extended the bidirectional type system of the original _8 '16 withrecursion and designed an elaboration from the extended system to _8 . We proved a theorem
which shows the type system of _8 can type check any well-typed terms in _8 '16, with type
annotations inserted based on the typing derivation:
Theorem 8.1 (Completeness of typing with respect to the extended original _8 ). If
A õ! e0 , then ` e0 , A.

|= e ,

The well-typed expression e in _8 '16 is mapped to e0 in _8 which is proved to be well-typed.
It means that _8 '16 can be used as a surface language where many of the explicit annotations of_8 are inferred automatically. Moreover, the extension of �xpoints further shows that some
type inference with recursion is feasible. As the elaboration is also complete to the original typesystem, the _8 '16 calculus can be translated into _8 without loss of expressivity or �exibility.
1298.2.2

Soundness of _8 with respect to Dun�eld’s Operational Semantics

Dun�eld’s non-deterministic operational semantics [Dun14] motivates our TDOS. Here, weshow the soundness of the operational semantics of _8 with respect to a slightly extended
version of Dun�eld’s semantics. The need for extending Dun�eld’s original semantics is mostly
due to the generalization of the rule S���� in subtyping. In the conference paper [HO20] we
also discuss a variant of _8 , which uses the original subtyping, and show that such a variant
requires no changes to Dun�eld’s semantics.
Dun�eld’s original reduction rules are presented in Section 2.2. We extend her operationalsemantics with two rules rules DS������� and DS����������.
e0e(The Extension of Dun�eld’s Operational Semantics)

DS��������

DS��������

e1

e10

e1 e2

e10 e2

e2

e20

v1 e2

v1 e20DS��������

(_x. e) v

DS������������

DS������������

e1 ,, e2

e1 ,, e2e1DS���������

ee ,, eDS�������

e[x 7! v]

fix x. eDS����������

e1e2

e1 ,, e2

e[x 7! fix x. e]DS����������

e10

e2

e10 ,, e2e1 ,, e2DS�������

DS����������

v

>v

>

e20

e1 ,, e20>

Rule DS���������� states that the value > can be used as a lambda which returns >,suggested by the newly added top-like types for arrow types returning >. Rule DS�������
states that any value can be reduced to >, corresponding to A <: >. Dun�eld avoids having arule DS������� by performing a simplifying elaboration step in advance:` v : > õ! >D��������T������T

With such a rule, values of type > are directly translated into >, and do not need any further
reduction in the target language. We do not have such an elaboration step. Instead we extend
the original semantics with the two rules above.
Type erasure. Di�erently from Dun�eld’s calculus, _8 uses type annotations in its syntax
to obtain a direct operational semantics. | e | erases annotations in term 4. By erasing all
annotations, terms in _8 can be converted to terms in Dun�eld’s calculus (and also the original130_8 ). Note that for every value E in _8 , | v | is a value as well.
|i||>|| _x. e : A ! B || �x x : A. e || e | :A
| e1 | e2| e1 | ,, e2

=
=
=
=
=
=
=

i
>
_x. | e |fix x. | e ||e|| e1 | | e2 || e1 | ,, | e2 |Soundness. Given Dun�eld’s extended semantics, we can show a theorem that each step in
the TDOS of _8 corresponds to zero, one, or multiple steps in Dun�eld’s semantics.
Theorem 8.2 (Soundness of õ! with respect to Dun�eld’s semantics). If e õ! e0, then| e | ⇤ | e0 |.
A necessary auxiliary lemma for this theorem is the soundness of casting.
Lemma 8.1 (Soundness of casting with respect to Dun�eld’s semantics). If v õ!A v 0, then
| v | ⇤ | v 0 |.
This lemma shows that although the type information guides the reduction of values, it does
not add additional behavior to values. For example, a merge can step to its left part (or the rightpart) with rule C����������� (or rule C�����������), corresponding to rule DS������������
(or rule DS������������). Rule C������� can be understood as a combination of splitting(rule DS��������� v
v ,, v) and further reduction on each component separately.

8.3

Calculi with the Merge Operator

This section discusses various lines of related work, including calculi with a merge operator,
record calculi and some work on OOP languages.
For easy reference and distinction, sometimes we attach the publication year to the work to
the corresponding calculus name. For instance, F8+ '19 means the original formulation of F8+ by
Bi et al. [Bi+19].

8.3.1

Calculi with the merge operator and a direct semantics

Intersection types with a merge operator are a key feature of the Forsythe language of
Reynolds [Rey88]. He also studied a core calculus with similarities to _8 [Rey91]. However,merges in Forsythe are restricted and use a syntactic criterion to determine what merges areallowed. A merge is permitted only when the second term is a lambda abstraction or a single
131�eld record, which makes the structure of merges always biased. To prevent potential ambiguity,
the latter overrides the former when they overlap. If formalized as a tree, the right child of
every node is a leaf. The only place for primitive types is the leftmost component. Forsythe
follows the standard call-by-name small-step reduction, during which types are ignored. The
reduction rules deal with merges by continuously checking if the second component can beused in the context (abstractions for application, records for projection). This simple approach,however, is unable to reduce merges when (multiple) primitive types are required. Reynolds
admitted this issue in his later work [Rey97]. We use types to select values from a merge andthe disjointness restriction guarantees the determinism. Therefore the order of a value in amerge is not a deciding factor on whether the value is used.
The calculus _& proposed by Castagna, Ghelli, and Longo has a restricted version of themerge operator for functions only [CGL95]. The merge operator is indexed by a list of types
of its components. Its operational semantics uses the runtime types of values to select the“best approximate” branch of an overloaded function. _& requires runtime type checking onvalues, while in TDOS, all type information is already present in type annotations. Anotherobvious di�erence is that _8 supports merges of any type (not just functions), which are usefulfor applications other than overloading of functions, including: multi�eld extensible records
with subtyping [OSA16]; encodings of objects and traits [BO18]; dynamic mixins [AOS17]; or
simple forms of family polymorphism [BOS18].
Several other calculi with intersection types and overloading of functions have been proposed [CX11; Cas+15; Cas+14], but these calculi do not support a merge operator, and thus
avoid the ambiguity problems caused by the construct.

8.3.2

Calculi with a Merge Operator and an Elaboration Semantics

Instead of a direct semantics, many recent works [Dun14; OSA16; AOS17; BOS18; Bi+19] onintersection types employ an elaboration semantics, translating merges in the source language
to products (or pairs) in a target language. With an elaboration semantics the subtyping
derivations are coercive [Luo99]: they produce coercion functions that explicitly convert termsof one type to another in the target language. This idea was �rst proposed by Dun�eld, where
she shows how to elaborate a calculus with intersection and union types and a merge operator
to a standard call-by-value lambda calculus with products and sums [Dun14]. Dun�eld also
proposed a direct semantics, which served as inspiration for our work. However, her directsemantics is non-deterministic and lacks subject reduction (as discussed in detail in Section 2.2).
Unlike Forsythe and _&, Dun�eld’s calculus has unrestricted merges and allows a merge towork as an argument. Her calculus is �exible and expressive and can deal with several programs
that are not allowed in Forsythe and _&.
To remove the ambiguity issues in Dun�eld’s work, the original _8 calculus [OSA16] forbids
overlapping in intersections using the disjointness restriction for all well-formed intersections.
132

Disjointness
Unrestricted
Intersections
Determinism /Coherence
Recursion
Direct / Elaboration
Semantics
Subject Reduction
Distributive Subtyping
Disjoint Polymorphism
Evaluation Strategy_,,_8 '16

F8_8+ '18

F8+ '19

_8

_8+

F8+

No

Coh.

Coh.

Coh.

Coh.

Det.

Det.

Det.

Dir.

Ela.

Ela.

Ela.

Ela.

Dir.

Dir.

Dir.

-

-

-

-

CBV

CBV

CBV

CBV

CBV

CBV

CBN

CBV

Figure 8.3: Summary of intersection calculi with the merge operator.
( = yes, = no, - = not applicable )Since it does not support unrestricted intersections, the proof of coherence in _8 '16 is relatively
simple. Likewise, in the following work on the F8 calculus [AOS17], which extends _8 withdisjoint polymorphism, all intersections must be disjoint. However, the disjointness restriction
causes di�culties because it breaks stability of type substitutions. Stability is a desirable property
in a polymorphic type system that ensures that if a polymorphic type is well-formed then any
instantiation of that type is also well-formed. Unfortunately, with disjoint intersections only,
this property is not true in general. Thus F8 can only prove a restricted version of stability,
which makes its metatheory non-trivial.
Disjointness of all well-formed intersections is only a su�cient (but not necessary) restriction to ensure an unambiguous semantics. The _8+ '18 calculus [BOS18] relaxes the restriction
without introducing ambiguity. _8+ '18 employs the disjointness restriction only on merges, butotherwise allows unrestricted intersections. It allows 1 : Int & Int, but the same term is rejectedin the original _8 . Unfortunately, this comes at a cost: it is much harder to prove the coherenceof elaboration. Both _8+ '18 and F8+ '19 [Bi+19] deal with this problem by establishing coherence
using contextual equivalence and a logical relation [Tai67; Plo73; Sta85] to prove it. The proof
method, however, cannot deal with non-terminating programs. In fact, none of the existing
calculi with disjoint intersection types supports recursion, which is a severe restriction.
We retain the essence of the power of Dun�eld’s calculus (modulo the disjointness restrictions to rule out ambiguity), and gain bene�ts from the direct semantics.
Figure 8.3 summarizes the key di�erences between our work and prior work, focusing on
the most recent work on disjoint intersection types. The last three calculi are present in thethesis.

133

8.4 Record Calculi with Record Concatenation and Subtyping
As we have seen, in calculi with disjoint intersection types and records, the merge operator
concatenates records in a symmetric way. However, designing a record concatenation operator,
no matter symmetric or asymmetric, is a di�cult problem in calculi with subtyping, as identi�edby Cardelli and Mitchell [CM91]. In both cases, a record can “hide” some �elds via subsumption
to bypass the restriction on types. This issue has been discussed in Section 2.3. As far as weknow, no existing record calculus in the literature supports nested composition. However, there
are numerous designs in the literature with concatenation or subtyping or both.
Asymmetric concatenation without subtyping. Record concatenation is used by Wandto model multiple inheritance [Wan89]. He has a biased operator, which overrides the �rst
term by the second if they have con�icting �elds. He makes every record types explicitly state
whether a �eld is present in it or absent with respect to a �xed set of labels, which could bein�nite. It is similar to the algorithm implemented by Rémy to type-check records in an ML
extension, which keeps track of if a �eld is absent or not [Rém89].
Symmetric concatenation without subtyping. Harper and Pierce design a record calculus
with symmetric concatenation [HP91]. Their system _ || keeps the extension and restriction
operators in terms and types and generalizes them to work on two records (or record types).
A compatibility check is enforced on types, via the typing of record concatenation and typewell-formedness de�nition. Their type quanti�cation only takes care of negative information.
For example, ⇤0#; .0 stands for any type that does not have a �eld of name ;. The bottom
type serves as the key to resolving the semantic di�erence between type disjointness andcompatibility. A compatibility constraint with {l: t} in _ || is equivalent to a disjointness
constraint with {l: Bot} in F8+ . Although they avoid subtyping, it is still necessary to reason
about type equivalence with the type operations in their calculus. Their compatibility constraint
plays a similar role disjoint quanti�cation in our system. Xie et al. demonstrated that disjoint
polymorphism subsumes the form of row polymorphism present in _ || [Xie+20].
A similar disjointness constraint for symmetric record concatenation is employed forthe language Ur presented by Chlipala, which has a more comprehensive reasoning on typeequivalence [Chl10]. Ur is a dependently typed language with �rst-class labels, designed
for statically typed meta-programming with type inference. It encodes disjoint assertions in
guarded types. Ur uses type-level computation, including a type-level map operation, to allow
�exible and generic programs to be written using records. The semantics is given by elaboration,
and a translation of Ur programs into terms of the Calculus of Inductive Constructions ensures
type soundness. Like Harper and Pierce’s work, Ur has no subtyping as it introduces ambiguity.
134

The absence of subtyping avoids the “hidden �elds” problem.
Record subtyping without concatenation. Cardelli and Mitchell propose to use extension
and restriction as primitive operators instead of concatenation [CM91]. They introduce type
operators and negative restrictions in record types, so that in their calculus, via bounded
quanti�cation, programmers can declare a polymorphic function that takes any records lacking
certain �elds. Like merges in _+8 , extension in their system is con�ict-free, which is ensured bystatic type-checking. Compared to restriction, we can use type annotations to drop �elds in arecord in _+8 . A di�erence is that the two operators deal with a record and a �eld, while oursystem can handle two records in a merge. As identi�ed by them, with subtyping, a record can“hide” some �elds via subsumption to bypass the restriction on types, which makes it hard tocapture the absent �elds in record calculi. Their solution is to add type operations that can
encode negative information in subtyping. Corresponding to the term operators, they have two
type operators of the same name: extension on a type requires that the given �eld is absent
from the type; restriction on a type explicitly excludes the �eld from it, if it has such a �eld.
For example, {}\; stands for an empty record with a restriction that cannot have �eld ;. Any
subtype cannot have ; either. Besides special subtyping rules, they de�ne type equivalencerules to reason about type operations on records.
Subtyping-constraint-based calculi. Rémy [Rém95] and following work by Pottier [Pot00]
handle both symmetric and asymmetric concatenation in a constraint-based type system. To
deal with record concatenation, type operators or conditional constraints are used to express two
branches: either a �eld exists or is absent, mirroring the reduction of programs. In subtyping,
the type of records are distinguished into two forms: rigid record types and �exible record
types. A rigid record type of a term re�ects all �elds in it. Rigid records have no subtyping, butthey can be used in a concatenation with another record. Every rigid record type corresponds
to a �exible record type, which has subtypes and supertypes. However �exible records cannot
be used with concatenation. In _8 and _+8 all records are �exible and they can be used withconcatenation. Moreover, the subtyping in their systems is not expressive enough to support
nested composition.
Record calculi as extensions of system <: . The <:d calculus proposed by Cardelli [Car94]
extends System <: by extensible records, and combines row quanti�cation used in the previously discussed Harper and Pierce’s work [HP91] with bounded quanti�cation. <:d does nothave record concatenation as a primitive operator. Instead, it has row extension and restriction.
A translation to <: is provided. Poll [Pol97] solves the polymorphic record update problem
in System F with a restricted formulation of subtyping: it only supports width-subtyping on
record types. It has a record-update operator instead of concatenation. One record-update

135operation only alters a �eld in a record. The subtype checking in its typing rule makes sure therecord contains that �eld of the expected type.
The # calculus by Zwanenburg supports intersection types [Zwa95] (in its later version [Zwa97] intersection types are eliminated) and record concatenation in a <: -like system.
Similar to _+8 , multi-�eld records are obtained by concatenating single-�eld records, and there
is a distributivity rule for records in subtyping as well. They use a “with” construct for record
concatenation which is similar to the merge operator. Like rule T��������, the typing of “with”
introduces intersections, and it has a compatibility pre-condiction for the two terms’ types(written as #⌫). Only record types or )>? can be compatible. The concatenation operator isasymmetric. When two concatenated records have the same label, the right one overwrites theleft. Correspondingly, two compatible types can have common �elds as long as for those shared�elds, the right one has a subtype of the left’s , e.g. {l : Int}#{l : Int} & {l : Char}. In contrast,
disjointness is symmetric, and a type (unless it is top-like) cannot be disjoint with its subtypes,
to ensure the two sides of a merge coexist safely. To prevent the issue of subsumption “hiding”
�elds of di�erent types the compatibility checking, they require explicit annotations on merged
records. These annotations are used during elaboration to a target calculus, therefore a�ecting
the program behavior, like in our calculus. The semantics of # is given by elaborating into system with pairs and records. In this sense, it predates Dun�eld’s work. Concatenated records
are translated into pairs, where a special “overwriter” function, generated by the compatibility
derivation, is applied to update the overlapped �elds in the �rst record by the second one. In
Zwanenburg’s work coherence is left for future work.

8.5 Languages and Calculi with a Type-Dependent Semantics
Typed operational semantics. Goguen’s typed operational semantics combines typing
and reduction in one relation [Gog94]. It is designed for studying meta-theoretic properties,
especially about the reduction of well-typed terms, and is not aimed to describe type-dependent
semantics. Typed operational semantics has been applied to several systems, include simply
typed lambda calculi [Gog95], calculi with dependent types [Gog94; FL09] and higher-ordersubtyping [CG03]. Note that the semantics of these systems does not depend on typing, andthe untyped (type-erased) reduction relations are still presented to describe how to evaluate
programs. As in typed operational semantics, reduction has access to typing derivations, it ispossible to model the semantics of merge operator in this framework. But the resulting systems
might be similar to the prior work on disjoint intersection types with elaboration semantics,
and it is unclear how to cope with non-terminating programs.

136

Type classes Type classes [WB89; Kae88] are an approach to parametric overloading used inlanguages like Haskell. The commonly adopted compilation strategy for it is the dictionary
passing style elaboration [WB89; Hal+96; CKJ05; Cha+05]. Other mechanisms inspired bytype classes, such as Scala’s implicits [OMO10], Agda’s instance arguments [DP11] or Ocaml’s
modular implicits [WBY14] have an elaboration semantics as well. In one of the pioneering
works of type classes, Kaes gives two formulations for a direct operational semantics [Kae88].
One of them decides the concrete type of the instance of overloaded functions at run-time, by
analyzing all arguments after evaluating them. In both Kaes’ work and the following workby Odersky, Wadler, and Wehr [OWW95], the run-time semantics has some restrictions withrespect to type classes. For example, overloading on return types (needed for example for theA403 function in Haskell) is not supported. Interestingly, the semantics of _8 allows overloadingon return types, which is used whenever two functions coexist on a merge. For a detailed
example, please refer to Section 6.3.
Gradual typing. Gradual typing [ST06] is another example of a type-dependent mechanism,
since the success or not of an (implicit) cast may depend on the particular type used for the
implicit cast. Thus the semantics of a gradually typed language is type-dependent. Like othertype-dependent mechanisms the semantics of gradually typed source languages is usually
given by a (type-dependent) elaboration semantics into a cast calculus, such as the Blame
calculus [WF09] or the Threesome calculus [SW10].
Multiple dispatching. Multiple dispatching [Cli+00; CC99; Mus+08; Par+19] generalizes
object-oriented dynamic dispatch to determine the overloaded method to invoke based on theruntime type of all its arguments. Similarly to TDOS, much of the type information is recoveredfrom type annotations in multiple dispatching mechanisms, but, unlike TDOS, they only use
input types to determine the semantics.

8.6

OOP

8.6.1

Dealing with Con�icts in OOP

There is a rich literature in OOP with various solutions for dealing with (method) con�icts. As wehave mentioned throughout this dissertation, the approach to deal with con�icts by employing
disjointness and a symmetric merge operator is closely related to the trait model [Sch+03] inOOP. In the trait model, the idea is that the composition of traits should only be accepted if
there are no con�icts: i.e. con�icts should result in errors. To resolve errors the trait model
typically allows operations for renaming and/or removing methods from an inherited trait.
We can resolve con�icts in the same way, using subtyping to hide (remove) some values in amerge. Bi and Oliveira [BO18] have shown how to build a source language with �rst-class137

traits on top of a calculus with a symmetric merge operator. An alternative approach would be
to have an asymmetric merge operator, such as the one from Dun�eld [Dun14]. In such a case,con�icts would be automatically resolved by simply employing the order of composition. Sucha semantics is closely related to the traditional semantics for mixins [BC90; FKF98]. However,this approach is prone to subtle errors arising from the implicit overriding of values/methods
triggered by the automatic (and implicit) resolution of con�icts.
Other approaches to con�icts in class-based languages. Several other approaches to deal
with con�icts have been studied in the context of OOP. C++ supports a very expressive model ofmultiple inheritance that accepts two classes and ⌫ with con�icting method implementations
to be inherited by a third class ⇠. To deal with method invocations that have multiple con�icting
implementations, programmers in C++ can upcast ⇠ to either or ⌫ and then the ambiguity
is removed because the static type ( or ⌫) is used to decide which of the methods to invoke.
A simple formal model of such a mechanism in C++ (and some extensions) was describedby Wang et al. [Wan+18]. A closely related approach was proposed by Flatt, Krishnamurthi,and Felleisen [FKF98] in the context of mixins for a Java-like setting. The idea there is alsothat if a class inherits from multiple mixins with con�icting methods, then invocations ofcon�icted methods can still be disambiguated by �rst upcasting the class to the mixin withthe method implementation that the programmer wishes to invoke. This approach is more
�exible than the traditional biased approach of mixin inheritance that employs the order of
mixins in composition to automatically override methods with con�icts. Furthermore, it avoids
the issues of unintentional errors due to accidental overriding of methods. In such approaches
nominal types play an important role, since the nominal types enable distinguishing possible
overlapping (or even equal) structural types. Our work is done in the context of languages
with structural types and thus it is closer to the work on record calculi. However the additionof nominal types would be interesting to investigate and could allow for improved mechanisms
for con�ict resolution.
Delegation-based languages. More generally, the very dynamic nature of merges is closely
related to delegation-based OOP languages [Lie86; Kni99; FM95; US88; Ost02; BW00]. Delegation, originally introduced by Lieberman [Lie86], is a form of dynamic inheritance. With
dynamic inheritance the inherited implementation is not statically known. This is in contrast to
static inheritance (which is widely adopted by mainstream OOP languages), where the inheritedclass must be known statically: in mainstream OOP languages, when using class A extends B,
B is some concrete (statically known) class. Delegation can itself be further classi�ed into
two di�erence forms: static delegation and dynamic delegation [Kni99]. In static delegation,
the inherited implementation may be statically unknown, but it cannot be changed after it
is “bound” to the object. In dynamic delegation, the inherited implementation is stored in a138

mutable reference in the object and can be changed at any time. The CP language, for instance,
adopts a static delegation model, since the self-reference is immutable.
The Self language [US88] was the �rst OOP language to employ delegation. JavaScript
has a closely related model and is directly inspired by Self. In Self and JavaScript the idea isthat an object has a property that holds a link to another object, which is called the prototype.
The prototype object can have a prototype of its own, and so on. This o�ers a very dynamic
model where prototype objects can be changed at runtime, by simply mutating the prototypereference. In other words, Self and JavaScript follow a dynamic delegation approach. Due totheir dynamically typed nature, there is no support for statically detecting con�icts in JavaScript
or Self.
Research on type systems for delegation-based languages is much less explored comparedwith class-based languages. Fisher and Mitchell [FM95] were among the �rst to study typesystems for delegation. Kniesel [Kni99] further explored this space and has investigated ways
to deal with issues arising from con�icts. In his model, he avoids most accidental overriding
con�icts, by adopting a rule that a method m in one of the parents can only (implicitly) override
another method implementation with the same name in another parent, if the two parents havea common parent class. This way, unrelated methods with the same name cannot be accidentallyoverridden. The work by Ostermann [Ost02] adapts the idea of family polymorphism to adelegation-based setting, and o�ers some of the advantages of nested composition that is
enabled in _+8 . There are a few other statically typed approaches to delegation in the context
of OOP programming [BW00; SBD11]. Overall the main di�erence is that we are looking
at foundational calculi using intersection types and a merge operator, instead of looking at
the semantics of high-level OOP languages. One application of the calculi is indeed to model
high-level programming abstractions for OOP languages, but that is not the focus of thiswork. In contrast the aforementioned related work on delegation is speci�cally focused on thesemantics of higher-level OOP languages and language mechanisms.

8.7

Subtyping Algorithms

This section focus on subtyping algorithms with distributivity rules.

8.7.1

BCD Subtyping Algorithms

Pierce developed an algorithm for a form of subtyping close to BCD subtyping using a queue oftypes. His algorithmic decision procedure ;4 (f, g, g) is equivalent to the declarative judgmentf  g ! g, where g is the queue, containing known argument types of the right-hand-sidefunction type. When g is a function type g1 ! g2 , its argument type g1 is added to the queue.
When f is an intersection type f1 & f2 , the queue is duplicated on both sub-branches in orderto re�ect the distributivity rule, by distributing the argument types to both components of an139

intersection type. The rules for function types, top types and intersection types then take careof argument types in the queue. Bi, Oliveira, and Schrijvers adapted Pierce’s algorithm to BCD
subtyping and extended it with record types without major di�culties.
The decidability of BCD subtyping is shown in several other works [KT95; RU11; Sta15]
through manual proofs, and there are also proofs formalized in Coq [Lau12; Bes+16]. Bessai,
Rehof, and Düdder developed a fast algorithm veri�ed in Coq [BRD19]. Their algorithm ispresented as a relational abstract machine speci�cation, with a long proof due to the mismatch
between the styles of the declarative system and algorithmic system. In contrast, our algorithm
is de�ned in a simple relational form, keeping the modularity of existing rules, resulting in anovel, simple and concise formulation of the metatheory for the algorithm. Of course, the twolines of work have quite distinct goals: while we emphasize the modularity and simplicity ofthe metatheory, Bessai et al. are interested in a fast algorithm, which justi�es the additional
complexity in the metatheory of their approach.
Siek [Sie19], inspired by Laurent [Lau19], proposed a new subtyping system and proved thetransitivity lemma directly. Siek keeps the judgment form A <: B (like us), but most subtyping
rules require changes, and are less modular than our rules. Siek’s transitivity proof involves asize measure, while we avoid any size measure by using an alternative relation of types (proper
types), which exploits the properties of our splittable type relation. Both works formalize
the transitivity property, as well as soundness and completeness to BCD subtyping in proof
assistants.
Algorithms for minimal relevant logic subtyping. There are some algorithms designed
for the provability problem of the minimal relevant logic [GGR95; Vig00]. Such algorithms
build a deduction system. But their formalization is quite di�erent from conventional subtyping
relations. Here we focus on algorithms designed for subtyping systems that are similar to theminimal relevant logic in expressiveness power. Unlike Pierce’s decision procedure or modular
BCD subtyping, most algorithms for minimal relevant logic subtyping require a pre-processing
step on types. Typically this pre-processing step is some reduction of types into a normal form.
Muehlboeck and Tate [MT18] proposed a composable algorithmic framework called integrated subtyping. Integrated subtyping is able to generate decision procedures for various
systems with union and intersection types including BCD subtyping, and the one arising fromminimal relevant logic. Their strategy is to transform types on the left-hand side to a normal
form, which is the disjunctive normal form in the setting without distributivity over arrows. A
function called intersector is used in the conversion, and it varies according to the subtyping
rules. To decide A <: B, they rewrite with (a generalized version of) rule OS�����A�� asmuch as possible. In contrast, we split ⌫ to make the types match.
Subtyping in the Delta-calculus [Sto19] extends BCD subtyping with union types, and has
rules similar to minimal relevant logic. This work provides an algorithm for deciding subtyping,140

which �rst rewrites types into some standard normal forms. After rewriting, the left-hand typeis a union of intersections, while the right-hand type is an intersection of unions. The basic
components in both types include type variables and arrow types rephrased into a normal
form, which corresponds to our intersection-ordinary arrow types. Because all arrow types
are naturally union-ordinary, these components are ordinary in both modes, and therefore theleft-hand side type is an intersection of intersection-ordinary types, while the right-hand side
type is a union of union-ordinary types. However, this method may not be able to scale if union
arrow distributivity rules (rule S�����A��R������ and rule S�����A��L������, discussed in
Section 4.2.2) are to be added in the future. As discussed at the end of Section 4.3, the next stepof the algorithm is similar to ours, except that it works on normalized types.
Frisch, Castagna, and Benzaken [FCB08] extended semantic subtyping to intersection andunion types for the CDuce project. Type constructors act as their corresponding set-theoretic
operators. They provided an algorithm for the induced subtyping relation. Firstly they write
types into a disjunctive normal form. Then they check whether the result of the left-hand typeminus the right-hand type is an empty type by enumeration. Improved versions of the algorithm
were implemented and run in the current implementation of CDuce [Fri04]. Pearce followed
their path and introduced a subtyping algorithm with a constructive proof for soundness andcompleteness [Pea13].

8.8

Other Problems in Calculi with Intersection and Union
Types

Parallel reduction for typing unions. As discussed in Section 6.3 and Section 7.2.4, _+8 andF8+ applies a merge of multiple functions to the input together, and reduces every component in
the resulting merge simultaneously. Although their system does not have merges, Barbanera,
Dezani-Ciancaglini, and De’Liguoro also employed a similar evaluation strategy called parallelbeta-reduction in a calculus with intersection and union types. They consider beta-redexes
rather than components in a merge. Instead of reducing the leftmost beta-redex, all occurrencesof the same redex are reduced together. Likewise, their motivation is a typing rule that does
not preserve types under conventional beta-reduction. This typing rule eliminates union types.
If e has type A | B, the rule considers two cases: every occurrence of e has type A or has type B,
and type-checks the expression twice under the two assumptions. Since beta-reduction canchange the syntax form of such subterms, it has to be done in parallel. This kind of reduction
strategy was proposed by Knuth, and formalized in “The lambda calculus - its syntax andsemantics”[Chapter 13], and is known as Gross-Knuth reduction. As merges can serve as anelimination construct of unions, there might exists a deeper connection for this similarity inevaluation strategy.

141

142

CHAPTER 9C���������� ��� F����� ����In this thesis, we designed algorithmic formulations for subtyping relations that support
intersection types, union types, and distributivity rules. Most previous work has addressedsimilar problems using a pre-processing step to transform types into a normal form, before
comparing types for subtyping. We presented a new algorithm that directly compares source
types for subtyping, without a pre-processing phase. Splittable types are key to our algorithm.
Starting from the subtyping of intersection types, we illustrate that splittable types can scale
up to systems with union types and additional distributivity rules.
Then we showed how a type-directed operational semantics allows us to address the ambiguity problems of calculi with a merge operator utilizing the subtyping algorithms. Therefore,
with a TDOS approach, we answered the question of how to give a deterministic direct operational semantics for both the general merge operator in a setting with intersection types, as wellas, calculi with record concatenation and subtyping. Both of these problems are well-known to
be challenging in the literature, while at the same time having important practical applications.
Compared with the elaboration approach, having a direct semantics avoids the translation
process and a target calculus. This simpli�es both informal and formal reasoning. For instance,
establishing the coherence of elaboration in the original _8+ [BOS18] requires much more sophistication than obtaining the determinism theorem in _8+ . Furthermore, the proof method forcoherence in the original _8+ cannot deal with non-terminating programs, whereas dealing withrecursion is straightforward in _8 and _8+ . Besides recursion, our formulation of F8+ also enables
impredicative polymorphism, validating the original trait encoding by Zhang et al. [ZSO21].
The TDOS approach exploits type annotations to guide reduction. The key component of TDOS
is a casting reduction, which allows values to be further reduced depending on their type.

143

9.1

Future Work

9.1.1

Mutable References

All three calculi present in this thesis are purely functional and programs have no side e�ects.
As a consequence, the CP language does not support imperative objects. Objects can be composed to create new objects, but their values cannot be changed after initialization. Althoughimmutable data is safer and su�cient to simulate mutable data, in a practical programming
language, being able to alter the content of objects is convenient to users and sometimes canimprove the performance of code, as writing and reading data from memory cells is natural tothe current computer infrastructure. As a step towards integration of computational e�ects
and disjoint intersection types, one direction of our future work is to support mutable data.
Davies and Pfenning designed a calculus supporting re�nement intersection types andmutable references [DP00]. Their system allows a reference term to be typed by an intersection
type, for example, (Int ref) & (Pos ref) for ref 1. And being typed by an intersection type means
the term can have either of the conjuncts, Int ref and Pos ref. Knowing the reference has typeInt ref, we can alter its content by 0, which breaks type safety if we later dereference the termand expect it to be a Pos. To make the type system sound, Davies and Pfenning introduced avalue restriction for intersection types so terms like ref 1 cannot be typed by (Int ref) & (Pos ref).
They also dropped the distributivity law (rule OS�����A��) from subtyping because the value
restriction can be bypassed through it: function applications can have intersection types even
if the function body is not a value.
Blaauwbroek proposed a calculus with intersection and union types, and an unrestricted
merge operator [Bla17]. It models computational e�ects via pass by sharing, where variables
are mutable and there are no reference types or explicit referencing and dereferencing. For
assignments, the left part must be a variable, and no subtyping is allowed for the variable.
Therefore, the previous unsoundness problem is avoided in Blaauwbroek’s calculus.
Note that the unsoundness problem is due to the subtyping around references, like theinformation hiding problem in record concatenation. It is possible to overcome it with our typesystem design, where each expression have a synthesized type which is its principal type.
Next we will try adding reference types to the _8+ calculus, and discuss some potential
challenges. Besides the intention to enhance the calculus, we also want to explore the interactionof the distributivity laws in subtyping and mutable references under the setting of disjoint
intersection types.
Syntax We use A ref to denote the reference type of type A, and add three new terms
constructs: ref e allocates a reference with the initial value e. !e takes a reference e and reads
the corresponding value. Assignment expression e1 B e2 changes the content of reference e1
by e2 . We adopt a call-by-value reduction so that e2 will be assigned to e1 after both evaluating144

to values and the whole expression reduces to >. r denotes the cells or store locations, which
are the values of allocation expressions.

, ⌫ ::= Int | {l : A} | A ! B | A & B | > | A refTypee ::= x | i | > | e : A | {l = e} | _x. e : A ! B | �x x : A. e | e1 e2 | e1 ,, e2

Expr| ref e | !e | e1 B e2 | r

E ::= > | i | _x. e : A ! B | v1 ,, v2 | {l = v} | r

Value

We also add stores and cell contexts for reduction and typing respectively.
Stores` ::= · | ` , r = v⌃ ::= · | ⌃ , r : A

Cell Contexts

Subtyping The subtyping of reference types is invariant. There are two contexts where areference can be used: reading and writing. Reading is covariant. Assuming A ref is expected,
in this case a reference of a subtype of A is su�cient. Writing is contravariant. Since we areassigning values to the reference, the type is a constraint to the value, and a subtype is harderto satisfy than its supertype. So the conversion of types is only justi�ed in the subtype tosupertype direction.
OS����

A6B

OS�����R��

B6A(A ref) & (B ref) 6 (A & B) ref

A ref 6 B ref

Introducing the distributivity rule of references over intersections allows us to read andwrite cells in a composed way: a merge of two reference terms can be dereferenced together
and be �lled in one assignment.
But this rule, unlike other distributivity rules we have seen in previous chapters, does not
imply the equivalence of (A & B) ref and (A ref) & (B ref). Because (A & B) ref is not a subtypeof (A ref) & (B ref). (Assuming it is, we will have (A & B) ref 6 A ref.) Thus if we split the type
(A & B) ref we will lose information, which brings challenges to the subtyping algorithm design.
A possible solution is to separate the two roles of the reference type: like Reynolds suggested in
the design of Forsythe, the type of integer variables can be viewed as an intersection of integer
expressions, which can be evaluated, and integer acceptors, which can be assigned [Rey97].
Another alternative design is to interpret assignment as an updating operation. Then thereference type constructor becomes covariant and we can split a reference type just like how
we split record types.

145

S�����

C1
C1 refB ⇤ C2

B ref ⇤ C2 ref

In record calculi, we can update some �elds of a record without touching the remaining�elds. Generalized to merges, it is imaginable that if a cell already contains 1 ,, true, assigning
2 to it can replace the integer �eld and the whole value becomes 2 ,, true. It is a bit subtle totell whether a function can be updated by another one but with enough type information it isdecidable [XHO23]. However, this kind of design breaks the read-after-write property.
Top-like Types and Disjointness One may expect the following new rule for top-like types
and a congruence rule for reference types to be disjoint.
TL����

D����C��eAd

A ⇤0 BeA ref d

A ref ⇤0 B ref

But as A ref 6 > ref does not hold generally, it is unnatural to force some reference types
to be top-like. So the de�nition of top-like types remains unchanged.
Also, only if reference type constructors are covariant, we can justify the congruence
rule. Under the current invariant subtyping rule, two reference types can share non-top-likesupertypes when they are equivalent. In other cases, they are disjoint.
D����I��¬(A 6 B ^ B 6 A)
A ref ⇤0 B ref
Typing The cell context ⌃ is added to the bidirectional typing judgment ; ⌃ ` e , A. Like
the typing context, we assume it contains no identical cell names. All the four rules are insynthesis mode to maintain the typing properties in _8+ : all well-typed terms have a uniquesynthesized type.

146

����T�������

����T������

r:A2⌃;⌃ ` e ) A; ⌃ ` r ) A ref
����T������; ⌃ ` e1 ) A

A ⇤ B ref; ⌃ ` e1 B e2 ) >; ⌃ ` ref e ) A ref
����T������; ⌃ ` e2 ( B;⌃ ` e ) AA ⇤ B ref; ⌃ `!e ) B

The typing of assignment and dereference makes use of the runtime subtyping relation,
allowing A to be an intersection type. This is to cope with the distributivity rule rule OS�����R��. In case the type constructor of reference is not distributive, the rule AD����R��
should be dropped so that only terms of a reference type can be dereferenced or assigned.
����AD����R��

����AD����A ⇤ A0 ref

B ⇤ B0 ref

A & B ⇤ (A0 & B0) ref

A ref ⇤ A ref

Reduction Semantics We use store ` to keep track of the contents of cells during reduction.
The following two congruence rules demonstrate how to add the store trivially for rules that
do not make use of it.
����S��������

����S�������C��

0 0`|e õ! ` 0 |e0`|e õ! ` |e`|e : A õ! ` 0 |e0 : A`|ref e õ! ` 0 |ref e0

These conventional rules de�ne how to read from and write to memory. An assignment
expression changes the store and evaluates to the top value.
����S�������

����S�������

r=v2``|ref v õ! ` , r = v|r` 1 |!r õ! `|v
����S�������

`1 , r = v 0 , ` 2 |r B v õ! ` 1 , r = v , ` 2 |>Thanks to the distributivity rule, a merge of references can act like a reference. Rule S�������M�� has no side-e�ect so it is safe to keep using the same store `. For assignments, we147

want to accumulate all the changes to the store. The disjointness and consistency restriction intyping should guarantee that the evaluation order of all the assignments of the subterms does
not a�ect the result.
����S�������M��

`|!v1 õ!

`|v10

����S�������M��

`|v20`|!v2 õ!

` 1 |v1 B v õ! ` 2 |>`|!(v1 ,, v2 ) õ! `|v10 ,, v20`2 |v2 B v õ! `3 |>`1 |(v1 ,, v2 ) B v õ! `3 |>In the parallel reduction rule, both subterms in the merge take the same store and reduce.
An immediate problem is how to combine the two changed stores. Especially, the same cell
could be written in both expressions. Could the consistency restriction on merges guaranteethat such changes never con�ict?
����S���������

`|e1 õ! ` 1 |e10`|e2 õ! ` 2 |e20`|e1 ,, e2 õ! `3 |e10 ,, e20

Casting Consider casting a cell by a reference type. Due to the invariance in subtyping, thetarget type has to be equivalent to the original type of the cell. Therefore it is unnecessary tocoerce the stored value.
The problem is mainly around casting merges. Assuming there is a merge containing two
reference cells, even though they are disjoint, we need to know the exact types they have to
distinguish them. Either we look up the content of cells in the store, or we record the type
information, for example, as part of the syntax of cells. The following rules present the two
designs respectively. The second rule assumes that the value form of cells is annotated liker : A. Such annotation is compared and updated during casting.
����C��A������

r=v2`

v:B

����C������

A6B

B6A

B6A

r : B õ! (A ref) r : A`|r õ! (A ref) r

9.1.2

A6B

Unannotated Lambda Functions

Type checking veri�es programs and prevents runtime errors. While types make programs
safer, it could be tedious for users to write type annotations explicitly. Type inference provides
automatic reasoning and infers the type of some expressions to reduce the burden of users. To
improve the type inference of our calculi and the CP language, one approach is via global type
inference, which generates constraints from a program that contains no type annotation and148then solves the constraints. Related work on intersection types including algebraic subtyping[DM17; Par20] and type inference for disjoint intersection types [Ber19].
But here we want to consider another approach, that is to further utilize bidirectional typechecking for local type inference, speci�cally, to accept unannotated lambda functions. In theprevious calculi, we use bidirectional typechecking to obtain algorithmic type systems. Given a
program, our type checking algorithm can determine whether to accept it in a decidable manner.
This technique propagates information and is often used to type check applied functions thathave no type annotation. But this widely followed design cannot be directly applied to our
calculi. At the moment all the functions in CP are required to have annotations, which are used
to cast the argument before substituting it in the function body.
T������

T������

, x :A ` e ( Bx:A2` _x. e : A ! B ) A ! B`x ) A

T������

` e1 ) CC⇤A!B` e2 ( A` e1 e2 ) B

In the above two rules, we can see the function body is typed with the assumption x : A,
which implies x has synthesized type A. But the typing of application only checks the argument
by A. (Here we only consider the case when the �rst premise of rule T������ is a direct resultof rule T������). Therefore, the synthesized type of the argument may be smaller than A,
and the typing derivation may not be preserved after direct substitution when it contains
disjointness checking. For example, although (_x. x ,, 1 : Bool ! Bool & Int) (true ,, 2) iswell-typed, changing the argument annotation for the lambda function leads to the failure oftyping _x. x ,, 1 : Bool & Int ! Bool & Int.
To allow direct substitution in beta-reduction, we need to have hypotheses about checked
types rather than synthesized types. So the typing context now contains two di�erent forms
of assumptions. The old assumption is reformatted as x ) A. This new assumption x ( Astands for that a variable x has a checked type A, which matches with the checking premise inrule T������ precisely.
����T������I��

����T������C��

x)A2

x(A2

`x ) A

����T������2

A6B`x ( B,x ( A`e ( B` _x. e ( A ! B

We keep the property that for any expression, if it can be checked against type A, it can

149also be checked against any supertype of A. Previously in _8+ every well-typed expression has
a unique synthesized type. So having the subsumption rule is su�cient to guard this property.
But now it requires more care, like adding subtyping in rule ����T������C�� and an extra
introduction rule for intersection types because rule ����T������2 only deals with function
types.
����T������

����T��������`e ) A

A6B`e ( A` e ( A&B

`e ( B

9.1.3`e ( B

Lazy merges

In our call-by-name variant of F8+ , although the evaluation of function arguments is delayed,
subterms in merges are still reduced eagerly. For example, in((1 + 1) ,, (not true) ,, ‘c’) : Char õ! (2 ,, false ,, ‘c’) : Char õ! ‘c’
the integer part and the boolean part do not contribute to the �nal result, but they are computedfor the whole merge to reach a value form. For the three values in 2 ,, false ,, ‘c’, we can telltheir types directly and compare them with the cast type Char.
To obtain a truly lazy merge, we need to recognize the type of subterms without evaluation.
A direct solution is to stop evaluating merges when all the subterms in it are wrapped by atype annotation, like(1 + 1) : Int ,, (not true) : Bool ,, ‘c’ : Char
Recall the de�nition of pre-values in F8+ :u ::= i | > | e : A | u1 ,, u2Pre-values

As pre-values correspond to all the expressions that have a directly recognizable principal type,we can use u1 ,, u2 as the value form of merges.
The other possible design is to annotate the merge operator, which introduces more annotations, but could help speed up the casting process.
(1 + 1)Int ,,Bool & Char ((not true)Bool ,,Char ‘c’)Furthermore, we can separate the merging construct that stores all the expressions and thecorresponding type information which serves as an index.
((1 + 1) ,, (not true) ,, ‘c’) as Int & Bool & Char150

R���������
[Ahm06]

Amal Ahmed. “Step-indexed syntactic logical relations for recursive and quanti�ed
types”. In: European Symposium on Programming (ESOP). 2006.

[AOS17]

João Alpuim, Bruno C. d. S. Oliveira, and Zhiyuan Shi. “Disjoint Polymorphism”.
In: European Symposium on Programming (ESOP). 2017.

[Bak+00]

Ste�en van Bakel et al. The Minimal Relevant Logic and the Call-by-Value Lambda
Calculus. Tech. rep. TR-ARP-05-2000. The Australian National University, 2000.

[Bar84]

Henk Barendregt. “The lambda calculus - its syntax and semantics”. In: Studies inlogic and the foundations of mathematics. Vol. 103. 1984.

[BC90]

Gilad Bracha and William R. Cook. “Mixin-based inheritance”. In: Object-Oriented
Programming, Systems, Languages and Applications (OOPSLA). 1990. ���: 10.1145/
97945.97982.

[BCD83]

Henk Barendregt, Mario Coppo, and Mariangiola Dezani-Ciancaglini. “A Filter
Lambda Model and the Completeness of Type Assignment”. In: The Journal of
Symbolic Logic 48.4 (1983), pp. 931–940.

[BCP97]

Kim B Bruce, Luca Cardelli, and Benjamin C Pierce. “Comparing object encodings”.
In: International Symposium on Theoretical Aspects of Computer Software. Springer.
1997, pp. 415–438.

[BDD95]

Franco Barbanera, Mariangiola Dezani-Ciancaglini, and Ugo De’Liguoro. “Intersection and union types: syntax and semantics”. In: Information and Computation
119.2 (1995), pp. 202–230.

[Ber19]Birthe van den Berg. Type Inference for Disjoint Intersection Types. 2019.

[Bes+16]

Jan Bessai et al. “Extracting a formally veri�ed Subtyping Algorithm for Intersection Types from Ideals and Filters”. In: TYPES. 2016.

[Bi+19]Xuan Bi et al. “Distributive Disjoint Polymorphism for Compositional Programming”. In: European Symposium on Programming (ESOP). 2019.

151

[Bla17]

Lasse Blaauwbroek. “On the Interaction Between Unrestricted Union and Intersection Types and Computational E�ects”. MA thesis. Eindhoven University ofTechnology, 2017.

[BO18]

Xuan Bi and Bruno C. d. S. Oliveira. “Typed First-Class Traits”. In: European
Conference on Object-Oriented Programming (ECOOP). 2018.

[BOS18]

Xuan Bi, Bruno C. d. S. Oliveira, and Tom Schrijvers. “The Essence of Nested
Composition”. In: European Conference on Object-Oriented Programming (ECOOP).
2018.

[BRD19]Jan Bessai, Jakob Rehof, and Boris Düdder. “Fast veri�ed BCD subtyping”. In:
Models, Mindsets, Meta: The What, the How, and the Why Not? Vol. 11200. Lecture
Notes in Computer Science. Springer, Cham, 2019, pp. 356–371. ���: 10.1007/9783-030-22348-9_21.

[BW00]

Martin Büchi and Wolfgang Weck. “Generic wrappers”. In: European Conference
on Object-Oriented Programming (ECOOP). 2000.

[Car94]

Luca Cardelli. Extensible Records in a Pure Calculus of Subtyping. Theoretical
Aspects of Object-Oriented Programming: Types, Semantics, and Language Design.
Foundations of Computing Series. The MIT Press, Jan. 1994, pp. 373–425.

[Cas+14]

Giuseppe Castagna et al. “Polymorphic functions with set-theoretic types: part 1:
syntax, semantics, and evaluation”. In: Symposium on Principles of Programming
Languages (POPL). 2014. ���: 10.1145/2535838.2535840.

[Cas+15]

Giuseppe Castagna et al. “Polymorphic Functions with Set-Theoretic Types: Part
2: Local Type Inference and Type Reconstruction”. In: Symposium on Principles ofProgramming Languages (POPL). 2015. ���: 10.1145/2676726.2676991.

[CC99]

Craig Chambers and Weimin Chen. “E�cient Multiple and Predicated Dispatching”. In: Object-oriented Programming: Systems, Languages and Applications (OOPSLA). 1999. ���: 10.1145/320384.320407.

[CD78]

Mario Coppo and Mariangiola Dezani-Ciancaglini. “A new type assignment for_-terms”. In: Archiv für mathematische Logik und Grundlagenforschung 19.1 (1978),pp. 139–156.

[CD80]

Mario Coppo and Mariangiola Dezani-Ciancaglini. “An extension of the basic
functionality theory for the _-calculus”. In: Notre Dame Journal of Formal Logic
21.4 (1980), pp. 685–693. ���: 10.1305/ndjfl/1093883253.

[CDS79]

Mario Coppo, Mariangiola Dezani-Ciancaglini, and Patrick Sallé. “Functional
Characterization of Some Semantic Equalities inside Lambda-Calculus”. In: Proceedings of the 6th Colloquium, on Automata, Languages and Programming. Berlin,
Heidelberg: Springer-Verlag, 1979, pp. 133–146. ����: 3540095101.
152

[CDV80]

Mario Coppo, Mariangiola Dezani-Ciancaglini, and Betti Venneri. “Principal Type
Schemes and Lambda-calculus Semantics”. In: (1980), pp. 535–560.

[CDV81]

Mario Coppo, Mariangiola Dezani-Ciancaglini, and Betti Venneri. “Functional
Characters of Solvable Terms”. In: Math. Log. Q. 27.2-6 (1981), pp. 45–58. ���:10.1002/malq.19810270205.

[CF58]

Haskell Brooks Curry and Robert M. Feys. Combinatory Logic Vol. 1. Amsterdam,
Netherlands: North-Holland Publishing Company, 1958.

[CG03]

Adriana B. Compagnoni and Healfdene Goguen. “Typed operational semantics
for higher-order subtyping”. In: Inf. Comput. 184.2 (2003), pp. 242–297. ���: 10.
1016/S0890-5401(03)00062-2.

[CGL95]

Giuseppe Castagna, Giorgio Ghelli, and Giuseppe Longo. “A calculus for overloaded functions with subtyping”. In: Information and Computation 117.1 (1995),
pp. 115–135.

[Cha+05]

Manuel M. T. Chakravarty et al. “Associated types with class”. In: Symposiumon Principles of Programming Languages (POPL). 2005, pp. 1–13. ���: 10.1145/
1040305.1040306.

[Chl10]Adam Chlipala. “Ur: statically-typed metaprogramming with type-level record
computation”. In: ACM Sigplan Notices 45.6 (2010), pp. 122–133.

[CKJ05]

Manuel M. T. Chakravarty, Gabriele Keller, and Simon L. Peyton Jones. “Associatedtype synonyms”. In: International Conference on Functional Programming (ICFP).
2005. ���: 10.1145/1086365.1086397.

[Cli+00]

Curtis Clifton et al. “MultiJava: modular open classes and symmetric multiple
dispatch for Java”. In: Object-Oriented Programming Systems, Languages and Applications (OOPSLA). Ed. by Mary Beth Rosson and Doug Lea. 2000. ���: 10.1145/
353171.353181.

[CM91]

Luca Cardelli and John Mitchell. “Operations on Records”. In: Mathematical Structures in Computer Science 1 (1991), pp. 3–48.

[Coo89]William R. Cook. “A Denotational Semantics of Inheritance”. PhD thesis. Brown
University, 1989.

[Coq21]The Coq Development Team. The Coq Reference Manual, version 8.13.2. Available
electronically at https : / / coq . inria .fr / distrib / current / refman/. Apr.
2021.

[CP]

Arthur Charguéraud and François Pottier. TLC: a non-constructive library for Coq.
https://www.chargueraud.org/softs/tlc/.

153

[CW85]

Luca Cardelli and Peter Wegner. “On Understanding Types, Data Abstraction, andPolymorphism”. In: ACM Comput. Surv. 17.4 (1985), pp. 471–522. ���: 10.1145/
6041.6042.

[CX11]

Giuseppe Castagna and Zhiwu Xu. “Set-theoretic foundation of parametric polymorphism and subtyping”. In: International Conference on Functional Programming(ICFP). 2011. ���: 10.1145/2034773.2034788.

[DM17]

Stephen Dolan and Alan Mycroft. “Polymorphism, subtyping, and type inferencein MLsub”. In: Proceedings of the 44th ACM SIGPLAN Symposium on Principles ofProgramming Languages. 2017, pp. 60–72.

[DP00]

Rowan Davies and Frank Pfenning. “Intersection types and computational e�ects”.
In: International Conference on Functional Programming (ICFP). 2000.

[DP11]

Dominique Devriese and Frank Piessens. “On the bright side of type classes: instance arguments in Agda”. In: International Conference on Functional Programming(ICFP). 2011. ���: 10.1145/2034773.2034796.

[Dun14]

Jana Dun�eld. “Elaborating intersection and union types”. In: Journal of Functional
Programming 24.2-3 (2014), pp. 133–165. ���: 10.1017/S0956796813000270.

[EP00]

Martin Erwig and Simon Peyton Jones. “Pattern Guards and Transformational
Patterns”. In: Haskell Workshop 2000. Sept. 2000.

[FCB08]

Alain Frisch, Giuseppe Castagna, and Véronique Benzaken. “Semantic Subtyping:
Dealing Set-Theoretically with Function, Union, Intersection, and Negation Types”.
In: J. ACM 55.4 (Sept. 2008). ����: 0004-5411. ���: 10.1145/1391289.1391293.

[FKF98]Matthew Flatt, Shriram Krishnamurthi, and Matthias Felleisen. “Classes and Mixins”. In: Symposium on Principles of Programming Languages (POPL). 1998. ���:10.1145/268946.268961.

[FL09]

Yangyue Feng and Zhaohui Luo. “Typed Operational Semantics for Dependent
Record Types”. In: Proceedings Types for Proofs and Programs, Revised Selected
Papers, TYPES. EPTCS. 2009. ���: 10.4204/EPTCS.53.3.

[FM95]

Kathleen Fisher and John Mitchell. “A delegation-based object calculus with
subtyping”. In: Fundamentals of Computation Theory. 1995.

[Fri04]

Alain Frisch. “Théorie, conception et réalisation d’un langage de programmation
adapté à XML”. PhD thesis. PhD thesis, Université Paris 7, 2004.

[GGR95]

Paul Gochet, Pascal Gribomont, and Didier Rossetto. “ALGORITHMS FOR RELEVANT LOGIC: Leo Apostel in memoriam”. In: Logique et Analyse 38.150/152(1995), pp. 329–346. ����: 00245836, 22955836.

154

[Gir72]

Jean-Yves Girard. “Interprétation fonctionnelle et élimination des coupures del’arithmétique d’ordre supérieur”. PhD thesis. Université Paris 7, 1972.

[Gog94]

Healfdene Goguen. “A typed operational semantics for type theory”. PhD thesis.
University of Edinburgh, UK, 1994.

[Gog95]

Healfdene Goguen. “Typed Operational Semantics”. In: Typed Lambda Calculi
and Applications, Second International Conference on Typed Lambda Calculi andApplications, TLCA. 1995. ���: 10.1007/BFb0014053.

[Hal+96]

Cordelia V. Hall et al. “Type Classes in Haskell”. In: ACM Trans. Program. Lang.
Syst. 18.2 (1996), pp. 109–138. ���: 10.1145/227699.227700.

[HO20]

Xuejing Huang and Bruno C. d. S. Oliveira. “A Type-Directed Operational Semantics for a Calculus with a Merge Operator”. In: 34th European Conference on
Object-Oriented Programming, ECOOP. 2020.

[How80]William A. Howard. “The formulae-as-types notion of construction”. In: To H.B.
Curry: Essays on Combinatory Logic, _-calculus and Formalism. Ed. by J. Hindleyand J. Seldin. Academic Press, 1980, pp. 479–490.

[HP91]

Robert Harper and Benjamin Pierce. “A Record Calculus Based on SymmetricConcatenation”. In: Symposium on Principles of Programming Languages (POPL).
1991.

[Kae88]

Stefan Kaes. “Parametric Overloading in Polymorphic Programming Languages”.
In: European Symposium on Programming (ESOP). Ed. by Harald Ganzinger. 1988.
���: 10.1007/3-540-19027-9\_9.

[Kni99]Günter Kniesel. “Type-safe delegation for run-time component adaptation”. In:
European Conference on Object-Oriented Programming (ECOOP). 1999.

[Knu71]

Donald E Knuth. “Examples of formal semantics”. In: Symposium on Semantics ofAlgorithmic Languages. Vol. 188. LNM. Springer. 1971.

[KT95]

Toshihiko Kurata and Masako Takahashi. “Decidable Properties of Intersection
Type Systems”. In: Proceedings of the Second International Conference on Typed
Lambda Calculi and Applications. TLCA ’95. Berlin, Heidelberg: Springer-Verlag,
1995, pp. 297–311. ����: 354059048X.

[Lau12]

Olivier Laurent. “Intersection types with subtyping by means of cut elimination”.
In: Fundamenta Informaticae 121.1-4 (2012), pp. 203–226.

[Lau19]Olivier Laurent. “Intersection Subtyping with Constructors”. In: Proceedings Twelfth
Workshop on Developments in Computational Models and Ninth Workshop on Intersection Types and Related Systems (DCM 2018 and ITRS 2018). Ed. by Michele
Pagani and Sandra Alves. Vol. 293. Electronic Proceedings in Theoretical Computer
Science. Apr. 2019, pp. 73–84.
155

[LHJ95]

Sheng Liang, Paul Hudak, and Mark Jones. “Monad transformers and modular
interpreters”. In: Proceedings of the 22nd ACM SIGPLAN-SIGACT symposium on
principles of programming languages. 1995, pp. 333–343.

[Lie86]

Henry Lieberman. “Using Prototypical Objects to Implement Shared Behavior in
Object Oriented Systems”. In: Object-Oriented Programming Systems, Languages,
and Applications (OOPSLA). 1986.

[Luo99]Zhaohui Luo. “Coercive Subtyping”. In: J. Log. Comput. 9.1 (1999), pp. 105–130.
���: 10.1093/logcom/9.1.105.

[Mil78]Robin Milner. “A Theory of Type Polymorphism in Programming”. In: Journalof Computer and System Sciences 17.3 (1978), pp. 348–375. ���: 10.1016/00220000(78)90014-4.

[MT18]

Fabian Muehlboeck and Ross Tate. “Empowering union and intersection types
with integrated subtyping”. In: Object-oriented Programming, Systems, Languages,
and Applications (OOPSLA). 2018.

[Mus+08]

Radu Muschevici et al. “Multiple dispatch in practice”. In: Object-oriented Programming, Systems, Languages, and Applications (OOPSLA). Ed. by Gail E. Harris. ACM,
2008, pp. 563–582. ���: 10.1145/1449764.1449808.

[OCR20]

Bruno C. d. S. Oliveira, Shaobo Cui, and Baber Rehman. “The Duality of Subtyping”.
In: European Conference on Object-Oriented Programming (ECOOP). 2020. ���:10.4230/LIPIcs.ECOOP.2020.29.

[Ode+04]

Martin Odersky et al. An overview of the Scala programming language. Tech. rep.
École Polytechnique Fédérale de Lausanne, 2004.

[OMO10]

Bruno C. d. S. Oliveira, Adriaan Moors, and Martin Odersky. “Type classes asobjects and implicits”. In: Object-Oriented Programming Systems, Languages, andApplications (OOPSLA). 2010. ���: 10.1145/1869459.1869489.

[OSA16]

Bruno C. d. S. Oliveira, Zhiyuan Shi, and João Alpuim. “Disjoint intersection
types”. In: International Conference on Functional Programming (ICFP). 2016. ���:10.1145/2951913.2951945.

[Ost02]Klaus Ostermann. “Dynamically composable collaborations with delegation layers”. In: European Conference on Object-Oriented Programming (ECOOP). 2002.

[OWW95] Martin Odersky, Philip Wadler, and Martin Wehr. “A Second Look at Overloading”.
In: Proceedings of the seventh international conference on Functional programming
languages and computer architecture, FPCA 1995. ACM, 1995, pp. 135–146. ���:10.1145/224164.224195.
[Par+19]

Gyunghee Park et al. “Polymorphic Symmetric Multiple Dispatch with Variance”.
In: Proc. ACM Program. Lang. 3.POPL (Jan. 2019). ���: 10.1145/3290324.
156

[Par20]

Lionel Parreaux. “The simple essence of algebraic subtyping: principal type inference with subtyping made easy (functional pearl)”. In: Proceedings of the ACM on
Programming Languages 4.ICFP (2020), pp. 1–28.

[Pea13]David J. Pearce. “Sound and Complete Flow Typing with Unions, Intersections and
Negations”. In: Veri�cation, Model Checking, and Abstract Interpretation. Ed. byRoberto Giacobazzi, Josh Berdine, and Isabella Mastroeni. 2013. ����: 978-3-64235873-9.

[Pie02]

Benjamin C. Pierce. Types and programming languages. MIT Press, 2002. ����:978-0-262-16209-8.

[Pie89]Benjamin C. Pierce. A decision procedure for the subtype relation on intersection types
with bounded variables. Tech. rep. School of Computer Science, Carnegie-Mellon
University, Sept. 1989.

[Pie91]

Benjamin C. Pierce. “Programming with Intersection Types and Bounded Polymorphism”. PhD thesis. Carnegie Mellon University, Dec. 1991.

[Plo73]

Gordon Plotkin. Lambda-de�nability and logical relations. Edinburgh University,
1973.

[Pol97]

Erik Poll. “System F with width-subtyping and record updating”. In: International
Symposium on Theoretical Aspects of Computer Software. 1997, pp. 439–457.

[Pot00]François Pottier. “A 3-part type inference engine”. In: European Symposium on
Programming. Springer. 2000, pp. 320–335.

[Pot80]Garrel Pottinger. “A type assignment for the strongly normalizable _-terms”. In:(1980). Ed. by J. Hindley and J. Seldin, pp. 561–577.

[PS97]

Benjamin Pierce and Martin Ste�en. “Higher-order subtyping”. In: TheoreticalComputer Science 176.1 (1997), pp. 235–282.

[PT98]

Benjamin C. Pierce and David N. Turner. “Local Type Inference”. In: Proceedings of
ACM Symposium on Principles of Programming Languages. Jan. 1998, pp. 252–265.

[PZ04]

Jens Palsberg and Tian Zhao. “Type inference for record concatenation and subtyping”. In: Information and Computation 189.1 (2004), pp. 54–86. ���: https://doi.org/10.1016/j.ic.2003.10.001.

[Rém89]

Didier Rémy. “Type checking records and variants in a natural extension of ML”.
In: Proceedings of the 16th ACM SIGPLAN-SIGACT symposium on Principles ofprogramming languages. 1989, pp. 77–88.

[Rém95]

Didier Rémy. “A case study of typechecking with constrained types: Typing record
concatenation”. Presented at the workshop on Advances in types for computerscience at the Newton Institute, Cambridge, UK. 1995.
157

[Rey74]

John C Reynolds. “Towards a theory of type structure”. In: Programming Symposium. Springer. 1974, pp. 408–425.

[Rey88]John C Reynolds. Preliminary design of the programming language Forsythe. Tech.
rep. CMU-CS-88-159. Carnegie Mellon University, 1988.

[Rey91]

John C. Reynolds. “The Coherence of Languages with Intersection Types”. In:
Theoretical Aspects of Computer Software, International Conference TACS. 1991. ���:10.1007/3-540-54415-1\_70.

[Rey97]

John C Reynolds. “Design of the Programming Language Forsythe”. In: ALGOL-likelanguages. Springer, 1997, pp. 173–233.

[RM72]

Richard Routley and Robert K. Meyer. “The Semantics of Entailment: III”. In:
Journal of Philosophical Logic 1.2 (1972), pp. 192–208.

[RU11]Jakob Rehof and Paweł Urzyczyn. “Finite combinatory logic with intersection
types”. In: International Conference on Typed Lambda Calculi and Applications.
2011.

[SBD11]

Ina Schaefer, Lorenzo Bettini, and Ferruccio Damiani. “Compositional TypeChecking for Delta-oriented Programming”. In: Proceedings of the tenth international conference on Aspect-oriented software development, AOSD ’11. 2011.

[Sch+03]

Nathanael Schärli et al. “Traits: Composable units of behaviour”. In: European
Conference on Object-Oriented Programming (ECOOP). 2003.

[SDO22]

Yaozhu Sun, Utkarsh Dhandhania, and Bruno C. d. S. Oliveira. “Compositional
Embeddings of Domain-Speci�c Languages”. In: Object-oriented Programming,
Systems, Languages, and Applications (OOPSLA). 2022.

[Sew+07]

Peter Sewell et al. “Ott: E�ective Tool Support for the Working Semanticist”. In:
SIGPLAN Not. 42.9 (Oct. 2007), pp. 1–12. ����: 0362-1340. ���: 10.1145/1291220.
1291155.

[Sie19]Jeremy G. Siek. “Transitivity of Subtyping for Intersection Types”. In: CoRR abs /1906.09709 (2019). arXiv: 1906.09709.

[SO11]Tom Schrijvers and Bruno C. d. S. Oliveira. “Monads, zippers and views: virtualizing the monad stack”. In: Proceedings of the 16th ACM SIGPLAN international
conference on functional programming. 2011, pp. 32–44.

[ST06]

Jeremy G. Siek and Walid Taha. “Gradual typing for functional languages”. In:
Scheme and Functional Programming Workshop. 2006.

[ST07]

Jeremy G. Siek and Walid Taha. “Gradual Typing for Objects”. In: European Conference on Object-Oriented Programming (ECOOP). 2007.

158

[Sta15]

Rick Statman. “A Finite Model Property for Intersection Types”. In: Electronic
Proceedings in Theoretical Computer Science 177 (2015), pp. 1–9.

[Sta85]

Richard Statman. “Logical relations and the typed _-calculus”. In: Information andControl 65.2-3 (1985), pp. 85–97. ���: 10.1016/S0019-9958(85)80001-2.

[Sto19]Claude Stolze. “Combining union, intersection and dependent types in an explicitly
typed lambda-calculus”. PhD thesis. Université Côte d’Azur, 2019.

[SW10]

Jeremy G. Siek and Philip Wadler. “Threesomes, with and without blame”. In:
Proceedings of the 37th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, POPL 2010, Madrid, Spain, January 17-23, 2010. Ed. by Manuel V.
Hermenegildo and Jens Palsberg. ACM, 2010, pp. 365–376. ���: 10.1145/1706299.
1706342.

[Tai67]

William W. Tait. “Intensional Interpretations of Functionals of Finite Type I”. In: J.
Symb. Log. 32.2 (1967), pp. 198–212. ���: 10.2307/2271658.

[US88]David Ungar and Randall B Smith. “SELF: the power of simplicity (object-oriented
language)”. In: Thirty-Third IEEE Computer Society International Conference, Digest
of Papers. 1988.

[Vig00]

Luca Viganò. “An O(n log n)-Space Decision Procedure for the Relevance Logic
B+”. In: Studia Logica: An International Journal for Symbolic Logic 66.3 (2000),
pp. 385–407. ����: 00393215, 15728730.

[Wad98]

Philip Wadler. “The Expression Problem”. In: Posted on the Java Genericity mailinglist (1998).

[Wan+18]

Yanlin Wang et al. “FHJ: A Formal Model for Hierarchical Dispatching and Overriding”. In: 32nd European Conference on Object-Oriented Programming, ECOOP 2018,
July 16-21, 2018, Amsterdam, The Netherlands. Ed. by Todd D. Millstein. Vol. 109.
LIPIcs. 2018.

[Wan89]Mitchell Wand. “Type inference for record concatenation and multiple inheritance”.
In: Proceedings. Fourth Annual Symposium on Logic in Computer Science. 1989,
pp. 92–97. ���: 10.1109/LICS.1989.39162.

[WB89]

Philip Wadler and Stephen Blott. “How to Make ad-hoc Polymorphism Less adhoc”. In: Conference Record of the Sixteenth Annual ACM Symposium on Principles
of Programming Languages, Austin, Texas, USA, January 11-13, 1989. ACM Press,
1989, pp. 60–76. ���: 10.1145/75277.75283.

[WBY14]

Leo White, Frédéric Bour, and Jeremy Yallop. “Modular implicits”. In: Proceedings
ML Family/OCaml Users and Developers workshops, ML/OCaml 2014, Gothenburg,
Sweden, September 4-5, 2014. Ed. by Oleg Kiselyov and Jacques Garrigue. Vol. 198.
EPTCS. 2014, pp. 22–63. ���: 10.4204/EPTCS.198.2.
159

[WF09]

Philip Wadler and Robert Bruce Findler. “Well-Typed Programs Can’t Be Blamed”.
In: Programming Languages and Systems, 18th European Symposium on Programming, ESOP 2009, York, UK, March 22-29, 2009. Proceedings. Ed. by Giuseppe
Castagna. Vol. 5502. Lecture Notes in Computer Science. Springer, 2009, pp. 1–16.
���: 10.1007/978-3-642-00590-9\_1.

[XHO23]

Han Xu, Xuejing Huang, and Bruno C. d. S. Oliveira. “Making a Type Di�erence:
Subtraction on Intersection Types as Generalized Record Operations”. In: Symposium on Principles of Programming Languages (POPL). 2023. ���: 10 . 1145 /
3571224.

[Xie+20]

Ningning Xie et al. “Row and Bounded Polymorphism via Disjoint Polymorphism”.
In: European Conference on Object-Oriented Programming (ECOOP). 2020.

[ZSO21]

Weixin Zhang, Yaozhu Sun, and Bruno C. d. S. Oliveira. “Compositional Programming”. In: ACM Transactions on Programming Languages and Systems (TOPLAS)
43.3 (2021), pp. 1–61.

[Zwa95]Jan Zwanenburg. Record Concatenation with Intersection Types. Tech. rep. 95/34.
Eindhoven University of Technology, 1995.

[Zwa97]Jan Zwanenburg. A Type System for Record Concatenation and Subtyping. Tech. rep.
Eindhoven University of Technology, July 1997.

160