Handling polymorphic algebraic eﬀects

. Algebraic eﬀects and handlers are a powerful abstraction mechanism to represent and implement control eﬀects. In this work, we study their extension with parametric polymorphism that allows ab-stracting not only expressions but also eﬀects and handlers. Although polymorphism makes it possible to reuse and reason about eﬀect implementations more eﬀectively, it has long been known that a naive combination of polymorphic eﬀects and let-polymorphism breaks type safety. Although type safety can often be gained by restricting let-bound expressions—e.g., by adopting value restriction or weak polymorphism— we propose a complementary approach that restricts handlers instead of let-bound expressions. Our key observation is that, informally speaking, a handler is safe if resumptions from the handler do not interfere with each other. To formalize our idea, we deﬁne a call-by-value lambda calculus λ leteﬀ that supports let-polymorphism and polymorphic algebraic eﬀects and handlers, design a type system that rejects interfering handlers, and prove type safety of our calculus.


Introduction
Algebraic effects [20] and handlers [21] are a powerful abstraction mechanism to represent and implement control effects, such as exceptions, interactive I/O, mutable states, and nondeterminism.They are growing in popularity, thanks to their success in achieving modularity of effects, especially the clear separation between their interfaces and their implementations.An interface of effects is given as a set of operations-e.g., an interface of mutable states consists of two operations, namely, put and get-with their signatures.An implementation is given by a handler H , which provides a set of interpretations of the operations (called operation clauses), and a handle-with expression handle M with H associates effects invoked during the computation of M with handler H . Algebraic effects and handlers work as resumable exceptions: when an effect operation is invoked, the run-time system tries to find the nearest handler that handles the invoked operation; if it is found, the corresponding operation clause is evaluated by using the argument to the operation invocation and the continuation up to the handler.The continuation gives the ability to resume the computation from the point where the operation was invoked, using the result from the operation clause.Another modularity that algebraic effects provide is flexible composition: multiple algebraic effects can be combined freely [13].
In this work, we study an extension of algebraic effects and handlers with another type-based abstraction mechanism-parametric polymorphism [22].In general, parametric polymorphism is a basis of generic programming and enhance code reusability by abstracting expressions over types.This work allows abstracting not only expressions but also effect operations and handlers, which makes it possible to reuse and reason about effect implementations that are independent of concrete type representations.Like in many functional languages, we introduce polymorphism in the form of let-polymorphism for its practically desirable properties such as decidable typechecking and type inference.
As is well known, however, a naive combination of polymorphic effects and let-polymorphism breaks type safety [23,11].Many researchers have attacked this classical problem [23,17,1,12,24,10,2,14], and their common idea is to restrict the form of let-bound expressions.For example, value restriction [23,24], which is the standard way to make ML-like languages with imperative features and let-polymorphism type safe, allows only syntactic values to be polymorphic.
In this work, we propose a new approach to achieving type safety in a language with let-polymorphic and polymorphic effects and handlers: the idea is to restrict handlers instead of let-bound expressions.Since a handler gives an implementation of an effect, our work can be viewed as giving a criterion that suggests what effects can cooperate safely with (unrestricted) let-polymorphism and what effects cannot.Our key observation for type safety is that, informally speaking, an invocation of a polymorphic effect in a let-bound expression is safe if resumptions in the corresponding operation clause do not interfere with each other.We formalize this discipline into a type system and show that typeable programs do not get stuck.
Our contributions are summarized as follows.
-We introduce a call-by-value, statically typed lambda calculus λ let eff that supports let-polymorphism and polymorphic algebraic effects and handlers.The type system of λ let eff allows any let-bound expressions involving effects to be polymorphic, but, instead, disallows handlers where resumptions interfere with each other.
-To give the semantics of λ let eff , we formalize an intermediate language λ Λ eff wherein type information is made explicit and define a formal elaboration from λ let eff to λ Λ eff .-We prove type safety of λ let eff by type preservation of the elaboration and type soundness of λ Λ eff .
We believe that our approach is complementary to the usual approach of restricting let-bound expressions: for handlers that are considered unsafe by our criterion, the value restriction can still be used.The rest of this paper is organized as follows.Section 2 provides an overview of our work, giving motivating examples of polymorphic effects and handlers, a problem in naive combination of polymorphic effects and let-polymorphism, and our solution to gain type safety with those features.Section 3 defines the surface language λ let eff , and Section 4 defines the intermediate language λ Λ eff and the elaboration from λ let eff to λ Λ eff .We also state that the elaboration is typepreserving and that λ Λ eff is type sound in Section 4. Finally, we discuss related work in Section 5 and conclude in Section 6.The proofs of the stated properties and the full definition of the elaboration are given in Appendix.

Overview
We start with reviewing how monomorphic algebraic effects and handlers work through examples and then extend them to a polymorphic version.We also explain why polymorphic effects are inconsistent with let-polymorphism, if naively combined, and how we resolve it.

