Let Arguments Go First

Ningning Xie, Bruno C. d. S. Oliveira The University of Hong Kong

ESOP 2018, Thessaloniki, Greece 2018-04-17

1 Background

2 Bi-Directional Type Checking

• Well known in the folklore of type system for a long time

• Popularized by Pierce and Turner’s work*

• Can support many type system features: refinements, indexed types, intersections and unions, contextual modal types, object-oriented subtyping, …

* Benjamin C Pierce and David N Turner. Local type inference. TOPLAS, 22(1):1–44, 2000. 3 Bi-Directional Type Checking

Two Modes in type-checking

• Inference (synthesis): e synthesizes A e A ` ) • Checked: check e against A e A ` ( • Which constructs should be in which mode? 4 Let Arguments Go First

Ningning Xie and Bruno C. d. S. Oliveira

The University of Hong Kong nnxie,bruno @cs.hku.hk { }

Abstract. Bi-directional type checking has proved to be an extremely useful and versatile tool for type checking and type inference. The con- ventional presentation of bi-directional type checking consists of two modes: inference mode and checked mode. In traditional bi-directional type-checking, type annotations are used to guide (via the checked mode) the type inference/checking procedure to determine the type of an ex- pression, and type information flows from functions to arguments. 21 This paper presents a variant of bi-directional type checking where the type information5.1 flows Combining from arguments Application to functions. and This Checkedvariant retains Modes the inference mode, but adds a so-called application mode. Such design can remove annotationsAlthough that the basicapplication bi-directional mode type provides checking us cannot, with alternative design choices in and is useful whena bi-directional type information type from system, arguments a checked is required mode to type- can still be easily added. One check the functionsmotivation being applied. for the We checked present mode two applications would be annotated and de- expressions e : A,where velop the meta-theorythe type (mostly of expressions verified in is Coq) known of the and application is therefore mode. used to check expressions. Consider adding e : A for introducing the third checked mode for the lan- 1 Introductionguage in Section 3. Notice that, since the checked mode is stronger than appli- cation mode, when entering checked mode the application context is no longer Bi-directional typeuseful. checking Instead has been we use known application in the folklore subtyping of type to satisfy systems the application context for a long time. Itrequirements. was popularized A possible by Pierce typing and Turner’s rule for work annotation on local expressions type is: inference [29]. Local type inference was introduced as an alternative to Hindley- Milner (henceforth HM system) type systems A [11<, 17: ],B which coulde easilyA deal ` ` ( T-Ann with polymorphic languages with subtyping. Bi-directional p (e : A type) checkingB is one component of local type inference that, aided by some` type) annotations, en- ables type inferenceHere, in ane expressiveis checked language using its with annotation polymorphismA, and and then subtyp- we instantiate A to B using ing. Since Pierce andBisubtyping Turner’s-Directional with work, application various other context authorsType . have provedChecking the ef- fectiveness of bi-directionalNow we type can checking have a in rule several set of other the settings, checked including mode for all expressions. For many di↵erent systemsexample, with one subtyping useful rule [12, for15, abstractions14], systems in with checked dependent mode could be Abs-Chk, * types [37, 10• ,A2 ,recipe21,where3], and thefrom various parameter Dunfield other works typeandA [1,serves 13Pfenning, 28, as7, the22]. typeFurthermore, of x, and typing checks the bi-directional typebody checking with hasB. also Also, been combined combined with with the HM-style information techniques flow, the checked rule for for providing type• Introduction inferenceapplication in the checks presence rules the function of higher-ranked with the types full type. [27, 14]. The key idea in bi-directional type checking( is simple. In its basic form typing is split into inference and,x: Acheckede modes.B The most saliente2 featureA of a bi-e1 A B directional type-checker is when` information( Abs-Chk deduced from` inference) mode` is ( ! App-Chk x. e A B e e B used to guide checking` of an expression( ! in checked mode. One of such interactions` 1 2 ( between modes• happensEliminationNote in the that typing adding rules rule expression for function annotations applications: might bring convenience for pro- grammers, since annotations) can be moreNotice freely placed here inhow a program. type For exam- e1 A B e2 A ple,` (f). f 1)! : (Int `Int) ( Int APPbecomesinformation valid. However flows this from does not add e1 e2 !B ! expressive power,` since) programs that are typeablefunctions under to expression arguments annotations, * Joshua Dunfieldwouldand remain Frank Pfenning typeable. Tridirectional aftertypechecking moving. POPL’04, the annotations 2004. to bindings. For example 5 the previous program is equivalent to (f :(Int Int). f 1). ! This discussion is a sketch. We have not defined the corresponding declarative system nor algorithm. However we believe that the addition of a checked mode will not bring surprises to the meta-theory.

5.2 Additional Constructs In this section, we show that the application mode is compatible with other constructs, by discussing how to add support for pairs in the language given in Section 3. A similar methodology would apply to other constructs like sum types, data types, if-then-else expressions and so on. The introduction rule for pairs must be in the inference mode with an empty application context. Also, the subtyping rule for pairs is as expected.

e1 A e2 B A1 <: B1 A2 <: B2 ` ) ` ) T-Pair S-Pair (e ,e ) (A, B) (A ,A ) <: (B ,B ) ` 1 2 ) 1 2 1 2 33

–– AA new new design design for for type type inference inference of of higher-ranked higher-ranked types types whichwhich gen- gen- eralizeseralizes the the HM HM type type system, system, supports supports a a polymorphic polymorphic letlet asas syntactic , sugar, andand infers infers higher higher rank rank types. types. We We present present a a syntax-directed syntax-directed specification, specification, an an elaborationelaboration semantics semantics to to System System F, F, some some meta-theory meta-theory in in Coq, Coq, and and an an algo- algo- rithmicrithmic type type system system with with completeness completeness and and soundness soundness proofs. proofs. –– AA System-F-like System-F-like calculus calculusasas a a theoretical theoretical response response to to the the challenge challenge noted noted byby Pierce Pierce and and Turner Turner [ [2929].]. It It shows shows that that the the application application mode mode is is compatible compatible withwith type type applications, applications, which which also also enables enables encoding encoding type type declarations. declarations. We We presentpresent a a type type system system and and meta-theory, meta-theory, including including proofs proofs of of type type safety safety and and uniquenessuniqueness of of typing typing in in Coq. Coq.

2Overview2Overview

2.12.1 Background: Background: Bi-Directional Bi-Directional Type Type Checking Checking TraditionalTraditional type type checking checking rules rules can can be be heavyweight heavyweight on on annotations, annotations, in in the the sense sense thatthat lambda-bound lambda-bound variables variables always always need need explicit explicit annotations. annotations. Bi-directional Bi-directional typetype checking checking [ [2929]] provides provides an an alternative, alternative, which which allows allows types types to to propagate propagate down- down- wardward the the syntax syntax tree. tree. For For example, example, in in the the expression expression ((ff::IntInt IntInt.. ff)()(yy.. !! yy)),, the the type type of of yy isis provided provided by by the the type type annotation annotation on on ff.. This This is is supported supported by by thethe bi-directional bi-directional typing typing rule rule for for applications: applications:

ee11 AA BB ee22 AA `` )) !! `` (( APPAPP ee ee BB `` 11 22 ))

