HAL Id: hal-03007256
https://hal.inria.fr/hal-03007256
Submitted on 16 Nov 2020
HAL is a multi-disciplinary open access archive for the deposit and dissemination of sci- entific research documents, whether they are pub- lished or not. The documents may come from teaching and research institutions in France or abroad, or from public or private research centers.
L’archive ouverte pluridisciplinaire HAL, est destinée au dépôt et à la diffusion de documents scientifiques de niveau recherche, publiés ou non, émanant des établissements d’enseignement et de recherche français ou étrangers, des laboratoires publics ou privés.
Extrinsically Typed Operational Semantics for Functional Languages
Matteo Cimini, Dale Miller, Jeremy Siek
To cite this version:
Matteo Cimini, Dale Miller, Jeremy Siek. Extrinsically Typed Operational Semantics for Functional
Languages. SLE 2020 - 13th ACM SIGPLAN/International Conference on Software Language Engi-
neering, Nov 2020, Virtual, United States. �hal-03007256�
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
Extrinsically Typed Operational Semantics for Functional Languages
Matteo Cimini
University of Massachusetts Lowell USA
Dale Miller
Inria & LIX, École Polytechnique France
Jeremy G. Siek
Indiana University USA [email protected]
Abstract
We present a type system over language definitions that classifies parts of the operational semantics of a language in input, and models a common language design organization.
The resulting typing discipline guarantees that the language at hand is automatically type sound.
Thanks to the use of types to model language design, our type checker has a high-level view on the language being analyzed and can report messages using the same jargon of language designers.
We have implemented our type system in the lang-n-check tool, and we have applied it to derive the type soundness of several functional languages, including those with recursive types, polymorphism, exceptions, lists, sums, and several common types and operators.
CCS Concepts:•Software and its engineering→Formal language definitions; • Theory of computation→ Type theory.
Keywords:Extrinsic type systems, type soundness, func- tional languages
ACM Reference Format:
Matteo Cimini, Dale Miller, and Jeremy G. Siek. 2020. Extrinsically Typed Operational Semantics for Functional Languages. InProceed- ings of the 13th ACM SIGPLAN International Conference on Software Language Engineering (SLE ’20), November 16–17, 2020, Virtual, USA.
ACM, New York, NY, USA, Article 1,18pages.
1 Introduction
Type systems play a major role inprogram analysis. Can they play a similar role inlanguage analysis, i.e. the analysis of the meta-theoretic properties of programming languages?
The research line on intrinsic typing has long investigated this question, and has demonstrated that type systems can be an effective tool for the analysis of languages. In this ap- proach, a language is implemented within a host type theory with strong meta-theoretic properties [Church 1940;Harper and Stone 2000;Poulsen et al. 2018;Rouvoet et al. 2020]. If the implementation type checks then the language is type sound. For example, if we can make a language definition
SLE’20, November, 2020, Online 2020.
type check within a type theory with exhaustive pattern- matching that is strongly normalizing then the progress theorem automatically holds.
In this paper, we take a different perspective in the type checking of languages for their soundness: we intend to use types and type systems in the same way they are used in program analysis [Cardelli 2004;Pierce 2002], i.e., to model a high-level organization and discipline to ensure that some property holds. The most common way to perform type checking is with an external function that analyzes programs, that is, anextrinsictype system. Our goal is to present an extrinsic type system that accepts or rejects a programming language definition (syntax, type system, operational seman- tics) and guarantees that accepted languages are type sound.
A Meta Type System for Type Soundness.To avoid nam- ing confusion, we use the termmeta type systemfor a type system that analyzes a language definition rather than a program1. Our main contribution is a meta type system that ensures that the various parts of a language definition (value declarations, typing rules, reduction rules, evaluation contexts, and so on) are all in order so that type sound- ness automatically holds. Our meta type system models a high-level organization and discipline that are not novel.
Conversely, they capture invariants that language designers have been using for a long time, and makes them explicit and formally defined. For example, our meta type system traverses the grammar and typing rules of the language at hand in order to apply the common classification of oper- ators asintroduction forms(such as𝜆𝑥 :𝑇 .𝑒 in the simply typed𝜆-calculus (STLC)),elimination forms(such as appli- cation),derived operators(such asletandletrec),errors anderror handlers(such astry). This classification paves the way for a high-level analysis of a language definition. For example, our meta type system can check the𝛽-rule of STLC (𝜆𝑥 :𝑇 .𝑒) 𝑣 −→𝑒[𝑣/𝑥]in the following way. (Below, the Classificationmeta-variable contains information about the role of operators and characterizes values. The application operator is named asapp,funTypeis the function type, and
1The wordextrinsiccan be confusing when we dive in the technical part of the paper, as our meta type system needs to analyze a type system which is itself extrinsic. We therefore saymeta type system.
1
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
Section3.2presents complete details.) Classification⊢app:elimfunType Classification⊢ (𝜆𝑥:𝑇 . 𝑒):valuefunType
Contexts⊢app:{1,2}
Contexts
|Classification ⊢ (app (𝜆𝑥 :𝑇 . 𝑒) 𝑣) −→ 𝑒[𝑣/𝑥] This is a meta-level typing rule that type checks a reduction rule. Here, the first line of premises says that the type of the operatorappis “elimfunType”, which means that the application is an elimination form of the function type, previ- ously classified as such inClassificationby other parts of the meta type system. It then requires that the argument being eliminated, which is highlighted and is sometimes called the principal argument[Harper 2012], be a value of the function type, which we check by making sure that the abstraction is of type “valuefunType”. This materializes a common de- sign in programming languages in whichelimination forms manipulate values of some data type. As exemplified above, it is typical to apply this approach by assigning a principal argument to an elimination form of a type and then by defin- ing its reduction rules by case analysis on the values of that type.
The meta-level typing rule above also checks that the arguments at positions1and2must be evaluation contexts for the application, as those arguments need to be evaluated for the𝛽-rule to apply.Contexts⊢app:{1,2}enforces that the definition of evaluation contexts for application have𝐸 in both the first and second sub-expression positions, as in the grammar:𝐸::=(app𝐸 𝑒) | (app𝑣 𝐸) | · · ·.
Analogously, if the language at hand had lists and the reduction rulehead (cons𝑣1𝑣2) −→ 𝑣1, our meta type system would use an instance of the rule above and detect thatheadis an elimination form for lists. It would then check that(cons𝑣1𝑣2)is a value for lists, and that the evaluation contexts are defined appropriately.
Our full meta type system captures design principles that are based on the above as well as other common language design invariants. It applies to functional languages with a typing relation of the form Γ ⊢ 𝑒 : 𝑇 and a reduction relation of the form𝑒−→𝑒based on small-step semantics and evaluation contexts. Ultimately, we have proved that languages that conform to our meta type system are type sound.
Implementation: lang-n-check.We have implemented our meta type system in the lang-n-check tool [Cimini 2015]. The tool works with language definitions such as that in Figure1, which contains the operational semantics of Sys- tem𝐹[Girard 1972;Reynolds 1974] with booleans. Language definitions use a domain-specific language that is close to pen&paper definitions in textbooks [Harper 2012;Pierce 2002] and research papers. The reason for this is that we wish to use the tool in courses on programming languages.
1 E x p r e s s i o n E ::= x | ( abs T ( x ) E ) | ( absT ( X ) E ) | ( app E E )
2 | ( appT E T ) | ( tt ) | ( ff ) | ( if E E E )
3 Type T ::= ( bool ) | ( arr ow T T ) | ( all ( X ) T ) 4 Va lue V ::= ( abs T ( x ) E ) | ( absT ( X ) E ) | ( tt ) | ( ff ) 5 Er ror ::=
6 C o n t e x t C ::= [] | ( app C e ) | ( app v C ) | ( appT C T )
7 | ( if C e e )
8
9 Ga mma | - ( abs T1 E ) : ( a rro w T1 T2 ) <==
10 Gamma , x : T1 | - E : T2 .
11 Ga mma | - ( absT E ) : ( all T ) <== Gamma , X | - E : T . 12 Ga mma | - ( app E1 E2 ) : T2 <== G amm a | - E1 : ( a rro w T1 T2 )
13 /\ Gam ma | - E2 : T1 .
14 Ga mma | - ( appT E T1 ) : T2 [ T1 / X ] <== G amm a | - E : ( all T2 ) . 15 Ga mma | - ( tt ) : ( bool ) .
16 Ga mma | - ( ff ) : ( bool ) .
17 Ga mma | - ( if E1 E2 E3 ) : T <== G amm a | - E1 : ( bool )
18 /\ Gam ma | - E2 : T
19 /\ Gam ma | - E3 : T .
20
21 ( app ( abs T E ) V ) -- > E [ V / x ].
22 ( appT ( absT E ) T ) -- > E [ T / X ].
23 ( if ( tt ) E1 E2 ) -- > E1 . 24 ( if ( ff ) E1 E2 ) -- > E2 .
Figure 1.Example input of lang-n-check: language defini- tion of System𝐹with booleans. We do not mention binding variable in lines such as 21 and 22 becausexis the bound expression variable by default in the tool, andXis the type variable by default.
Language definitions that type check are type sound.What happens if our meta type system fails?One of the differences between our approach and intrinsic typing is that since we directly model language design with types then the meta type checker has a high-level view on the language being analyzed and can report messages using the same jargon of language designers. For example, if we forgot the context (if C e e) at line 7, lang-n-check would reject the specification with the error message“The principal argument of the elimination form ifis not declared as evaluation context, hence some programs may get stuck”. We are not aware of intrinsic type systems for languages whose type error messages refer to terms such as “principal argument” and “elimination form”.
We have applied lang-n-check to a plethora of func- tional languages and checked their type soundness, including the simply typed𝜆-calculus and its variants with integers, booleans, pairs, lists, sums, tuples,fix,let,letrec, unit, universal types, recursive types, option types, exceptions, list operations such as append, map, mapi (also depends on the position in the list of the current element being processed), filter, filteri, range, list length, reverse, and the recursor of nat- ural numbers (natrec). We have also considered different eval- uation strategies for the features mentioned above: call-by- value, call-by-name and a parallel reduction strategy (both function and argument can evaluate non-deterministically), as well as lazy pairs, lazy lists, and lazy tuples, and both left- to-right and right-to-left evaluations. lang-n-check com- piles the languages that type check successfully into the Abella theorem prover [Baelde et al. 2014] and automatically generates their machine-checked proof of type soundness.
2
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
This gives us high confidence that, besides the theoretical guarantees of our paper, also our implementation is reliable.
Closely Related Work.Cimini reports that lang-n-check has been used to teach programming languages theory [Ci- mini 2019]. We would like to clearly distinguish that work from this paper. That work briefly (and incompletely) de- scribes the capabilities of lang-n-check2, makes the point that error messages are informative, sets forth the thesis that a tool such as lang-n-check can be beneficial in a teach- ing context, and describes the studies that have been made, and that are to be made in the future. This paper, instead, provides a formal meta type system, gives a complete de- scription of the organization principles that guide the meta type system, provides a proof of correctness, and reports on the many languages that have been checked as type sound using lang-n-check.
Intrinsic vs Extrinsic Typing? So Far, Intrinsic Wins.
We have described the difference between intrinsic and ex- trinsic typing above, and also pointed out the benefits of the latter. Where does extrinsic typing of languages stand as compared to intrinsic typing?
A recent result by Poulsen et al has demonstrated that intrinsic typing can be applied to practical languages, and in particular to a large subset of Middleweight Java [Poulsen et al. 2018]. Our work is limited to the functional realm, and we acknowledge that the state of the art of intrinsic typing is substantially ahead.
The research line of intrinsic typing can be seen as oc- curring in two stages.Stage 1laid down the idea and the practice of intrinsic typing.Stage 2demonstrated that in- trinsic typing can scale, as was recently shown by Poulsen et al2018.
Research in extrinsic typing of languages may need to follow a similar path. We believe that the research in this paper helps to establishStage 1. It has been challenging to reachStage 2for intrinsic typing: we leave scaling up our approach for future work.
Summary of our Contributions.This paper makes the following contributions.
1. We devise a new approach to language analysis based on extrinsic typing of operational semantics. Our meta type system models a common high-level organization and discipline on language definitions that guarantee their type soundness (Section3).
2. We prove that language definitions accepted by our meta type system are type sound (Section4). In some sense, this result proves that the invariants that lan- guage designers have been using for years are correct at some general scale.
2That paper refers to a tool with another name because lang-n-check is used within a larger tool.
3. We implement the meta type system in lang-n-check (Section5). We have applied the tool to derive the type soundness of several functional languages, including those with recursive types, polymorphism, exceptions, lists, sums, and several common types and operators.
2 Language Definitions
We briefly review how languages are defined in small-step operational semantics. This section serves to fix the termi- nology that we use in the rest of the paper.
Figure2shows the definition of𝐹exc, which essentially is System F extended with exceptions. The language defines a series of syntactic categories defined by a BNF grammar. The syntactic categoriesTypeandExpressiondefine the types and the expressions of the language. Next, language design- ers decide which expressions constitutevalues. These are the results of successful computations. Values are defined with the syntactic categoryValue. Similarly, language designers designate which expression constitute theerror, which is the outcome when computations fail. The error is defined with the syntactic categoryError.Contextdefines theevaluation contexts, which prescribe within what contexts reduction can take place. Similarly,Error Contextdefines theerror contexts, which are those contexts in which we are allowed to detect that an error has occurred. (They typically differ from evalu- ation contexts when the language includes error handlers.)
Next,𝐹excdefines its type system with a relation of the formΓ ⊢𝑒 :𝑇, which is inductively defined with a set of inference rules. The dynamic semantics here is of the form 𝑒 −→𝑒and is also inductively defined by a set of inference rules called reduction rules.
In the setting of small-step operational semantics and languages with errors, the following is the statement of type soundness. (−→∗is the reflexive and transitive closure of
−→).
Definition 2.1 (Type Soundness). A languageL is type sound whenever for all expressions𝑒,𝑒′, and types𝑇, if
∅ ⊢𝑒:𝑇 and𝑒−→∗𝑒′then either
• 𝑒′is a value such that∅ ⊢𝑒′:𝑇,
• 𝑒′is an error, or
• there exists𝑒′′such that𝑒′−→𝑒′′and∅ ⊢𝑒′′:𝑇.
3 A Meta Type System for Type Soundness
We work with a formal representation for language defini- tions. We define alanguage definitionLas an 8-tuple
(Type,Expression,Value,Error,Context,Error Context, Type System,Dynamic Semantics).
3
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
Type 𝑇 ::= ⊤ | 𝑇 →𝑇 | ∀𝑋 .𝑇
Expression 𝑒 ::= 𝑥 |𝜆𝑥:𝑇 .𝑒|𝑒 𝑒 |Λ𝑋 .𝑒 |𝑒 [𝑇]
|raise𝑒 |try𝑒 with𝑒 Value 𝑣 ::= 𝜆𝑥:𝑇 .𝑒|Λ𝑋 .𝑒
Error er ::= raise𝑣
Context 𝐸 ::= 𝐸 𝑒 |𝑣 𝐸|𝐸 [𝑇] |raise𝐸|try𝐸with𝑒 Error Ctx 𝐹 ::= 𝐹 𝑒 |𝑣 𝐹 |𝐹 [𝑇] |raise𝐹
Type System Γ⊢𝑒:𝑇
(t-var) Γ, 𝑥:𝑇 ⊢𝑥 :𝑇
(t-abs)
Γ, 𝑥:𝑇1⊢𝑒:𝑇2 Γ⊢𝜆𝑥:𝑇 .𝑒:𝑇1→𝑇2
(t-app)
Γ⊢𝑒1:𝑇1→𝑇2 Γ⊢𝑒2:𝑇1 Γ⊢𝑒1𝑒2:𝑇2 (t-tabs)
Γ, 𝑋⊢ 𝑒:𝑇 Γ⊢ Λ𝑋 .𝑒:∀𝑋 .𝑇
(t-tapp)
Γ⊢ 𝑒 :∀𝑋 .𝑇2 Γ⊢ (𝑒[𝑇1]):𝑇2[𝑇1/𝑋]
(t-raise) Γ⊢𝑒:⊤ Γ⊢raise𝑒:𝑇 (t-try)
Γ⊢𝑒1:𝑇 Γ⊢𝑒2:⊤ →𝑇 Γ⊢ try𝑒1with𝑒2:𝑇
Dynamic Semantics 𝑒−→𝑒
(𝜆𝑥:𝑇 .𝑒)𝑣 −→𝑒[𝑣/𝑥] (beta) Λ𝑋 .𝑒 [𝑇] −→𝑒[𝑇/𝑋] (r-tappt) try𝑣with𝑒 −→𝑣 (r-try-success) try(raise𝑣)with𝑒 −→ (𝑒 𝑣) (r-try-raise) 𝑒−→𝑒′
𝐸[𝑒] −→𝐸[𝑒′] (ctx) 𝐹[er] −→er (err-ctx) Figure 2.Type system and dynamic semantics of𝐹exc.
where we place the components of Fig2in the tupleL. To make an example,𝐹excis represented as
(Types=𝑇 ::=⊤ | 𝑇 →𝑇 | ∀𝑋 .𝑇 ,
Expression=𝑒::=𝑥 |𝜆𝑥:𝑇 .𝑒|𝑒 𝑒|Λ𝑋 .𝑒 |𝑒 [𝑇]
|raise𝑒|try𝑒with𝑒, Value=𝑣::=𝜆𝑥:𝑇 .𝑒|Λ𝑋 .𝑒,
Error=er ::=raise𝑣 ,
Context=𝐸::=𝐸 𝑒 |𝑣 𝐸|𝐸[𝑇] |raise𝐸|try𝐸with𝑒, Error Context=𝐹 ::=𝐹 𝑒 |𝑣 𝐹 |𝐹 [𝑇] |raise𝐹 ,
Type System={(t-var),(t-abs),(t-app),(t-tabs),(t-tapp), (t-raise),(t-try)},
Dynamic Semantics={(beta),(r-tapp),(r-try-success), (r-try-raise),(r-ctx),(r-errCtx)}) where we simply wrote the name of rules, although the tuple contains the actual inference rules.
In this section we define a meta type system with judgment
⊢ Lthat makes sure that soundness automatically holds.
Our setting must accommodate syntax with some gen- erality. Therefore, we assume that operators are defined in abstract syntax rather than concrete syntax. For example, we haveif𝑒 𝑒 𝑒 rather thanif𝑒then𝑒else𝑒. We use𝑥s as variables for expressions and (capitalized)𝑋s for types.
Without loss of generality, we assume that the type annota- tions of an operator all appear first, followed by types with a bound𝑋, followed by expressions with a bound𝑥, followed by expressions with a bound𝑋, and finally followed by (not bound) expression arguments. This leads to a general shape that is similar to Harper’s abstract binding trees [Harper 2012] and is𝑜 𝑝 𝑇 (𝑋).𝑇 (𝑥).𝑒 (𝑋).𝑒 𝑒, where𝑜 𝑝 is an operator, and · denotes sequences. To make an example, abstraction fits that general shape as(abs𝑇 (𝑥).𝑒)and a type-annotatedconsfits that shape as(cons𝑇 𝑒 𝑒).
Our meta type system is an inference system that type checks parts of languages, including inference rules. To avoid confusion, we write the parts of the language being type checked inbluecolor. To help our presentation, we some times make examples with operators that are not in𝐹exc.
Figure3contains the main judgement for⊢ L, handled by rule [main]. This rule simply checks all the components of the language in the way described in the following sections.
3.1 Meta Type Systems for the Syntactic Categories The meta type system for type checking the syntactic cate- gories are in Figure3, as well. The language design invariants that are at play at this point are:
• Val:Any argument that is required to be evaluated to a value for a definition to apply must be declared as evaluation context. For example,Valenforces that if (cons𝑣 𝑣)is declared as value thenContextmust con- tain productions of the form(cons𝐸_)and(cons_𝐸), where _ can be𝑒or𝑣in both occurrences. Indeed, if one of these were missing, say the first, the expres- sion(cons ( (𝜆𝑥 .𝑥) nil) nil)would be stuck. This expression is not a value and does not take any step.
Type soundness would then be jeopardized.
• Ctx:Evaluation contexts have no circular dependencies w.r.t. the evaluation of their arguments.For example, we must forbid context declarations such as(cons𝐸 𝑣) and(cons𝑣 𝐸). Such declarations make the expres- sion(cons( (𝜆𝑥 .𝑥)nil) ( (𝜆𝑥 .𝑥)nil))stuck because the first argument does not start evaluating until the second is a value, while the second waits for the first to become a value, which won’t start evaluating.
• ErrCtx:Error contexts are evaluation contexts minus the error handler at the principal argument (where the error is expected to appear to be handled). This says that the contexttry𝐹 with𝑒should not be an error context. Indeed, (err-ctx) should not apply to derive the reductiontry(raise𝑣)with𝑒−→raise𝑣, as we expect the semantics oftryto handle the error.
Type CheckingType. The judgement⊢ Typein Fig. 3 checks some restrictions on the grammar for types. In par- ticular, we allow types to be a constant𝑐applied to𝑇s, or applied to𝑇s with bound variables𝑋s (for types quantified by types). On one hand, this accommodates universal types
4
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
and recursive types but also prevents expressions from being used in types, ruling out dependent types and refinement types. These latter features are rather advanced and we leave them for future work.
Type CheckingExpression. We use𝑒𝑥 𝑝−to denote an ex- pression derived by the grammar forExpression. The judge- ment⊢Expressionchecks that each grammar production is of the form𝑜 𝑝 𝑇 (𝑋).𝑇 (𝑥).𝑒 (𝑋).𝑒 𝑒, which we have dis- cussed previously. Notice that no other syntactic categories are allowed so far. This means that we rule out layered gram- mars such as expressions vs statements, which we plan to address in the future.
Type CheckingValue.The judgementContext⊢ Value checks the value declarations. We refer to𝑒𝑥 𝑝for𝑒𝑥 𝑝−in which we can use𝑣. There are two aspects that are checked for values. The first is that they make use of𝑒 𝑣, which denotes a variable that can be either𝑒or𝑣. The second aspect is that we check the language design invariantVal, defined above.
This check is done withContext ⊢ 𝑜 𝑝 : contextPositions, which informs about the set of argument positions that are declared as evaluation contexts for𝑜 𝑝. For example, if Contexthas declarations𝐸::=(cons𝐸 𝑒) | (cons𝑣 𝐸), we haveContext⊢cons:{1,2}. Notice that𝐸cannot appear underneath a binder, so we forbid evaluation underneath binders. Once we have computed the setcontextPositions, we then check that the argument positions in a value declaration that are𝑣s, i.e., that are required to be values, are in that set.
To make an example, the value declaration𝑣 ::=(cons𝑣 𝑣) is well-typed because the𝑣s appear in argument positions1 and2, which are in{1,2}, contextual positions forcons.
Type CheckingError. The judgementContext ⊢ Error checks the error declaration, if present. The invariantValis checked here, as well. For example,raise𝐸must be an eval- uation context to prevent expressions such asraise(𝜆𝑥: 𝑇 .𝑒 nil)from being stuck and thereby jeopardizing type soundness.
Type CheckingContext.We use𝑒 𝑣 𝐸to denote a variable that can be𝑒,𝑣or𝐸, and we refer to𝑐𝑡 𝑥as those expressions where𝐸s and𝑣s can appear. For example,(cons 𝐸 𝑣)is a valid𝑐𝑡 𝑥. The judgementContext ⊢ Contextchecks that each context declaration has exactly one occurrence of𝐸. That is,(cons𝐸 𝐸)is not a valid𝑐𝑡 𝑥. (We enforce this with the existential quantification with uniqueness∃!.) It also enforces language design invariantsValandCtx. The lat- ter is ensured with the use of the functionacyclicwhich performs this check through a graph representation of the dependencies at play. To be precise, we have an edge for each context declaration from the index position of𝐸to the index positions of𝑣s. Context declarations(cons𝐸 𝑒)and (cons 𝑣 𝐸), i.e., left-to-right evaluation, induce the graph {2 ↦→ 1}, which is acyclic. The bad context declarations
(cons 𝐸 𝑣) and (cons 𝑣 𝐸), instead, induce the graph {1 ↦→ 2,2 ↦→ 1}, which contains a cycle and is rejected.
The functionacyclicperforms a standard topological sort and so we omit its definition.
The last syntactic category that must be checked isError Context. However, in order to check invariantErrCtxwe need to know whether an error handler exists. We therefore postpone this check until after we present the meta type system forType System.
3.2 Meta Type System for Typing Rules
Figure4contains the meta type system for checking the typing rules of the language. The typing rules classify the operators of the language w.r.t. their role. Operators are classified asintroduction forms,elimination forms,derived operators,the erroranderror handlers.
[t-main] (Figure4) is the main rule. It checks all the typing rules and returns the complete classification of the opera- tors in the structureClassification, which we explain. When checking each typing rule, we return arole map𝐵 which can be of three possible forms: 1)𝑜 𝑝 ↦→𝑅, where𝑜 𝑝is an operator and𝑅 is the role that this operator plays in the language, 2)𝑒𝑥 𝑝↦→value𝑐that denotes that𝑒𝑥 𝑝is a value for the type constructor𝑐, or 3)𝑒𝑥 𝑝↦→error, which means that𝑒𝑥 𝑝is an error.
The meta type system collects all the role maps𝐵1, . . . , 𝐵𝑛, for which we checkcompatible(𝐵1, . . . , 𝐵𝑛). This check en- sures that each operator has only one role. For example,cons cannot be both a value and an elimination form. Ultimately, the collection of all the role maps formsClassification.
Anatomy of a Typing Rule. Below we discuss how the meta type system checks each typing rule. Before proceeding, we take a closer look at the typing rule forletand type abstraction in system𝐹.
(t-let)
Γ,⊢𝑒1:𝑇1 Γ, 𝑥:𝑇1⊢𝑒2:𝑇2 Γ⊢ let𝑥 =𝑒1in𝑒2:𝑇2
(t-tabs) Γ, 𝑋 ⊢𝑒 :𝑇 Γ⊢Λ𝑋 .𝑒:∀𝑋 .𝑇 We say thatletis thesubjectof the typing rule (t-let), and 𝑇2is itsassigned type. We impose a common form for type environments: they can be used asΓ⊢𝑒:𝑇 andΓcan have bindings𝑥:𝑇 (as in (t-let)), and/or type variables𝑋 (as in (t-abst)). We also impose that typing rules type checkall their𝑒arguments, as done above and in virtually any typing rule we know.
[t-value] detects the introduction forms following the common design principle thatintroduction forms build val- ues of some data type.To this aim, [t-value] imposes that the assigned type of the typing rule has the form(𝑐 𝑇), as highlighted, that is, a type constructor applied to arguments.
[t-value] also checks that𝑜 𝑝forms a value. To make some examples, below [t-value] is instantiated to check (t-abs)
5
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605
606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660
⊢ L
⊢Type ⊢Expression Context⊢Value Context⊢Error Context⊢Context Value|Error|Dynamic Semantics⊢Type System:Classification
Classification|Context⊢Error Context
Context|Classification|Type System⊢Dynamic Semantics
⊢ (Types,Expression,Value,Error,Context,Error Context,Type System,Dynamic Semantics)
⊢Typeand⊢𝑡𝑦
⊢𝑡𝑦1 . . . ⊢𝑡𝑦𝑛
⊢𝑇 ::=𝑡𝑦1|. . .|𝑡𝑦𝑛 ⊢𝑐 𝑇 (𝑋).𝑇
⊢Expressionand⊢𝑒𝑥 𝑝−
⊢𝑒𝑥 𝑝−
1 . . . ⊢𝑒𝑥 𝑝−
𝑛
⊢𝑒::= 𝑒𝑥 𝑝−
1 |. . .|𝑒𝑥 𝑝𝑛− ⊢𝑜 𝑝 𝑇 (𝑋).𝑇 (𝑥).𝑒 (𝑋).𝑒 𝑒
Context⊢ValueandContext⊢𝑒𝑥 𝑝 Context⊢𝑒𝑥 𝑝1 . . . Context⊢𝑒𝑥 𝑝𝑛
Context⊢𝑣::= 𝑒𝑥 𝑝1|. . .|𝑒𝑥 𝑝𝑛
Context⊢𝑜 𝑝:contextPositions
∀𝑖∈ {𝑖|𝑒 𝑣𝑖=𝑣}, 𝑖∈contextPositions Context⊢𝑜 𝑝 𝑇 (𝑋).𝑇 (𝑥).𝑒 (𝑋).𝑒 𝑒 𝑣 Context⊢ErrorandContext⊢𝑜 𝑝:contextPositions
Context⊢𝑒𝑟::=𝜖
Context⊢𝑒𝑥 𝑝 Context⊢𝑒𝑟::=𝑒𝑥 𝑝
contextPositions={𝑖|𝑜 𝑝 𝑎𝑟 𝑔𝑠∈Contextand𝐸∈𝑎𝑟 𝑔𝑠at position𝑖} Context⊢𝑜 𝑝:contextPositions
Context⊢ContextandContext⊢𝑐𝑡 𝑥 Context⊢𝑐𝑡 𝑥1 . . . Context⊢𝑐𝑡 𝑥𝑛
acyclic(Context) Context⊢𝐸::= 𝑐𝑡 𝑥1|. . .|𝑐𝑡 𝑥𝑛
∃!(𝑒 𝑣 𝐸𝑖=𝐸) Context⊢𝑜 𝑝:contextPositions
∀𝑖∈ {𝑖|𝑒 𝑣𝑖=𝑣}, 𝑖∈contextPositions Context⊢𝑜 𝑝 𝑇 (𝑋).𝑇 (𝑥).𝑒 (𝑋).𝑒 𝑒 𝑣 𝐸
Figure 3.Meta Type system: Main Judgement and Syntactic Categories, with the exception ofError Context, which is defined at the end of Section3.2.𝑡𝑦is an expression derived by the grammar forType.𝑒𝑥 𝑝is𝑒𝑥 𝑝−in which we can use𝑣variables.
𝑐𝑡 𝑥is derived by the grammar forContext.𝑒𝑥 𝑝−is derived by the grammar forExpression.𝑒 𝑣, is a variable that can be either 𝑒or𝑣.𝑒 𝑣 𝐸, is a variable that can be either𝑒or𝑣or𝐸.
and the typing rule for the list operatorcons.
𝑣::=𝜆𝑥:𝑇 .𝑒 · · ·
|Error
|Dynamic Sem.
⊢ Γ, 𝑥:𝑇1⊢𝑒:𝑇2 Γ⊢𝜆𝑥:𝑇1.𝑒: 𝑇1→𝑇2
:
𝜆𝑥:𝑇 .𝑒
↦→
value→
𝑣::=cons𝑣 𝑣 · · ·
|Error
|Dyn. Sem.
⊢
Γ⊢𝑒1:𝑇 Γ⊢𝑒2:(List𝑇) Γ⊢ (cons𝑒1𝑒2): List𝑇
:
cons𝑣 𝑣
↦→
valueList
[t-value] helps satisfy the progress theorem because when the values of the language are type checked with this rule it is immediate to prove the lemmas for the canonical forms of the language.
[t-elim] classifies elimination forms following a common pattern:
Elim:elimination forms manipulate/inspect values of some data type at their principal argument.
Accordingly, [t-elim] imposes that the typing rule as- signs a complex type(𝑐 𝑇)to the principal argument of𝑜 𝑝1. To simplify our presentation, we assume without loss of generality that the principal argument is always the first expression variable (𝑒1). We expect that the behavior of the operator is defined by case analysis on some values. There- fore, [t-elim] expects to find at least a reduction rule of the form(𝑜 𝑝1 (𝑜 𝑝2𝑎𝑟 𝑔𝑠2) 𝑎𝑟 𝑔𝑠1) −→ 𝑒𝑥 𝑝+, that is, the principal argument is a complex expression, as highlighted.
Reduction rules typically follow this pattern, examples are
6
661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770
Type Environment Γ∗ ::= Γ|Γ, 𝑥:𝑇 |Γ, 𝑋
Role Maps 𝐵 ::= 𝑜 𝑝↦→𝑅 |𝑒𝑥 𝑝↦→value𝑐|𝑒𝑥 𝑝↦→error Roles 𝑅 ::= elim𝑐|derived|errorHandler
Value|Error|Dynamic Semantics⊢Type System:Classification [t-main]
Values|Error|Dynamic Semantics⊢𝜙1:𝐵1 . . .
Values|Error|Dynamic Semantics⊢𝜙𝑛:𝐵𝑛 compatible(𝐵1, . . . , 𝐵𝑛)
Values|Error|Dynamic Semantics⊢ {𝜙1, . . . ,𝜙𝑛}:{𝐵1, . . . , 𝐵𝑛} [t-value]
(𝑜 𝑝 𝑎𝑟 𝑔𝑠)∈Values
Values|Error|Dynamic Semantics⊢ Γ∗⊢𝑒1:𝑡𝑦1 . . . Γ∗⊢𝑒𝑛:𝑡𝑦𝑛 Γ⊢ (𝑜 𝑝 𝑇′𝑒1 · · · 𝑒𝑛): (𝑐 𝑇)
:(𝑜 𝑝 𝑎𝑟 𝑔𝑠)↦→value𝑐
[t-elim]
(𝑜 𝑝1(𝑜 𝑝2𝑎𝑟 𝑔𝑠2)𝑎𝑟 𝑔𝑠1) −→ 𝑒𝑥 𝑝+∈Dynamic Semantics 𝑜 𝑝2∈Values Values|Error|Dynamic Semantics⊢
Γ⊢𝑒1: (𝑐 𝑇) . . . Γ∗⊢𝑒𝑛:𝑡𝑦𝑛 Γ⊢ (𝑜 𝑝1 𝑇′ 𝑒1 · · ·𝑒𝑛):𝑡𝑦
:𝑜 𝑝1↦→elim𝑐 [t-errHandler]
(𝑜 𝑝1(𝑜 𝑝2𝑎𝑟 𝑔𝑠2)𝑎𝑟 𝑔𝑠1) −→ 𝑒𝑥 𝑝+∈Dynamic Semantics 𝑜 𝑝2∈Error Values|Error|Dynamic Semantics⊢ Γ∗⊢𝑒1:𝑡𝑦1 . . . Γ∗⊢𝑒𝑛:𝑡𝑦𝑛
Γ⊢ (𝑜 𝑝1𝑇 𝑒1 · · ·𝑒𝑛):𝑡𝑦
:𝑜 𝑝1↦→errorHandler [t-derived]
∀(𝑜 𝑝 𝑡 𝑒𝑟 𝑚𝑠) −→ 𝑒𝑥 𝑝+∈Dynamic Semantics, 𝑡 𝑒𝑟 𝑚𝑠contains only variables Values|Error|Dynamic Semantics⊢ Γ∗⊢𝑒1:𝑡𝑦1 . . . Γ∗⊢𝑒𝑛:𝑡𝑦𝑛
Γ⊢ (𝑜 𝑝 𝑇 𝑒1 · · · 𝑒𝑛):𝑡𝑦
:𝑜 𝑝↦→derived [t-error]
(𝑜 𝑝 𝑎𝑟 𝑔𝑠) ∈Error 𝑇 ∉(𝑇′∪vars(𝑡𝑦1) ∪. . .∪vars(𝑡𝑦𝑛)) Values|Error|Dynamic Semantics⊢ Γ∗⊢𝑒1:𝑡𝑦1 . . . Γ∗⊢𝑒𝑛:𝑡𝑦𝑛
Γ⊢ (𝑜 𝑝 𝑇′ 𝑒1 · · ·𝑒𝑛):𝑇
:(𝑜 𝑝 𝑎𝑟 𝑔𝑠)↦→error
Figure 4.Meta Type system: Typing Rules. For simplicity, each𝑒𝑖 in𝑒1, . . . , 𝑒𝑛may be an expression variable or a bound expression such as(𝑥).𝑒. The sequences𝑇 contain types, each of which may also be a bound type such as(𝑋).𝑇. Sequences 𝑎𝑟 𝑔𝑠contain variables, which may be under a binder as well. Also, sequences in this figure have distinct variables.
(app (𝜆 𝑥 .𝑒) 𝑒) −→ 𝑒[𝑣/𝑥]for the elimination formapp, and(head (cons𝑣1𝑣2) ) −→ 𝑣1for the elimination form head. Here, the left-hand side of reduction rules have an expression𝑒𝑥 𝑝+, which denotes an expression𝑒𝑥 𝑝in which substitutions of the form𝑒𝑥 𝑝[𝑒𝑥 𝑝/𝑥] and𝑒𝑥 𝑝[𝑡𝑦/𝑥] can occur.
Some of the reduction rules of error handlers have the same pattern of that for elimination forms, but an error
appears as principal argument. Therefore, to distinguish whether the operator is an elimination form rather than an error handler, we check that𝑜 𝑝2is a value.
7
771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825
826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880
To make some examples, below we instantiate [t-elim]
for checking (t-app), and the typing rule forhead. app(𝜆𝑥:𝑇 .𝑒)𝑣−→ 𝑒[𝑣/𝑥]∈Dynamic Semantics
𝜆∈Values Value
|Error
|Dyn. Sem.
⊢ Γ⊢𝑒1:𝑇1→𝑇2 Γ⊢𝑒2:𝑇1 Γ⊢app𝑒1𝑒2:𝑇2
: app
↦→
elim→
head(cons𝑣1𝑣2) −→ 𝑣1∈Dynamic Semantics cons∈Values
Value
|Error
|Dynamic Sem.
⊢ Γ⊢𝑒:List𝑇 Γ⊢head𝑒:𝑇
:head↦→elimList Imposing that the principal argument be a value and typed at a complex type helps satisfy the progress theorem for the language being type checked. In particular, when we analyze an operator whose typing rule has been type checked with [t-elim] we are guaranteed to be able to apply the appro- priate canonical form lemma. The meta type system for the dynamic semantics of Section3.3then ensures the existence of reduction rules to prove some steps, and therefore that the progress theorem would hold for the operator.
[t-errHandler] classifies the error handlers. In doing so, we make sure thaterror handlers handle the error at their prin- cipal argument.[t-errHandler] is similar to [t-elim]. There are two differences: it does not impose the principal argu- ment to be typed at some precise type, and it expects a reduc- tion rule of the form (𝑜 𝑝1 (𝑜 𝑝2𝑎𝑟 𝑔𝑠2) 𝑎𝑟 𝑔𝑠1) −→ 𝑒𝑥 𝑝+ where the operator𝑜 𝑝2is an error rather than a value.
To make an example, we instantiate [t-errHandler] for the typing rule (t-try).
try(raise𝑣)with𝑒−→ (𝑒 𝑣)∈Dynamic Semantics raise∈Error
Value
|Error
|Dyn. Sem.
⊢
Γ⊢𝑒1:𝑇 Γ⊢𝑒2:⊤ →𝑇 Γ⊢ try𝑒1with𝑒2:𝑇
:
try
↦→
errorHandler [t-derived] classifies derived operators. One of their char- acteristics is thatderived operators do not primitively manip- ulate complex data, rather they pass it on to other operators. For this reason, [t-derived] checks that all the reduction rules for the operator are of the form(𝑜 𝑝 𝑎𝑟 𝑔𝑠) −→ 𝑒𝑥 𝑝+, where𝑎𝑟 𝑔𝑠are exclusively variables. Therefore,𝑜 𝑝does not pattern-match its arguments into complex expressions. To make some examples, we instantiate [t-derived] for the typing rules offixandletrec.
fix𝑣−→𝑣(fix𝑣) ∈Dynamic Semantics Value
|Error
|Dynamic Sem.
⊢ Γ⊢𝑒:𝑇 →𝑇 Γ⊢fix𝑒:𝑇
:fix↦→derived
letrec𝑥=𝑒1in𝑒2−→𝑒2[(fix(𝜆𝑥 .𝑒1))/𝑥]∈Dyn. Sem.
Value
|Error
|Dyn. Sem.
⊢
Γ, 𝑥 :𝑇1⊢𝑒1:𝑇1 Γ, 𝑥 :𝑇1⊢𝑒2:𝑇2 Γ⊢ letrec𝑥=𝑒1in𝑒2:𝑇2
: letrec
↦→
derived [t-error] handles the typing rule for the error. We enforce that the assigned type is a fresh variable𝑇. This ensures that the error can be typed at any type. This is necessary to establish the type preservation of the language being type checked. Indeed, the error travels through contexts thanks to the rule (err-ctx), and it must be prepared to match the type of the expression it replaces. It is easy to see that [t-error]
checks (t-error) successfully.
For𝐹exc, all typing rules check successfully and we end up with the classification below.
Classification={
𝜆𝑥:𝑇 .𝑒↦→value→, Λ𝑋 .𝑒↦→value∀, app↦→elim→, tapp↦→elim∀, try↦→errorHandler, raise𝑣↦→error
}
We write Classification ⊢ app : elim → for retrieving information about operators.
Back toError Context.After having meta type checked the typing rules, we can checkError Contextbecause we have acquired knowledge on the error handler, if present.
Indeed, we need to ensureErrCtx, and we do so with the typing judgementClassification |Context⊢Error Context, defined below.
Classification|Context⊢Error Context (𝑜 𝑝 · · · ):error∉Classification Classification|Context⊢er::=𝜖
Classification⊢(𝑜 𝑝1 · · · ):error (𝑜 𝑝2 · · · ):errorHandler∉Classification
Classification|Context⊢Context[F/E]
Classification⊢(𝑜 𝑝1 · · · ):error Classification⊢(𝑜 𝑝2 · · · ):errorHandler Classification|Context⊢Context[F/E]−(𝑜 𝑝2𝐹 · · · ) If the language does not contain an error,Error Context is the empty derivation𝜖, which we consider well-typed by default. If an error is present but there are no error handlers, then we simply impose that error contexts are exactly the evaluation contexts. We recall that evaluation contexts are defined with the variable𝐸and error contexts are defined with the variable𝐹. With the notationContexts[F/E] we denote the grammar ofContext in which variables𝐸 are replaced with𝐹. Ultimately, if an operator is classified as an error handler, we check that error contexts are evaluation contexts minus the error handler at the principal argument (𝐹as the first argument of𝑜 𝑝2).
8
881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990
Type checking error contexts make them synch with eval- uation contexts, and helps proving the progress theorem for the language being type checked because it ensures that operators have a defined behavior if an error appears as one of their arguments.
3.3 Meta Type System for Dynamic Semantics Figure5contains the meta type system for checking the dynamic semantics. The language design invariants that we enforce at this point are:
• ValRed:Principal arguments, and any argument that is required to be evaluated to a value for a reduction rule to fire, must be declared as evaluation context.For example, without the context declaration(𝐸 𝑒)the ex- pression( (𝜆𝑥 .𝑥) (𝜆𝑥 .𝑥))nil)would be stuck because (beta) would not fire and jeopardize type soundness.
Similarly, since (beta) requires that also the second argument ofappbe a value, missing the evaluation context would jeopardize type soundness.
• AllVal:Each elimination form of some type manipu- lates all the values of that type. For example, were we to miss to specify the reduction rule for the predeces- sor operation(pred zero) −→error, the expression (pred zero)would be stuck, jeopardizing type sound- ness.
• ErrSucc:Error handlers must handle both the error and the case of success. For example, if we were to define (r-try-error) as the sole behavior of the error han- dler, the expressiontry true with𝑒would be stuck, jeopardizing type soundness. A reduction rule such as (r-try-success), which expects a value at principal argument position, must be specified.
• Preserv:Naturally, reductions must be type preserv- ing, i.e., in a reduction𝑒−→𝑒′,𝑒and𝑒′must have the same type.
[r-main] is the main typing rule. First, it imposes that (ctx) and (err-ctx) are present. Next, it makes sure that the rest of the reduction rules𝜙1,. . .,𝜙𝑛 are well-typed.
Meta type checking a reduction rule returns amove map (𝐶), which is a description of the computational step that the reduction rule enables. A move map assigns amove (𝑀)to the operator that is the subject of the reduction rule. Moves can be:
• eliminates𝑜 𝑝: for reduction rules of elimination forms, which manipulate some specific value.
• handlesError: for the reduction rule that handles the error.
• handlesSuccess: for the error handler to handle the case when an error does not occur.
• moves: for reduction rules of derived operators.
When all the reduction rules have been checked, [r-main]
collects all the move maps and we perform an exhaustiveness
check to ensure thatAllValandErrSuccare fulfilled. This is done withMoves exhaustsClassification.
[r-elimination] handles the case of reduction rules for elimination forms. The first aspect that [r-elimination]
enforces is the language design patternElim. To this aim, we check that𝑜 𝑝1is an elimination form for a type𝑐and that𝑜 𝑝2 is a value of the same type𝑐. Next, [r-elimination] covers ValRed. In particular, we check that the principal argument (position1) is an evaluation context. Not only that, we check that any other argument of𝑜 𝑝1that is required to be a value has an evaluation context defined. These checks help satisfy the progress theorem of the language being type checked. If some arguments need to become a value for the rule to fire, the existence of the corresponding evaluation contexts let them evaluate indeed. Also, [r-elimination] ensures that when the principal argument becomes the value𝑜 𝑝2then we can take a step with this reduction rule, satisfying the progress theorem.
Lastly, [r-elimination] and all other rules of Figure5 check that the overall reduction is type preserving. This is done with the last line of the premises. We postpone the discussion of type preservation until Section3.4.
To make an example, we instantiate [r-elimination] for (beta) and one of the reduction rules forhead. (Below and throughout this subsection we have elided the type preser- vation check, which we discuss later).
Classification⊢app:elim→ Classification⊢𝜆 𝑥:𝑇 .𝑒:value→ Context⊢app:{1,2}
Context
|Classif.
|Type System
⊢(app(𝜆 𝑥:𝑇 .𝑒))𝑣 −→ 𝑒[𝑣/𝑥] : app
↦→
eliminates𝜆 Classification⊢head:elimList
Classification⊢cons𝑣1𝑣2:valueList Context⊢head:{1}
Context
|Classif.
|Type System
⊢head(cons𝑣1𝑣2) −→𝑣1:
head
↦→
eliminatescons
Notice that a call-by-name application with reduction rule (app(𝜆 𝑥:𝑇 .𝑒1))𝑒2−→ 𝑒1[𝑒2/𝑥]would be handled simi- larly, with the difference that the check on evaluation con- texts would beContext⊢app:{1}. This is because, roughly speaking, the second argument of the application is an𝑒 rather than a𝑣.
[r-errHandler] addresses the reduction rule for error handling. This rule is similar to [r-elimination]. We first detect that the operator at hand is an error handler, and then we check that the principal argument forms an error.
To make an example, [r-errHandler] is instantiated for
9