Monomorphic algebraic effects and handlers
Exception.Our first example is exception handling, shown in an ML-like language below.
1 effect fail : unit ֒→ unit 2 3 let div100 (x:int) : int = 4 if x = 0 then (#fail(); -1) 5 else 100 / x 6 7 let f (y:int) : int option = 8 handle (div_100 y) with 9 return z → Some z 10 fail z → None Some and None are constructors of datatype α option.Line 1 declares an effect operation fail, which signals that an anomaly happens, with its signature unit ֒→ unit, which means that the operation is invoked with the unit value (), causes some effect, and may return the unit value.The function div100, defined in Lines 3-5, is an example that uses fail; it returns the number obtained by dividing 100 by argument x if x is not zero; otherwise, if x is zero, it raises an exception by calling effect operation fail. 3In general, we write #op(M ) for invoking effect operation op with argument M .The function f (Lines 7-10) calls div 100 inside a handle-with expression, which returns Some n if div 100 returns integer n normally and returns None if it invokes fail.
An expression of the form handle M with H handles effect operations invoked in M (which we call handled expression) according to the effect interpretations given by handler H .A handler H consists of two parts: a single return clause and zero or more operation clauses.A return clause return x → M ′ will be executed if the evaluation of M results in a value v .Then, the value of M ′ (where x is bound to v ) will be the value of the entire handle-with expression.For example, in the program above, if a nonzero number n is passed to f, the handle-with expression would return Some (100/n) because div100 n returns 100/n.An operation clause op x → M ′ defines an implementation of effect op: if the evaluation of handled expression M invokes effect op with argument v , expression M ′ will be evaluated after substituting v for x and the value of M ′ will be the value of the entire handle-with expression.In the program example above, if zero is given to f, then None will be returned because div100 0 invokes fail.
As shown above, algebraic effect handling is similar to exception handling.However, a distinctive feature of algebraic effect handling is that it allows resumption of the computation from the point where an effect operation was invoked.The next example demonstrates such an ability of algebraic effect handlers.

Choice.
The next example is effect choose, which returns one of the given two arguments.
) is a pair expression, and fst is the first projection function.The first line declares that effect choose is for choosing integers.The handled expression #choose(1,2) + #choose (10,20) intuitively suggests that there would be four possible results-11, 21, 12, and 22-depending on which value each invocation of choose returns.The handler in this example always chooses the first element of a given pair 4 and returns it by using a resume expression, and, as a result, the expression in Lines 3-5 evaluates to 11.
A resumption expression resume M in an operation clause makes it possible to return a value of M to the point where an effect operation was invoked.This behavior is realized by constructing a delimited continuation from the point of the effect invocation up to the handle-with expression that deals with the effect and passing the value of M to the continuation.We illustrate it by using the program above.When the handled expression #choose(1,2) + #choose (10,20) is evaluated, continuation (10,20) is constructed.Then, the body resume (fst x) of the operation clause is evaluated after binding x to the invocation argument (1,2).Receiving the value 1 of fst (1,2), the resumption expression passes it to the continuation c and c[1] = 1 + #choose (10,20) is evaluated under the same handler.Next, choose is invoked with argument (10,20).Similarly, continuation c ′ def = 1 + [ ] is constructed and the operation clause for choose is executed again.Since fst (10,20) evaluates to 10, c ′ [10] = 1 + 10 is evaluated under the same handler.Since the return clause returns what it receives, the entire expression evaluates to 11.
Finally, we briefly review how an operation clause involving resumption expressions is typechecked [13,3,16].Let us consider operation clause op(x) → M for op of type signature A ֒→ B. The typechecking is performed as follows.First, argument x is assigned the domain type A of the signature as it will be bound to an argument of an effect invocation.Second, for resumption expression resume M ′ in M , (1) M ′ is required to have the codomain type B of the signature because its value will be passed to the continuation as the result of the invocation and (2) the resumption expression is assigned the same type as the return clause.Third, the type of the body M has to be the same as that of the return clause because the value of M is the result of the entire handle-with expression.For example, the above operation clause for choose is typechecked as follows: first, argument x is assigned type int × int; second, it is checked whether the argument fst x of the resumption expression has int, the codomain type of choose; third, it is checked whether the body resume (fst x) of the clause has the same type as the return clause, i.e., int.If all the requirements are satisfied, the clause is well typed.

Polymorphic algebraic effects and handlers
This section discusses motivation for polymorphism in algebraic effects and handlers.There are two ways to introduce polymorphism: by parameterized effects and by polymorphic effects.
The former is used to parameterize the declaration of an effect by types.For example, one might declare: An invocation #choose involves a parameterized effect of the form A choose (where A denotes a type), according to the type of arguments: For example, #choose(true,false) has the effect bool choose and #choose(1,-1) has int choose.Handlers are required for each effect A choose.
The latter is used to give a polymorphic type to an effect.For example, one may declare effect choose : ∀α.α × α ֒→ α In this case, the effect can be invoked with different types, but all invocations have the same effect choose.One can implement a single operation clause that can handle all invocations of choose, regardless of argument types.Koka supports both styles [16] (with the value restriction); we focus, however, on the latter in this paper.A type system for parameterized effects lifting the value restriction is studied by Kammar and Pretnar [14] (see Section 5 for comparison).
In what follows, we show a polymorphic version of the examples we have seen, along with brief discussions on how polymorphic effects help with reasoning about effect implementations.Other practical examples of polymorphic effects can be found in Leijen's work [16].
Polymorphic exception.First, we extend the exception effect fail with polymorphism.
The polymorphic type signature of effect fail ∀ , given in Line 1, means that the codomain type α can be any.Thus, we do not need to append the dummy value -1 to the invocation of fail ∀ by instantiating the bound type variable α with int (the shaded part).
Choice.Next, let us make choose polymorphic.The function random walk implements random walk; it takes the current coordinate x, chooses whether it stops, and, if it decides to continue, recursively calls itself with a new coordinate.In the definition, choose ∀ is used twice with different types: bool and int.Lines 11-12 give choose ∀ an interpretation, which calls rand to obtain a random float, 5 and returns either the first or the second element of y.
Typechecking of operation clauses could be extended in a straightforward manner.That is, an operation clause op(x) → M for an effect operation of signature ∀α.A ֒→ B would be typechecked as follows: first, α is locally bound in the clause and x is assigned type A; second, an argument of a resumption expression must have type B (which may contain type variable α); third, M must have the same type as that of the return clause (its type cannot contain α as α is local) under the assumption that resumption expressions have the same type as the return clause.For example, let us consider typechecking of the above operation clause for choose ∀ .First, the typechecking algorithm allocates a local type variable α and assigns type α × α to y.The body has two resumption expressions, and it is checked whether the arguments fst y and snd y have the codomain type α of the signature.Finally, it is checked whether the body is typed at int assuming that the resumption expressions have type int.The operation clause meets all the requirements, and, therefore, it would be well typed.
An obvious advantage of polymorphic effects is reusability.Without polymorphism, one has to declare many versions of choose for different types.
Another pleasant effect of polymorphic effects is that, thanks to parametricity, inappropriate implementations for an effect operation can be excluded.For example, it is not possible for an implementation of choose ∀ to resume with values other than the first or second element of y.In the monomorphic version, however, it is possible to resume with any integer, as opposed to what the name of the operation suggests.A similar argument applies to fail ∀ ; since the codomain type is α, which does not appear in the domain type, it is not possible to resume!In other words, the signature ∀α. unit ֒→ α enforces that no invocation of fail ∀ will return.