Specifically,Specifically, if if we we know know that that the the type type of ofee11 isis a a function function from from AA BB,, we we can can check check !! thatthat ee22 hashas type type AA.. Notice Notice that that here here the the type type information information flows flows from from functions functions toto arguments. arguments. OneOne guideline guideline for for designing designing bi-directional bi-directional type type checking checking rules rules [ [1515]istodis-]istodis- tinguishtinguishBi introduction introduction-Directional rules rules from from elimination eliminationType rules. rules. Constructs ConstructsChecking which which correspond correspond toto introduction introduction forms forms are are checkedchecked againstagainst a a given given type, type, while while constructs constructs cor- cor- respondingresponding to to elimination elimination forms forms inferinfer (or(or synthesize) synthesize) their their types. types. For For instance, instance, • Considerunderunder this this design designdesigning principle, principle, rules the the introduction introduction for pairs rule rule for for pairs pairs is is supposed supposed to to be be in in checkedchecked mode, mode, as as in in the the rule rule Pair-CPair-C..

ee11 AA ee22 BB ee11 AA ee22 BB `` (( `` (( Pair-CPair-C `` )) `` )) Pair-IPair-I ((ee ,e,e)) ((A,A, B B)) ((ee ,e,e )) ((A,A, B B)) `` 11 22 (( `` 11 22 )) Unfortunately,Unfortunately, this this means means that that the the trivial trivial program program (1,(1, 2) 2) cannotcannot type-check, type-check, whichwhich• (1, in in this this2) casecannot case has has totype to be be- rewritten rewrittencheck to to (1,(1, 2) 2) : : ( (IntInt ,, IntInt)).. InIn…unless this this particular particular you write case, case, bi-directional bi-directionalit as (1, 2) type type : checking checking(int, int goes goes) against against its its original original intentionintention of of removing removing burden burden from from programmers, programmers, since since a a seemingly seemingly unnecessary unnecessary annotationannotation• …unless is is needed. needed.you have Therefore, Therefore, also an in in practice, practice,inference bi-directional bi-directional rule for type type pairs systems systems do do not not strictlystrictly follow follow the the guideline, guideline, and and usually usually have have additional additional inference inference rules rules for for the the introductionintroduction• Rules scales form form of of constructs.up constructs. with the For For pairs,typing pairs, the the rules corresponding corresponding rule rule is is Pair-IPair-I.. NowNow we we can can type type check check (1,(1, 2) 2),, but but the the price price to to pay pay is is that that two two typing typing rules rules6 forfor pairs pairs are are needed. needed. Worse Worse still, still, the the same same criticism criticism applies applies to to other other constructs. constructs. Contributions

• A variant of bi-directional type checking with an application mode type information propagates from arguments to functions • A new design for type inference of higher-ranked types generalizes the Hindley-Milner type system supports syntactic sugar for polymorphic let • A System-F like calculus compatible with type application Except the algorithm encoding type declaration system, most parts are formalized in Coq 7 Contributions

• A variant of bi-directional type checking with an application mode type information propagates from arguments to functions • A new design for type inference of higher-ranked types generalizes the Hindley-Milner type system supports syntactic sugar for polymorphic let • A System-F like calculus compatible with type application encoding type declaration

8 Application Mode

9 Application Mode (x. x)1

• cannot type-check …unless you write it as ((x. x):int int)1 ! • …unless you have also an inference rule for lambdas (with some type inference)

• …WAIT! What if the type of the argument is accounted for in inferring the function?

10 Application Mode

(x. x)1

The argument 1 has type int Can the function accept arguments of int Let’s assume x : int We have return type int The type of function is int → int ………

11 Let Arguments Go First

Ningning Xie and Bruno C. d. S. Oliveira

The University of Hong Kong nnxie,bruno @cs.hku.hk { }

Abstract. Bi-directional type checking has proved to be an extremely useful and versatile tool for type checking and type inference. The con- ventional presentation of bi-directional type checking consists of two modes: inference mode and checked mode. In traditional bi-directional type-checking, type annotations are used to guide (via the checked mode) the type inference/checking procedure to determine the type of an ex- pression, and type information flows from functions to arguments. This paper presents a variant of bi-directional type checking where the type information flows from arguments to functions. This variant retains the inference mode, but adds a so-called application mode. Such design 4 can remove annotations that basic bi-directional type checking cannot, and is useful when type information from arguments is required to type- Thischeck shows the one functions drawback being of applied.bi-directional We present type checking: two applications often to and minimize de- anno- tations,velop many the meta-theory rules are duplicated (mostly verified for having in Coq) both of the inference application and mode.checked mode, which scales up with the typing rules in a type system. 1 Introduction 2.2 Bi-Directional Type Checking with the Application Mode Bi-directional type checking has been known in the folklore of type systems for aWe long propose time. a It variant was popularized of bi-directional by Pierce type checking and Turner’s with a new workapplication on local type mode. inferenceThe application[29]. Local mode type inference preserves was the introduced advantage of as bi-directional an alternative type to Hindley- checking, Milnernamely (henceforth many redundant HM system) annotations type systems are removed, [11, 17], while which certain could programs easily deal can withtype polymorphic check with languages even fewer with annotations. subtyping. Also, Bi-directional with our proposal, type checking the inference is one componentmode is a of special local case type of inference the application that, aided mode, by so it some does typenot produce annotations, duplications en- ablesof type rules inference in the type in an system. expressive Additionally, language the with checked polymorphism mode can and still subtyp- be easily ing.combined Since Pierce into and the Turner’s system (see work, Section various5.1 otherfor details). authors have The essentialproved the idea ef- of the application mode is to enable the type information flow in applications to fectiveness of bi-directional type checking in several other settings, including propagate from arguments to functions (instead of from functions to arguments many di↵erent systems with subtyping [12, 15, 14], systems with dependent as in traditional bi-directional type checking). types [37, 10, 2, 21, 3], and various other works [1, 13, 28, 7, 22]. Furthermore, To motivate the design of bi-directional type checking with an application bi-directional type checking has also been combined with HM-style techniques mode, consider the simple expression for providing type inference in the presence of higher-ranked types [27, 14]. The(x key. x idea)1 in bi-directional type checking is simple. In its basic form typing is splitThis into expressioninference cannotand typechecked checkApplicationmodes. in traditional The most bi-directional salient Mode feature type of checking a bi- directionalbecause type-checker unannotated abstractions is when information only have deduced a checked from mode, inference so annotations mode is are usedrequired. to guide For checking example, of an(( expressionx. x):Int in checkedInt)1 mode.. One of such interactions ! betweenIn modes thisInstead example happens we inof can the… observe typing that rule if for the function type of applications: the argument is accounted for in inferring the type of x. x, then it is actually possible to deduce that the e1 A B e2 A lambda expression` has type) Int! Int , from` the( argumentAPP 1. e !e B ` 1 2 ) The applicationAn alternative mode. If types idea flow from is theto argumentspush the to thetype function, of the an alternative idea is to push the type of the arguments into the typing of the function, asarguments the rule that into is briefly the introduced typing in Sectionof the1 : function

e2 A p ,A e1 A B ` ) ` ) ! APP p e1 e2 B ` )

Here the argument e2 synthesizes its type A,whichthenispushedintothe application context . Lambda expressions can now make use of the application 12 context, leading to the following rule:

,x: A p e B ` ) Lam p ,A x. e A B ` ) ! The type A that appears last in the application context serves as the type for x, and type checking continues with a smaller application context and x:A in the typing context. Therefore, using the rule App and Lam, the expression (x. x)1can type-check without annotations, since the type Int of the argument 1 is used as the type of the binding x. 4

This shows one drawback of bi-directional type checking: often to minimize anno- tations, many rules are duplicated for having both inference and checked mode, which scales up with the typing rules in a type system.

2.2 Bi-Directional Type Checking with the Application Mode