Problem in naive combination with let-polymorphism
Although polymorphic effects and handlers provide an ability to abstract and restrict effect implementations, one may easily expect that their unrestricted use with naive let-polymorphism, which allows any let-bound expressions to be polymorphic, breaks type safety.Indeed, it does.
We develop a counterexample, inspired by Harper and Lillibridge [11], below.
effect get_id : ∀α. unit ֒→ (α → α) let f () : int = let g = #get_id() in (* g : ∀α.α → α *) if (g true) then ((g 0) + 1) else 2 The function f first binds g to the invocation result of op.The expression #get id() is given type α → α and the naive let-polymorphism would assign type scheme ∀α.α → α to g, which makes both g true and g 0 (and thus the definition of f) well typed.An intended use of f is as follows: handle f () with return x → x get_id y → resume (λz.z) The operation clause for get id resumes with the identity function λz.z.It would be well typed under the typechecking procedure described in Section 2.2 and it safely returns 1.
However, the following strange expression handle f () with return x → x get_id y → resume (λz1.(resume (λz2.z1)); z1) will get stuck, although this expression would be well typed: both λz1.• • • ;z1 and λz2.z1 could be given type α → α by assigning both z1 and z2 type α, which is the type variable local to this clause.Let us see how the evaluation gets stuck in detail.When the handled expression f () invokes effect get id, the following continuation will be constructed: Next, the body of the operation clause get id is evaluated.It immediately resumes and reduces to Here, the hole in c ′ is filled by function (λz2.true), which returns a Boolean value, though the hole is supposed to be filled by a function of ∀α.α → α.This weird gap triggers a run-time error: true in if (g true) then ((g 0) + 1) else 2 with . . .−→ * handle if true then (((λz2.true)0) + 1) else 2 with . . .−→ handle ((λz2.true)0) + 1 with . . .−→ handle true + 1 with . . .We stop here because true + 1 cannot reduce.

Our solution
A standard approach to this problem is to restrict the form of let-bound expressions by some means such as the (relaxed) value restriction [23,24,10] or weak polymorphism [1,12].This approach amounts to restricting how effect operations can be used.
In this paper, we seek for a complementary approach, which is to restrict how effect operations can be implemented. 6More concretely, we develop a type system such that let-bound expressions are polymorphic as long as they invoke only "safe" polymorphic effects and the notion of safe polymorphic effects is formalized in terms of typing rules (for handlers).
To see what are "safe" effects, let us examine the above counterexample to type safety.The crux of the counterexample is that 1. continuation c uses g polymorphically, namely, as bool → bool in g true and as int → int in g 1; 2. c is invoked twice; and 3. the use of g as bool → bool in the first invocation of c-where g is bound to λz1.• • • ; z1-"alters" the type of λz2.z1 (passed to resume) from α → α to α → bool, contradicting the second use of g as int → int in the second invocation of c.
The last point is crucial-if λz2.z1 were, say, λz2.z2, there would be no influence from the first invocation of c and the evaluation would succeed.The problem we see here is that the naive type system mistakenly allows interference between the arguments to the two resumptions by assuming that z1 and z2 share the same type.
Based on this observation, the typing rule for resumption is revised to disallow interference between different resumptions by separating their types: for each resume M in the operation clause for op : ∀α 1 • • • α n .A ֒→ B, M has to have type B ′ obtained by renaming all type variables α i in B with fresh type variables α ′ i .In the case of get id, the two resumptions should be called with β → β and γ → γ for fresh β and γ; for the first resume to be well typed, z1 has to be of type β, although it means that the return type of λz2.z1 (given to the second resumption) is β, making the entire clause ill typed, as we expect.If a clause does not have interfering resumptions like get id y → resume (λz1.z1) or get id y → resume (λz1.(resume (λz2.z2));z1), it will be well typed.
3 Surface language: λ let eff We define a lambda calculus λ let eff that supports let-polymorphism, polymorphic algebraic effects, and handlers without interfering resumptions.This section introduces the syntax and the type system of λ let eff .The semantics is given by a formal elaboration to intermediate calculus λ Λ eff , which will be introduced in Section 4.

Effect operations op
Type variables α, β, γ Effects ǫ ::= sets of effect operations Base types