We propose a variant of bi-directional type checking with a new application mode. The application mode preserves the advantage of bi-directional type checking, namely many redundant annotations are removed, while certain programs can type check with even fewer annotations. Also, with our proposal, the inference mode is a special case of the application mode, so it does not produce duplications of rules in the type system. Additionally, the checked mode can still be easily combined into the system (see Section 5.1 for details). The essential idea of the application mode is to enable the type information flow in applications to propagate from arguments to functions (instead of from functions to arguments as in traditional bi-directional type checking). To motivate the design of bi-directional type checking with an application mode, consider the simple expression (x. x)1 This expression cannot type check in traditional bi-directional type checking because unannotated abstractions only have a checked mode, so annotations are required. For example, ((x. x):Int Int)1. ! In this example we can observe that if the type of the argument is accounted for in inferring the type of x. x, then it is actually possible to deduce that the lambda expression has type Int Int , from the argument 1. ! The application mode. If types flow from the arguments to the function, an alternative idea is to push the type of the arguments into the typing of the function, as the rule that is briefly introduced in Section 1: Application Mode e2 A p ,A e1 A B ` ) ` ) ! APP • Application p e1 contexte2 B is a stack that tracks the type of the arguments` ) Here the argument e2 synthesizes its type A,whichthenispushedintothe application context• .Lambda Lambda expressions expressions can can now now make make use use of the of application the application context, leading to thecontext following rule:

,x: A p e B ` ) Lam p ,A x. e A B ` ) ! The type A that appears• (x. last x)1 in the application context serves as the type for x, and type checking continues with a smaller application context and x:A in the 13 typing context. Therefore, using the rule App and Lam, the expression (x. x)1can type-check without annotations, since the type Int of the argument 1 is used as the type of the binding x. Application Mode

Two Modes in type-checking

• Inference (synthesis): e synthesizes A e A ` ) • Application: under application ctx , e synthesizes A p e A ` )

14 Application Mode

e A Interpretation ` ) p e A n Recipe? ` ) Whether the expression can be applied or not

• Expressions can be applied: variables, lambdas, applications, eliminations of pairs,…

• Expressions that cannot be applied: literals, pairs,… 15 Application Mode

e A Interpretation ` ) p e A n What if the application context is empty? ` )

…it is not applied to any arguments …we know nothing about the expression …we should infer it! • We can model inference mode as a particular case of the application mode

16 Application Mode

e A Interpretation ` ) p e A n What if we have a possibly non-empty application` ) context? e : A B C ! ! • Inference: e • Checked : e, A → B → C • Application Mode : e = = A = A, B ; finer grain notion leads to partial type checking 17 Application Mode

e A Interpretation ` ) p e A n Is Inference mode + Application mode better/worse` ) than Bi-Directional type checking?

• No one is conservative over the other. (x. x)1 (x : int int.y : bool.y)(y. y) True ! • But it does open paths to design choices 18 Application Mode

e A Benefits ` ) p e A n Local constraint solver for function variables.` )

Type system with implicit polymorphism and/or static overloading needs type information about the arguments when type-checking function variables.

id 3, (==) True False, …

Type system employs an application subtyping A B `  19 6

provides a new design choice for type inference/checking algorithms, especially for those where the information about arguments is useful. Therefore we next discuss some benefits of the application mode for two interesting cases where functions are either variables; or lambda (or type) abstractions.

2.3 Benefits of Information Flowing from Arguments to Functions

Local constraint solver for function variables. Many type systems, including type systems with implicit polymorphism and/or static overloading, need infor- mation about the types of the arguments when type checking function variables. For example, in conventional functional languages with implicit polymorphism, function calls such as (id 3) where id: a.(a a), are pervasive.Insucha 8 ! function call the type system must instantiate a to Int. Dealing with such im- plicit instantiation gets trickier in systems with higher-ranked types. For example, Peyton Jones et al. [27] require additional syntactic forms and relations, whereas Dunfield and Krishnaswami [14] add a special purpose application judgment. With the application mode, all the type information about the arguments be- ing applied is availableApplication in application contexts Mode and can be used to solve instanti- ation constraints. To exploit such information, the type system employs a special subtyping judgment called application subtyping, with the form A B. Un- `  Benefitslike conventional subtyping, computationally ande A areA interpreted as inputs and B as output. In above example, we have that` Int) a.a a B and we p e`8 A!  n Declarationcan determine desugaring that a = Int andfor Blambda= Int abstractions.Int. In this` way,) type system is able to solve the constraints locally according! to the application contexts since we no Annotationslonger need toare propagate never needed the instantiation for applied constraintslambdas to the typing process. (x. x)1 Declaration desugaring for lambda abstractions. An interesting consequence of Itthe enables usage oflet an sugar application mode is that it enables the following let sugar:

let x = e1 in e2 (x. e2) e1 Such syntactic sugar for let is, of course, standard. However, in20 the context of implementations of typed languages it normally requires extra type annotations or a more sophisticated type-directed translation. Type checking (x. e2) e1 would normally require annotations (for example an annotation for x), or other- wise such annotation should be inferred first. Nevertheless, with the application mode no extra annotations/inference is required, since from the type of the ar- gument e1 it is possible to deduce the type of x. Generally speaking, with the application mode annotations are never needed for applied lambdas.Thuslet can be the usual sugar from the untyped , including HM-style let expression and even type declarations.

2.4 Application 1: Type Inference of Higher-Ranked Types

As a first illustration of the utility of the application mode, we present a calculus with implicit predicative higher-ranked polymorphism. Contributions

• A variant of bi-directional type checking with an application mode type information propagates from arguments to functions • A new design for type inference of higher-ranked types generalizes the Hindley-Milner type system supports syntactic sugar for polymorphic let • A System-F like calculus compatible with type application encoding type declaration

21 Application 1 for the Application Mode

22 Application 1 n Type Inference of (implicit, predicative) Higher-Ranked Types

• Enables expressiveness power of System F.

• Undecidable.