Syntax
The syntax of λ let eff is given in Figure 1.Effect operations are denoted by op and type variables by α, β, and γ.An effect, denoted by ǫ, is a finite set of effect operations.We write for the empty effect set.A type, denoted by A, B , C , and D , is a type variable; a base type ι, which includes, e.g., bool and int; or a function type A → ǫ B , which is given to functions that take an argument of type A and compute a value of type B possibly with effect ǫ.A type scheme σ is obtained by abstracting type variables.Terms, denoted by M , consist of variables; constants (including primitive operations); lambda abstractions λx .M , which bind x in M ; function applications; let-expressions let x = M 1 in M 2 , which bind x in M 2 ; effect invocations #op(M ); handle-with expressions handle M with H ; and resumption expressions resume M .All type information in λ let eff is implicit; thus the terms have no type annotations.A handler H has a single return clause return x → M , where x is bound in M , and zero or more operation clauses of the form op(x ) → M , where x is bound in M .A typing context Γ binds a sequence of variable declarations x : σ and type variable declarations α.
We introduce the following notations used throughout this paper.We write ∀ α i∈I .A for ∀ α 1 ....∀ α n .A where I = {1, ..., n}.We often omit indices (i and j ) and index sets (I and J ) if they are not important: e.g., we often abbreviate ∀ α i∈I .A to ∀ α I .A or even to ∀ α.A. Similarly, we use a bold font for other sequences (A i∈I for a sequence of types, v i∈I for a sequence of values, etc.).We sometimes write {α} to view the sequence α as a set by ignoring the order.Free type variables ftv (σ) in a type scheme σ and type substitution B [A/α] of A for type variables α in B are defined as usual (with the understanding that the omitted index sets for A and α are the same).
We suppose that each constant c is assigned a first-order closed type ty(c) of the form ι 1 → • • • → ι n and that each effect operation op is assigned a signature of the form ∀α.A ֒→ B , which means that an invocation of op with type instantiation C takes an argument of A[C /α] and returns a value of B [C /α].We also assume that, for ty (op) = ∀α.A ֒→ B , ftv (A) ⊆ {α} and ftv (B ) ⊆ {α}.

Type system
The type system of λ let eff consists of four judgments: well-formedness of typing contexts ⊢ Γ ; well formedness of type schemes Γ ⊢ σ; term typing judgment Γ ; R ⊢ M : A | ǫ, which means that M computes a value of A possibly with effect ǫ under typing context Γ and resumption type R (discussed below); and handler typing judgment which means that H handles a computation that produces a value of A with effect ǫ and that the clauses in H compute a value of B possibly with effect ǫ ′ under Γ and R.
A resumption type R contains type information for resumption.
Definition 1 (Resumption type).Resumption types in λ let eff , denoted by R, are defined as follows: If M is not a subterm of an operation clause, it is typechecked under R = none, which means that M cannot contain resumption expressions.Otherwise, suppose that M is a subterm of an operation clause op(x ) → M ′ that handles effect op of signature ∀α.A ֒→ B and computes a value of C possibly with effect ǫ.Then, M is typechecked under R = (α, x : A, B → ǫ C ), which means that argument x to the operation clause has type A and that resumptions in M are effectful functions from B to C with effect ǫ.Note that type variables α occur free only in A and B but not in C . Figure 2 shows the inference rules of the judgments (except for Γ ⊢ σ, which is defined by: Γ ⊢ σ if and only if all free type variables in σ are bound by Γ ).For a sequence of type schemes σ, we write Γ ⊢ σ if and only if every type scheme in σ is well formed under Γ .
Well-formedness rules for typing contexts, shown at the top of Figure 2, are standard.A typing context is well formed if it is empty (WF Empty) or a variable in the typing context is associated with a type scheme that is well formed in the remaining typing context (WF Var) and a type variable in the typing context is not declared (WF TVar).For typing context Γ , dom(Γ ) denotes the set of type and term variables declared in Γ .
Typing rules for terms are given in the middle of Figure 2. The first six rules are standard for the lambda calculus with let-polymorphism and a typeand-effect system.If a variable x is introduced by a let-expression and has type scheme ∀ α.A in Γ , it is given type A[B/α], obtained by instantiating type variables α with well-formed types B. If x is bound by other constructors (e.g., a lambda abstraction), x is always bound to a monomorphic type and both α and B are the empty sequence.Note that (TS Var) gives any effect ǫ to the typing judgment for x .In general, ǫ in judgment Γ ; R ⊢ M : A | ǫ means that the evaluation of M may invoke effect operations in ǫ.Since a reference to a variable Well-formed rules for typing contexts Typing rules involves no effect, it is given any effect; for the same reason, value constructors are also given any effect.The rule (TS Const) means that the type of a constant is given by (meta-level) function ty.The typing rules for lambda abstractions and function applications are standard in the lambda calculus equipped with a type-and-effect system.The rule (TS Abs) gives lambda abstraction λx .M function type A → ǫ ′ B if M computes a value of B possibly with effect ǫ ′ by using x of type A. The rule (TS App) requires that (1) the argument type of function part M 1 be equivalent to the type of actual argument M 2 and (2) effect ǫ ′ invoked by function M 1 be contained in the whole effect ǫ.The rule (TS Weak) allows weakening of effects.
The next two rules are mostly standard for algebraic effects and handlers.The rule (TS Op) is applied to effect invocations.Since λ let eff supports implicit polymorphism, an invocation #op(M ) of polymorphic effect op of signature ∀α.A ֒→ B also accompanies implicit type substitution of well-formed types C for α.Thus, the type of argument M has to be A[C /α] and the result of the invocation is given type B [C /α].In addition, effect ǫ contains op.The typeability of handle-with expressions depends on the typing of handlers (TS Handle), which will be explained below shortly.
The last typing rule (TS Resume) is the key to gaining type safety in this work.Suppose that we are given resumption type (α, x : A, B → ǫ C ). Intuitively, B → ǫ C is the type of the continuation for resumption and, therefore, argument M to resume is required to have type B .As we have discussed in Section 2, we avoid interference between different resumptions by renaming α, the type parameters to the effect operation, to fresh type variables β, in typechecking M .Freshness of β will be ensured when well-formedness of typing contexts Γ 1 , Γ 2 , β, . . . is checked at the leaves of the type derivation.The type variables α in the type of x , the parameter to the operation, are also renamed for x to be useful in M .To see why this renaming is useful, let us consider an extension of the calculus with pairs and typechecking of an operation clause for choose ∀ of signature ∀α.α × α ֒→ α: Variable x is assigned product type α × α for fresh type variable α and the body resume (fst x ) is typechecked under the resumption type (α, x : α × α, α → ǫ A) for some ǫ and A (see the typing rules for handlers for details).To typecheck resume (fst x ), the argument fst x is required to have type β, freshly generated for this resume.Without applying renaming also to x , the clause would not typecheck.Finally, (TS Resume) also requires that (1) the typing context contains α, which should have been declared at an application of the typing rule for the operation clause that surrounds this resume and (2) effect ǫ, which may be invoked by resumption of a continuation, be contained in the whole effect ǫ ′ .The binding x : D in the conclusion means that parameter x to the operation clause is declared outside the resumption expression.
The typing rules for handlers are standard [13,3,16].The rule (THS Return) for a return clause return x → M checks that the body M is given a type under the assumption that argument x has type A, which is the type of the handled expression.The effect ǫ stands for effects that are not handled by the operation clauses that follow the return clause and it must be a subset of the effect ǫ ′ that M may cause. 7A handler having operation clauses is typechecked by (THS Op), which checks that the body of the operation clause op(x ) → M for op of signature ∀α.C ֒→ D is typed at the result type B , which is the same as the type of the return clause, under the typing context extended with fresh assigned type variables α and argument x of type C , together with the resumption type (α, x : C , D → ǫ ′ B ).The effect ǫ ⊎ {op} in the conclusion means that the effect operation op is handled by this clause and no other clauses (in the present handler) handle it.Our semantics adopts deep handlers [13], i.e., when a handled expression invokes an effect operation, the continuation, which passed to the operation clause, is wrapped by the same handler.Thus, resumption may invoke the same effect ǫ ′ as the one possibly invoked by the clauses of the handler, hence D → ǫ ′ B in the resumption type.
Remark.The rule (TS Resume) allows only the type of the argument to an operation clause to be renamed.Thus, other variables bound by, e.g., lambda abstractions and let-expressions outside the resumption expression cannot be used as such a type.As a result, more care may be required as to where to introduce a new variable.For example, let us consider the following operation clause (which is a variant of the example of choose ∀ above).
choose ∀ (x ) → let y = fst x in resume y The variable x is assigned α × α first and the resumption requires y to be typed at fresh type variable β.This clause would be rejected in the current type system because fst x appears outside resume and, therefore, y is given type α, not β.This inconvenience may be addressed by moving down the let-binding in some cases: e.g., resume (let y = fst x in y) is well typed.
4 Intermediate language: λ Λ eff The semantics of λ let eff is given by a formal elaboration to an intermediate language λ Λ eff , wherein type abstraction and type application appear explicitly.We define the syntax, operational semantics, and type system of λ Λ eff and the formal elaboration from λ let eff to λ Λ eff .Finally, we show type safety of λ let eff via type preservation of the elaboration and type soundness of λ Λ eff .

Syntax
The syntax of λ Λ eff is shown in Figure 3. Values, denoted by v , consist of constants and lambda abstractions.Polymorphic values, denoted by w , are values abstracted over types.Terms, denoted by e, and handlers, denoted by h, are the same as those of λ let eff except for the following three points.First, type abstraction and type arguments are explicit in λ Λ eff : variables and effect invocations are accompanied by a sequence of types and let-bound expressions, resumption expressions, and operation clauses bind type variables.Second, a new term constructor of the form #op(σ, w , E ) is added.It represents an intermediate state in which an effect invocation is capturing the continuation up to the closest handler for op.Here, E is an evaluation context [6] and denotes a continuation to be resumed by an operation clause handling op.In the operational semantics, an operation invocation #op(A, v ) is first transformed to #op(A, v , [ ]) (where [ ] denotes the empty context or the identity continuation) and then it bubbles up by capturing its context and pushing it onto the third argument.Note that σ and w of #op(σ, w , E ) become polymorphic when it bubbles up from the body of a type abstraction.Third, each resumption expression resume α x .edeclares distinct (type) variables α and x to denote the (type) argument to an operation clause, whereas a single variable declared at op(x ) → M and implicit type variables are used for the same purpose in λ let eff .For example, the λ let eff operation clause choose ∀ (x ) → resume (fst x ) is translated to Λα.choose ∀ (x ) → resume β y.(fst y).This change simplifies the semantics.
Evaluation contexts, denoted by E α , are standard for the lambda calculus with call-by-value, left-to-right evaluation except for two points.First, they contain the form let x = Λα.E β in e 2 , which allows the body of a type abstraction to be evaluated.Second, the metavariable E for evaluation contexts is indexed by type variables α, meaning that the hole in the context appears under type abstractions binding α.For example, let x = Λα.lety = Λβ.[] in e 2 in e 1 is denoted by E α,β and, more generally, let x = Λβ J1 .E γ J 2 in e is denoted by (Here, β J1 , γ J2 stands for the concatenation of the two sequences β J1 and γ J2 .)If α is not important, we simply write E for E α .We often use the term "continuation" to mean "evaluation context," especially when it is expected to be resumed.
As usual, substitution e[w /x ] of w for x in e is defined in a capture-avoiding manner.Since variables come along with type arguments, the case for variables is defined as follows: Application of substitution [Λα I .v/x ] to x A J , where I = J , is undefined.We define free type variables ftv (e) and ftv (E ) in e and E , respectively, as usual.