• Hindley-Milner*(henceforth HM) with let generalization has rank 1 types. * Luis Damas and Robin Milner. Principal type-schemes for functional programs. POPL ’82, 1982. * J. Roger Hindley. The principal type-scheme of an object in combinatory logic. Transactions of the 23 American Mathematical Society, 146:29–60, 1969. 7 7 Higher-ranked types. Type systems with higher-ranked types generalize the tra- ditionalHigher-ranked HM type types. system,Type and systems are useful with in higher-ranked practice in languages types generalize like Haskell the or tra- otherditional ML-like HM type languages. system, Essentially and are usefulhigher-ranked in practice types in enable languages much like of the Haskell ex- or pressiveother ML-like power of languages. System F, Essentially with the advantage higher-ranked of implicit types polymorphism. enable much Com- of the ex- pletepressive type power inference of System for System F, with F is the known advantage to be of undecidable implicit polymorphism. [36]. Therefore, Com- severalplete type partial inference type inference for System algorithms, F is known exploiting to be additional undecidable type annotations, [36]. Therefore, haveseveral been partial proposed typeApplication in inference the past algorithms, instead [25 , exploiting115, 31, 27]. additional type annotations, have been proposed in the past instead [25, 15, 31, 27]. Higher-ranked types and bi-directional type checking. Bi-directional type check- n TypeingHigher-ranked isInference also used types to of help Higher and with bi-directional the-Ranked inferenceTypes type of higher-ranked checking. Bi-directional types [27, 14 type]. Con- check- sidering is the also following used to program: help with the inference of higher-ranked types [27, 14]. Con- • siderGHC(f .(rejects: thef following1, f ’c’)) program: (x. x) which(f.( is notf 1, typeablef ’c’)) under (x those. x) type systems because they fail to infer the type of f, since it is supposed to be polymorphic. Using bi-directional type checking, which is not typeable under those type systems because they fail to infer the type • weRewriting can rewrite according this program to as bi-directional guideline of f, since it is supposed to be polymorphic. Using bi-directional type checking, ((f.(f 1, f ’c’)) : ( a. a a) (Int, Char)) (x . x) we can rewrite this program8 as ! ! • Here…Wait!(( thef.( typeIff 1,we off fgeneralize’canc’)) be : easily ( a. the deriveda identitya) from( theInt ,function typeChar signature)) ( x . usingx) checked modeand propagate in bi-directional it into type 8 checking.the function! However,! … although some redundant an- * a state-ofnotationsHere-the-art thecompiler are type for Haskell removed of f can by be bi-directional easily derived type from checking, the type the signature burden24 of using inferring checked higher-rankedmode in bi-directional types is still type carried checking. by programmers: However, they although are forced some to redundant add poly- an- morphicnotations annotations are removed to help by bi-directional with the type type derivation checking, of higher-ranked the burden of types. inferring Forhigher-ranked the above example, types is still the carried type annotation by programmers: is still provided they are by forced programmers to add poly-, evenmorphic though annotations the necessary to help type with information the type can derivation be derived of intuitively higher-ranked without types. anyFor annotations: the above example,f is applied the to typex. x annotation, which is of is type still provideda. a a by. programmers, even though the necessary type information can be derived8 ! intuitively without any annotations: f is applied to x. x, which is of type a. a a. Generalization. Generalization is famous for its application8 in let polymorphism! in the HM system, where generalization is adopted at let bindings. Let polymor- phismGeneralization. is a usefulGeneralization component to introduceis famous top-levelfor its application quantifiers in (rank let polymorphism 1 types) intoin the a polymorphic HM system, type where system. generalization The previous is adopted example at becomes let bindings. typeable Let in polymor- the HMphism system is a if useful we rewrite component it to: let tof introduce= x. x in top-level(f 1, f quantifiers’c’). (rank 1 types) into a polymorphic type system. The previous example becomes typeable in the TypeHM system Inference if forwe rewritehigher-ranked it to: typeslet f with= x the. x applicationin (f 1, f mode.’c’).Using our bi- directional type system with an application mode, the original expression can typeType check Inference without for annotations higher-ranked or rewrites: types with( thef.( applicationf 1, f ’c’)) mode. (x. Usingx). our bi- directionalThis result type comes system naturally with if an we application allow type information mode, the flow original from expression arguments can totype functions. check without For inferring annotations polymorphic or rewrites: types for(f arguments,.(f 1, f we’c’ use))generaliza- (x. x). tion. In the above example, we first infer the type a. a a for the argument, This result comes naturally if we allow type8 information! flow from arguments thento functions. pass the For type inferring to the function. polymorphic A nice types consequence for arguments, of such we an use approachgeneraliza- istion that. In HM-style the above polymorphic example, welet firstexpressions infer the are type simplya. regardeda a for as the syntactic argument, 8 ! sugarthen topass a combination the type to of the lambda/application: function. A nice consequence of such an approach islet thatx = HM-stylee1 in e2 polymorphic (x. e2) e1let expressions are simply regarded as syntactic sugar to a combination of lambda/application: Interestingly, with this approach, nested lets can lead to types which are more generallet x than= e1 HM.in e2 For example,(x. e2)lete1 s = x. x in let t = y. s in e.Thetype Interestingly, with this approach, nested lets can lead to types which are more general than HM. For example, let s = x. x in let t = y. s in e.Thetype Application 1 n Type Inference of Higher-Ranked Types

Apply the application mode to higher-ranked type system* with generalization on applications