Semantics
The semantics of λ Λ eff is given in the small-step style and consists of two relations: the reduction relation , which is for basic computation, and the evaluation relation −→, which is for top-level execution.Figure 4 shows the rules for these relations.In what follows, we write h return for the return clause of handler h, ops(h) for the set of effect operations handled by h, and h op for the operation clause for op in h.
Most of the reduction rules are standard [13,16].A constant application c 1 c 2 reduces to ζ(c 1 , c 2 ) (R Const), where function ζ maps a pair of constants to another constant.A function application (λx .e)v and a let-expression let x = Λα.v in e reduce to e[v /x ] (R Beta) and e[Λα.v/x ] (R Let), respectively.If a handled expression is a value v , the handle-with expression reduces to the body of the return clause where v is substituted for the parameter x (R Return).An effect invocation #op(A, v ) reduces to #op(A, v , [ ]) with the identity continuation, as explained above (R Op); the process of capturing its evaluation context is expressed by the rules (R OpApp1), (R OpApp2), (R OpOp), (R OpHandle), and (R OpLet).The rule (R OpHandle) can be applied only if the handler h does not handle op.The rule (R OpLet) is applied to a let-expression where #op(σ J , w , E ) appears under a type abstraction with bound type variables α I .Since σ J and w may refer to α I , the reduction result binds α I in both σ J and w .We write ∀ α I .σJ for a sequence ∀ α I .σj1 , . . ., ∀ α I .σjn of type schemes (where J = {j 1 , . . ., j n }).
The crux of the semantics is (R Handle): it is applied when #op(σ I , w , E ) reaches the handler h that handles op.Since the handled term #op(σ I , w , E ) is constructed from an effect invocation #op(A I , v ), if the captured continuation E binds type variables β J , the same type variables β J should have been added to A I and v along the capture.Thus, the handled expression on the left-hand side of the rule takes the form #op(∀ β J .A I , Λβ J .v , E β J ) (with the same type variables β J ).
The right-hand side of (R Handle) involves three types of substitution: continuation substitution [handle E β J with h/resume] ∀ β J .A I Λβ J .v for resumptions, type substitution for α I , and value substitution for x .We explain them one by one below.In the following, let h op = Λα I .op(x ) → e and E ′ β J = handle E β J with h.
Continuation substitution.Let us start with a simple case where the sequence β J is empty.Intuitively, continuation substitution [E ′ /resume] A I v replaces a resumption expression resume γ I z .e′ in the body e with E ′ [v ′ ], where v ′ is the value of e ′ , and substitutes A I and v (arguments to the invocation of op) for γ I and z , respectively.Therefore, assuming resume does not appear in e ′ , we define (resume (for fresh y).Note that the evaluation of e ′ takes place outside of E so that an invocation of an effect in e ′ is not handled by handlers in E .When β J is not empty, (The differences from the simple case are shaded.)The idea is to bind β J that appear free in A I and v by type abstraction at let and to instantiate with the same variables at y β J , where β J are bound by type abstractions in E β J .
Continuation substitution is formally defined as follows: Definition 2 (Continuation substitution).Substitution of continuation E β J for resumptions in e, written e[E β J /resume] ∀ β J .A I Λβ J .v , is defined in a captureavoiding manner, as follows (we describe only the important cases): The second and third clauses (for a handler) mean that continuation substitution is applied only to return clauses.
Type and value substitution.The type and value substitutions A I [⊥ J /β J ] and v [⊥ J /β J ], respectively, in (R Handle) are for (type) parameters in h op = Λα I .op(x ) → e.The basic idea is to substitute A I for α I and v for x -similarly to continuation substitution.We erase free type variables β J in A I and v by substituting the designated base type ⊥ for all of them.(We write A I [⊥ J /β J ] and v [⊥ J /β J ] for the types and value, respectively, after the erasure.) The evaluation rule is ordinary: Evaluation of a term proceeds by reducing a subterm under an evaluation context.

Type system
The type system of λ Λ eff is similar to that of λ let eff and has five judgments: wellformedness of typing contexts ⊢ Γ ; well formedness of type schemes Γ ⊢ σ; term typing judgment Γ ; r ⊢ e : A | ǫ; handler typing judgment Γ ; r ⊢ h : The first two are defined in the same way as those of λ let eff .The last judgment means that a term obtained by filling the hole of E with a term having A under Γ, α is typed at B under Γ and possibly involves effect ǫ.A resumption type r is similar to R but does not contain an argument variable.

Definition 3 (Resumption type). Resumption types in λ Λ
eff , denoted by r , are defined as follows: Fig. 5. Typing rules for terms in λ Λ eff .
The typing rules for terms, shown in Figure 5, and handlers, shown in the upper half of Figure 6, are similar to those of λ let eff except for a new rule (T OpCont), which is applied to an effect invocation #op(∀ β J .C I , Λβ J .v , E β J ) with a continuation.Let ty (op) = ∀α I .A ֒→ B .Since op should have been invoked with C I and v under type abstractions with bound type variables β J , the argument v has type A[C I /α I ] under the typing context extended with β J .Similarly, the hole of E β J expects to be filled with the result of the invocation, i.e., a value of B [C I /α I ].Since the continuation denotes the context before the evaluation, its result type matches with the type of the whole term.
The typing rules for continuations are shown in the lower half of Figure 6.They are similar to the corresponding typing rules for terms except that a subterm is replaced with a continuation.In (TE Let), the continuation let x = Λα.E in e has type ∀ α.σ ⊸ B because the hole of E appears inside the scope of α.
Fig. 6.Typing rules for handlers and continuations in λ Λ eff .

Elaboration
This section defines the elaboration from λ let eff to λ Λ eff .The important difference between the two languages from the viewpoint of elaboration is that, whereas the parameter of an operation clause is referred to by a single variable in λ let eff , it is done by one or more variables in λ Λ eff .Therefore, one variable in λ let eff is represented by multiple variables (required for each resume) in λ Λ eff .We use S , a mapping from variables to variables, to make the correspondence between variable names.We write S • {x → y} for the same mapping as S except that x is mapped to y.
Elaboration is defined by two judgments: term elaboration judgment Γ ; R ⊢ M : A | ǫ ⊲ S e, which denotes elaboration from a typing derivation of judgment Γ ; R ⊢ M : A | ǫ to e with S , and handler elaboration judgment Selected elaboration rules are shown in Figure 7; the complete set of the rules is found in the full version of the paper.The elaboration rules are straightforward except for the use of S .A variable x is translated to S (x ) (Elab Var) and, every time a new variable is introduced, S is extended: see the rules other than (Elab Var) and (Elab Handle).

Properties
We show type safety of λ let eff , i.e., a well-typed program in λ let eff does not get stuck, by proving (1) type preservation of the elaboration from λ let eff to λ Λ eff and ( 2) The first can be shown easily.We write ∅ also for the identity mapping for variables.
Theorem 1 (Elaboration is type-preserving) If M is a well-typed program of A, then ∅; none ⊢ M : A | ⊲ ∅ e and ∅; none ⊢ e : A | for some e.
We show the second-type soundness of λ Λ eff -via progress and subject reduction [25].We write ∆ for a typing context that consists only of type variables.Progress can be shown as usual.
Proof.By induction on the derivation of ∆; none ⊢ e : A | ǫ.
A key lemma to show subject reduction is type preservation of continuation substitution.

Lemma 2 (Continuation substitution). Suppose that
Proof.By mutual induction on the typing derivations.
Using the continuation substitution lemma as well as other lemmas, we show subject reduction.

Now, type safety of λ let
eff is obtained as a corollary of Theorems 1 and 2.
Corollary 1 (Type safety of λ let eff ).If M is a well-typed program of A, there exists some e such that ∅; none ⊢ M : A | ⊲ ∅ e and e does not get stuck.
5 Related work

Polymorphic effects and let-polymorphism
Many researchers have attacked the problem of combining effects-not necessarily algebraic-and let-polymorphism so far [23,17,1,12,24,10,2,14].In particular, most of them have focused on ML-style polymorphic references.The algebraic effect handlers dealt with in this paper seem to be unable to implement general ML-style references-i.e., give an appropriate implementation to a set of effect operations new with the signature ∀α.α ֒→ α ref, get with ∀α.α ref ֒→ α, and put with ∀α.α × α ref ֒→ unit for abstract datatype α ref-even without the restriction on handlers because each operation clause in a handler assigns type variables locally and it is impossible to share such type variables between operation clauses. 8Nevertheless, their approaches would be applicable to algebraic effects and handlers.
A common idea in the literature is to restrict the form of expressions bound by polymorphic let.Thus, they are complementary to our approach in that they restrict how effect operations are used whereas we restrict how effect operations are implemented.
Value restriction [23,24], a standard way adopted in ML-like languages, restricts polymorphic let-bound expressions to syntactic values.Garrigue [10] relaxes the value restriction so that, if a let-bound expression is not a syntactic value, type variables that appear only at positive positions in the type of the expression can be generalized.Although the (relaxed) value restriction is a quite clear criterion that indicates what let-bound expressions can be polymorphic safely and it even accepts interfering handlers, it is too restrictive in some cases.We give an example for such a case below.
In the definition of function f1, variable g is used polymorphically.Execution of this function under an appropriate handler would succeed, and in fact our calculus accepts it.By contrast, the (relaxed) value restriction rejects it because the let-bound expression #choose ∀ (fst,snd) is not a syntactic value and the type variable appear in both positive and negative positions, and so g is assigned a monomorphic type.A workaround for this problem is to make a function wrapper that calls either of fst or snd depending on the Boolean value chosen by choose ∀ : let f2 () = 8 One possible approach to dealing with ML-style references is to extend algebraic effects and handlers so that a handler for parameterized effects can be connected with dynamic resources [3].
let b = #choose ∀ (true,false) in let g = λx.if b then (fst x) else (snd x) in if g (true,false) then g (-1,1) else g (1,-1) However, this workaround makes the program complicated and incurs additional run-time cost for the branching and an extra call to the wrapper function.
Asai and Kameyama [2] study a combination of let-polymorphism with delimited control operators shift/reset [4].They allow a let-bound expression to be polymorphic if it invokes no control operation.Thus, the function f1 above would be rejected in their approach.
Another research line to restrict the use of effects is to allow only type variables unrelated to effect invocations to be generalized.Tofte [23] distinguishes between applicative type variables, which cannot be used for effect invocations, and imperative ones, which can be used, and proposes a type system that enforces restrictions that (1) type variables of imperative operations can be instantiated only with types wherein all type variables are imperative and (2) if a let-bound expression is not a syntactic value, only applicative type variables can be generalized.Leroy and Weis [17] allow generalization only of type variables that do not appear in a parameter type to the reference type in the type of a let-expression.To detect the hidden use of references, their type system gives a term not only a type but also the types of free variables used in the term.Standard ML of New Jersey (before ML97) adopted weak polymorphism [1], which was later formalized and investigated deeply by Hoang et al. [12].Weak polymorphism equips a type variable with the number of function calls after which a value of a type containing the type variable will be passed to an imperative operation.The type system ensures that type variables with positive numbers are not related to imperative constructs, and so such type variables can be generalized safely.In this line of research, the function f1 above would not typecheck because generalized type variables are used to instantiate those of the effect signature, although it could be rewritten to an acceptable one by taking care not to involve type variables in effect invocation.let f3 () = let g = if #choose ∀ (true,false) then fst then snd in if g (true,false) then g (-1,1) else g (1,-1) More recently, Kammar and Pretnar [14] show that parameterized algebraic effects and handlers do not need the value restriction if the type variables used in an effect invocation are not generalized.Thus, as the other work that restricts generalized type variables, their approach would reject function f1 but would accept f3.

Algebraic effects and handlers
Algebraic effects [20] are a way to represent the denotation of an effect by giving a set of operations and an equational theory that capture their properties.Algebraic effect handlers, introduced by Plotkin and Pretnar [21], make it possible to provide user-defined effects.Algebraic effect handlers have been gaining popularity owing to their flexibility and have been made available as libraries [13,26,15] or as primitive features of languages, such as Eff [3], Koka [16], Frank [18], and Multicore OCaml [5].In these languages, let-bound expressions that can be polymorphic are restricted to values or pure expressions.
Recently, Forster et al. [9] investigate the relationships between algebraic effect handlers and other mechanisms for user-defined effects-delimited control shift0 [19] and monadic reflection [7,8]-conjecturing that there would be no type-preserving translation from a language with delimited control or monadic reflection to one with algebraic effect handlers.It would be an interesting direction to export our idea to delimited control and monadic reflection.

Conclusion
There has been a long history of collaboration between effects and let-polymorphism.This work focuses on polymorphic algebraic effects and handlers, wherein the type signature of an effect operation can be polymorphic and an operation clause has a type binder, and shows that a naive combination of polymorphic effects and let-polymorphism breaks type safety.Our novel observation to address this problem is that any let-bound expression can be polymorphic safely if resumptions from a handler do not interfere with each other.We formalized this idea by developing a type system that requires the argument of each resumption expression to have a type obtained by renaming the type variables assigned in the operation clause to those assigned in the resumption.We have proven that a well-typed program in our type system does not get stuck via elaboration to an intermediate language wherein type information appears explicitly.
There are many directions for future work.The first is to address the problem, described at the end of Section 3, that renaming the type variables assigned in an operation clause to those assigned in a resumption expression is allowed for the argument of the clause but not for variables bound by lambda abstractions and let-expressions outside the resumption expression.Second, we are interested in incorporating other features from the literature on algebraic effect handlers, such as dynamic resources [3] and parameterized algebraic effects, and restriction techniques that have been developed for type-safe imperative programming with let-polymorphism such as (relaxed) value restriction [23,24,10].For example, we would like to develop a type system that enforces the non-interfering restriction only to handlers implementing effect operations invoked in polymorphic computation.We also expect that it is possible to determine whether implementations of an effect operation have no interfering resumption from the type signature of the operation, as relaxed value restriction makes it possible to find safely generalizable type variables from the type of a let-bound expression [10].Finally, we are also interested in implementing our idea for a language with effect handlers such as Koka [16] and in applying the idea of analyzing handlers to other settings such as dependent typing.

Errata
The following typographical errors in the ESOP'19 paper are fixed (the page numbers are those of the ESOP '19).
Page 363, Definition 1 "R ::= none | (α, A, B → ǫ C )" is corrected to "R ::= none | (α, x : A, B → ǫ C )". Page 367 "We define the syntax, operational semantics, and type system of λ let eff " is corrected to "We define ... of λ Λ eff ". page 370 "The basic idea is to substitute A I for β I " is corrected to "The basic idea is ... for α I ".A where I = {1, ..., n}.We often omit indices (i and j ) and index sets (I and J ) if they are not important: for example, we often abbreviate ∀ α i∈I .A to ∀ α I .A or even ∀ α.A. Similarly, we use a bold font for other sequences (A i∈I for a sequence of types, v i∈I for a sequence of values, and so on).We sometimes write {α} to view the sequence α as a set by ignoring the order.We also write ∀ α I .σJ for a sequence ∀ α I .σj1 , . . ., ∀ α I .σjn of type schemes (where J = {j 1 , . . ., j n }).

A Definition
Definition 4 (Domain of typing contexts).We define dom(Γ ) as follows.
Free type variables ftv (σ) in a type scheme σ and type substitution B [A/α] of A for type variables α in B are defined as usual.
Assumption 1 We suppose that each constant c is assigned a first-order closed type ty(c) of the form ι 1 → • • • → ι n and that each effect operation op is assigned a signature of the form ∀α.A ֒→ B .We also assume that, for ty (op) = ∀α.A ֒→ B , ftv (A) ⊆ {α} and ftv (B ) ⊆ {α}.
Suppose that, for any ι, there is a set K ι of constants of ι.
We write E for E α if α is not important.
Well-formed rules for typing contexts Definition 9 (Free type variables).We write ftv (e) and ftv (E ) for sets of type variables that occur free in e and E , respectively.The notion of free type variables is defined as usual.
Definition 10 (Substitution).Substitution e[A/α] of A for α in e is defined in a capture-avoiding manner as usual.Substitution e[w /x ] of polymorphic value w for variable x in e is also defined in a standard capture-avoiding manner: in particular, of continuation E β J for resumptions in e is defined in a capture-avoiding manner, as follows (we describe only important cases).
Definition 11 (Resumption type).We define resumption type r as follows. r We also define a set of type variables captured by a resume type: Definition 14 (Nonreducible terms).We write e −→ if there no terms e ′ such that e −→ e ′ .Γ