* Martin Odersky and Konstantin L ̈aufer. Putting type annotations to work. POPL ’96, 1996. * Simon Peyton Jones, Dimitrios Vytiniotis, Stephanie Weirich, and Mark Shields. Practical type inference for arbitrary-rank types. Journal of func- tional programming, 17(01):1–82, 2007. * Joshua Dunfield and Neelakantan R. Krishnaswami. Complete and easy bidirectional typechecking for higher-rank polymorphism. ICFP ’13, 2013. 25 Application 1 n Type Inference of Higher-Ranked Types

1. Sugars for HM style polymorphic let expression

2. Conservative over the HM type system

3. Comparison with existing literatures

26 Application 1 24

System Types ImpredLet Annotations MLF flexible and rigid yes yes on polymorphically used parameters HML flexible F-types yes yes on polymorphic parameters FPH boxy F-types yes yes onpolymorphicparametersandsome let bindings with higher-ranked types Peyton Jones F-types no yes on polymorphic parameters et al. (2007) Dunfield et al. F-types no no on polymorphic parameters (2013) this paper F-types no sugar on polymorphic parameters that are not applied

Fig. 5. Comparison of higher-ranked type inference systems. 27

Predicative Systems. Peyton Jones et al. [27] developed an approach for type in- ference for higher rank types using traditional bi-directional type checking based on Odersky and L¨aufer [24]. However in their system, in order to do instantia- tion on higher rank types, they are forced to have an additional type category (⇢ types) as a special kind of higher rank type without top-level quantifiers. This complicates their system since they need to have additional rule sets for such types. They also combine a variant of the containment relation from Mitchell [23] for deep skolemisation in subsumption rules, which we believe is compatible with our subtyping definition. Dunfield and Krishnaswami [14] build a simple and concise algorithm for higher ranked polymorphism based on traditional bidirectional type checking. They deal with the same language of Peyton Jones et al. [27], except they do not have let expressions nor generalization (though it is discussed in design variations). They have a special application judgment which delays instantiation until the expression is applied to some argument. As with application mode, this avoids the additional category of types. Unlike their work, our work supports generalization and HM-style let expressions. Moreover the use of an application mode in our work introduces several di↵erences as to when and where annota- tions are needed (see Section 2.4 for related discussion).

Impredicative Systems. MLF [18, 32, 19] generalizes ML with first-class poly- morphism. MLF introduces a new type of bounded quantification (either rigid or flexible) for polymorphic types so that instantiation of polymorphic bindings is delayed until a principal type is found. The HML system [20] is proposed as a simplification and restriction of MLF . HML only uses flexible types, which simplifies the type inference algorithm, but retains many interesting properties and features. The FPH system [35] introduces boxy monotypes into System F types. One critique of boxy type inference is that the impredicativity is deeply hidden in the algorithmic type inference rules, which makes it hard to understand the interac- tion between its predicative constraints and impredicative instantiations [31]. Application 1 n Type Inference of Higher-Ranked Types

1. Sugars for HM style polymorphic let expression

2. Conservative over the HM type system

3. Comparison with existing literatures

4. Interesting metatheory studies about the application mode formalized in Coq.

5. An algorithm; a translation to System F 28 Contributions

• A variant of bi-directional type checking with an application mode type information propagates from arguments to functions • A new design for type inference of higher-ranked types generalizes the Hindley-Milner type system supports syntactic sugar for polymorphic let • A System-F like calculus compatible with type application encoding type declaration

29 Application 2 for the Application Mode

30 Application 2

“It is possible, of course, to come up with examples where it would be beneficial to synthesize the argument types first and then use the resulting information to avoid type annotations in the function part of an application expression....Unfortunately this refinement does not help infer the type of polymorphic functions. For example, we cannot uniquely determine the type of x in the expression (fun[A](x) e) [Int] 3” *

* Benjamin C Pierce and David N Turner. Local type inference. TOPLAS, 22(1):1–44, 2000. 31 9 binders can be omitted in their system. This requires understanding how the applications in checked mode operate. In our system the above expression is not typeable, as a consequence of the information flow in the application mode. However, following our guideline for annotations leads to a program that can be type-checked with a smaller annotation: (f. f)(g :(a. a a). (g 1, g ’a’)). This means that our 8 ! work is not conservative over their work, which is due to the design choice of the application typing rule. Nevertheless, we can always rewrite programs using our guideline, which often leads to fewer/smaller annotations.

2.5 Application 2: More Expressive Type Applications The design choice of propagating arguments to functions was subject to consid- eration in the original work on local type inference [29], but was rejected due to possible non-determinism introduced by explicit type applications:

“It is possible, of course, to come up with examples where it would be beneficial to synthesize the argument types first and then use the result- ing information to avoid type annotations in the function part of an application expression....Unfortunately this refinement does not help in- fer the type of polymorphic functions. For example, we cannot uniquely determine the typeApplication of x in the expression 2 (fun[X](x) e)[Int]3.” [29] Therefore, as a response to this challenge, our second application is a variant nofA System Variant F. Ourof System development F with of the calculus shows that the application mode canMore actually Expressive work wellType with Applications calculi with explicit type applications. To explain the new design, consider the expression: (⇤a. x : a. x + 1) Int which…not istypeable not typeablein traditional in the traditional System F type system for System F. In System F the lambda abstractions do not account for the context of possible function applications.…using application Therefore mode, when we can type verify checkinga = theInt inner body of the lambda ab- straction,Use application the expression context xto+ track 1 is ill-typed,type equalities because all that is known is that x hasintroduced the (abstract) by type type applicationa. If we are allowed to propagate type information from arguments32 to functions, then we can verify that a = Int and x + 1 is well-typed. The key insight in the new type system is to use application contexts to track type equalities induced by type applications. This enables us to type check expressions such as the body of the lambda above (x+1). Therefore, back to the problematic expression (fun[X](x) e)[Int] 3, the type of x can be inferred as either X or Int since they are actually equivalent.

Sugar for type synonyms. In the same way that we can regard let expressions as syntactic sugar, in the new type system we further gain built-in type synonyms for free.Atype synonym is a new name for an existing type. Type synonyms are common in languages such as Haskell. In our calculus a simple form of type synonyms can be desugared as follows: Application 2 n A Variant of System F with More Expressive Type Applications

(fun[A](x) e) [Int] 3

x:A or x:Int

33 9

binders can be omitted in their system. This requires understanding how the applications in checked mode operate. In our system the above expression is not typeable, as a consequence of the information flow in the application mode. However, following our guideline for annotations leads to a program that can be type-checked with a smaller annotation: (f. f)(g :(a. a a). (g 1, g ’a’)). This means that our 8 ! work is not conservative over their work, which is due to the design choice of the application typing rule. Nevertheless, we can always rewrite programs using our guideline,10 which often leads to fewer/smaller annotations.

2.5Sugar Application for Type Synonyms. 2: MoreIn Expressive the same way Type that we Applications can regard let expressions as syntactic sugar, in the new type system we further gain built-in type synonyms The design choice of propagating arguments to functions was subject to consid- for free.Atype synonym is a new name for an existing type. Type synonyms eration in the original work on local type inference [29], but was rejected due to are common in languages such as Haskell. In our calculus a simple form of type possible non-determinism introduced by explicit type applications: synonyms can be desugared as follows: type“Ita is= possible,A in e of( course,⇤a. e) toA come up with examples where it would be Onebeneficial practical to synthesize benefit of the such argument syntactic types sugar first is andthat then it enables use the a result- direct en- codinging of information a SystemApplication F-like to avoid language type with annotations 2 declarations in the (including function type-synonyms). part of an Althoughapplication declarations expression....Unfortunately are often viewed as a this routine refinement extension does to not a calculus, help in- and arefer not the formally type of studied, polymorphic they are functions. highly relevant For example, in practice. we cannot Therefore, uniquely a more n A Variantrealisticdetermineof formalization System the type F ofwith of ax programmingin the expression language(fun[X should](x) e)[ directlyInt]3.” account[29] for More Expressive Type Applications declarations.Therefore, By as a providing response10 a to way this to challenge, encode declarations, our second application our new calculus is a variant en- ofables System a simple F. Our way development to formalize of declarations. the calculus shows that the application mode 1. Sugar for type synonyms type a = A in e (⇤a. e) A can actually work well with calculi with explicit type applications. To explain Type Abstraction. The typeOne equalities practical introduced benefit of such by syntactic type applications sugar is that may it enables seem a direct en- 2. Preservethelike new we are design,System breaking considerF type System abstractioncoding the expression: ofF a type System abstraction. F-like language However, with declarations we argue (including that type-synonyms).type abstraction(⇤a. x :isa still. x supported+ 1) AlthoughInt by declarations our System are F often variant. viewed For as a example: routine extension to a calculus, and are not formally studied, they are highly relevant in practice. Therefore, a more whichlet inc is not= ⇤ typeablea. x : a inrealistic. thex +1 traditional formalizationin inc Int type ofe a programmingsystem for System language shouldF. In directlySystem account for F the lambda abstractionsdeclarations. do not By account providing for a the way context to encode of declarations, possible function our new calculus en- (after desugaring) does ablesnot type-check, a simple way to as formalize in a System-F declarations. like language. In our applications.type system lambda Therefore abstractions when type that checking are immediatelly the inner body applied34 of to the an lambda argument, ab- straction,and unapplied the expression lambdaType abstractionsx + abstraction. 1 is ill-typed, behaveThe type because di equalities↵erently. all introduced that Unapplied is known by type lambda applications is that ab-x may seem hasstractions the (abstract) are just type like Systemlikea. we are F abstractionsbreaking System and F type retain abstraction. type abstraction. However, we The argue that type abstraction is still supported by our System F variant. For example: exampleIf we are above allowed illustrates to propagate this. In type contrast information the typeable from example arguments(⇤ toa. functions,x : a. let id = ⇤a. x : a. x +1in id Int e thenx + 1) weInt can, which verify uses that aa lambda= Int and abstractionx + 1 is well-typed. directly applied The key to an insight argument, in the new type system is to use(after application desugaring) contexts does not type-check, to track type as in a equalities System-F like induced language. In our can be regarded as the desugaredtype system expression lambda abstractions for type thata = areInt immediatellyin x : a applied. x +1 to an. argument, by type applications. Thisand unapplied enables lambda us to type abstractions check behave expressions di↵erently. such Unapplied as the lambda ab- body3 A of Polymorphicthe lambda abovestractions Language (x+1). are Therefore, just like with System back Higher-Ranked F to abstractions the problematic and retain Types expression type abstraction. The (fun[X](x) e)[Int] 3, theexample type above of x can illustrates be inferred this. In contrast as either theX typeableor Int examplesince they(⇤a. x : a. are actually equivalent. x + 1) Int, which uses a lambda abstraction directly applied to an argument, This section first presentscan a be declarative, regarded assyntax-directed the desugared expressiontype system for type fora = aInt lambdain x : a . x +1. calculus with implicit higher-ranked polymorphism. The interesting aspects about Sugar for type synonyms. In the same way that we can regard let expressions as the new type system are:3 1) A the Polymorphic typing rules, Language which employ with aHigher-Ranked combination of Types syntacticinference andsugar, application in the new modes; type system2) the novel we further subtypinggain relation built-in under type synonyms an appli- This section first presents a declarative, syntax-directed type system for a lambda forcation free context..Atype Later, synonym we proveis a new our name type system for an is existing type-safe type. by Type a type synonyms directed are common in languagescalculus such with as Haskell. implicit higher-ranked In our calculus polymorphism. a simple The form interesting of type aspects about translation to System F[the16, new27] in type Section system3.4 are:. Finally 1) the typing an algorithmic rules, which type employ system a combination of synonymsis discussed can in be Section desugared3.5inference. as follows: and application modes; 2) the novel subtyping relation under an appli- cation context. Later, we prove our type system is type-safe by a type directed translation to System F [16]. in Section 3.4. Finally an algorithmic type system 3.1 Syntax is discussed in Section 3.5. The syntax of the language is: 3.1 Syntax

Expr The syntax ofe the::= languagex n is:x : A. e x. e e1 e2 | | | | Type ExprA, B ::= a A B a.Ae ::=Intx n x : A. e x. e e1 e2 | ! | 8 | | | | | Monotype Type⌧ ::= a ⌧1 A,⌧2 B, C,Int D ::= a A B a.A Int | ! | | ! | 8 | Monotype ⌧ ::= a ⌧1 ⌧2 Int Typing Context ::= ? ,x: A | ! | Typing Context| ::= ? ,x: A Application Context ::= ? ,A | Application Context| ::= ? ,A | Expressions. Expressions e include variables (x), integers (n), annotated lambda abstractions (x : A. e), lambda abstractions (x. e), and applications (e1 e2). Letters x, y, z are used to denote term variables. Notably, the syntax does not include a let expression (let x = e1 in e2). Let expressions can be regarded as the standard syntax sugar (x. e2) e1, as illustrated in more detail later. Application 2 n A Variant of System F with More Expressive Type Applications10

1. Sugar for type synonyms type a = A in e (⇤a. e) A One practical benefit of such syntactic sugar is that it enables a direct en- 2. Preserve System F type abstractioncoding of a System F-like language with declarations (including type-synonyms). Although declarations are often viewed as a routine extension to a calculus, and 3. Metatheory studies formalizedare not formallyin Coq. studied, they are highly relevant in practice. Therefore, a more type safety, uniqueness realisticof typing formalization of a programming language should directly account for declarations. By providing a way to encode declarations, our new calculus en- ables a simple way to formalize declarations. 35 Type abstraction. The type equalities introduced by type applications may seem like we are breaking System F type abstraction. However, we argue that type abstraction is still supported by our System F variant. For example: let id = ⇤a. x : a. x +1in id Int e (after desugaring) does not type-check, as in a System-F like language. In our type system lambda abstractions that are immediatelly applied to an argument, and unapplied lambda abstractions behave di↵erently. Unapplied lambda ab- stractions are just like System F abstractions and retain type abstraction. The example above illustrates this. In contrast the typeable example (⇤a. x : a. x + 1) Int, which uses a lambda abstraction directly applied to an argument, can be regarded as the desugared expression for type a = Int in x : a . x +1.

3 A Polymorphic Language with Higher-Ranked Types

This section first presents a declarative, syntax-directed type system for a lambda calculus with implicit higher-ranked polymorphism. The interesting aspects about the new type system are: 1) the typing rules, which employ a combination of inference and application modes; 2) the novel subtyping relation under an appli- cation context. Later, we prove our type system is type-safe by a type directed translation to System F [16]. in Section 3.4. Finally an algorithmic type system is discussed in Section 3.5.

3.1 Syntax The syntax of the language is:

Expr e ::= x n x : A. e x. e e1 e2 | | | | Type A, B, C, D ::= a A B a.A Int | ! | 8 | Monotype ⌧ ::= a ⌧1 ⌧2 Int | ! | Typing Context ::= ? ,x: A | Application Context ::= ? ,A | Expressions. Expressions e include variables (x), integers (n), annotated lambda abstractions (x : A. e), lambda abstractions (x. e), and applications (e1 e2). Letters x, y, z are used to denote term variables. Notably, the syntax does not include a let expression (let x = e1 in e2). Let expressions can be regarded as the standard syntax sugar (x. e2) e1, as illustrated in more detail later. Discussion

36 Discussion

• Combine application and checked mode

• Additional constructs: pairs

• Encoding declarations in dependent type systems*

See our full paper if you are • Related work interested! * Paula Severi and Erik Poll. Pure type systems with definitions. Logical Foundations of Computer Science, pages 316–328, 1994. 37 Thanks!

38 Let Arguments Go First

Ningning Xie, Bruno C. d. S. Oliveira The University of Hong Kong

ESOP 2018, Thessaloniki, Greece 2018-04-17

39