Hostname: page-component-78c5997874-ndw9j Total loading time: 0 Render date: 2024-11-20T01:30:02.941Z Has data issue: false hasContentIssue false

Signature restriction for polymorphic algebraic effects

Part of: ICFP20/21

Published online by Cambridge University Press:  27 May 2024

TARO SEKIYAMA
Affiliation:
National Institute of Informatics & SOKENDAI, Tokyo, Japan (e-mail: [email protected])
TAKESHI TSUKADA
Affiliation:
Chiba University, Chiba, Japan (e-mail: [email protected])
ATSUSHI IGARASHI
Affiliation:
Graduate School of Informatics, Kyoto University, Kyoto, Japan (e-mail: [email protected])
Rights & Permissions [Opens in a new window]

Abstract

The naive combination of polymorphic effects and polymorphic type assignment has been well known to break type safety. In the literature, there are two kinds of approaches to this problem: one is to restrict how effects are triggered and the other is to restrict how they are implemented. This work explores a new approach to ensuring the safety of the use of polymorphic effects in polymorphic type assignment. A novelty of our work is to restrict effect interfaces. To formalize our idea, we employ algebraic effects and handlers, where an effect interface is given by a set of operations coupled with type signatures. We propose signature restriction, a new notion to restrict the type signatures of operations and show that signature restriction ensures type safety of a language equipped with polymorphic effects and unrestricted polymorphic type assignment. We also develop a type-and-effect system to enable the use of both of the operations that satisfy and those that do not satisfy the signature restriction in a single program.

Type
Research Article
Creative Commons
Creative Common License - CCCreative Common License - BY
This is an Open Access article, distributed under the terms of the Creative Commons Attribution licence (https://creativecommons.org/licenses/by/4.0/), which permits unrestricted re-use, distribution and reproduction, provided the original article is properly cited.
Copyright
© The Author(s), 2024. Published by Cambridge University Press

1 Introduction

1.1 Background: Polymorphic type assignment with computational effects

Computational effects are pervasive in programming, including mutable memory cells, backtracking, exception handling, concurrency/parallelism, and I/O processing for terminals, files, networks, etc. These effects have a variety of roles: I/O processing enables interaction with external environments; memory manipulation and concurrency/parallelism make software efficient; and backtracking and exceptions provide structured operations that make it unnecessary to write boilerplate code. These effects have also been proven convenient in functional programming (Gordon et al., Reference Gordon, Milner and Wadsworth1979; Wadler, Reference Wadler1992; Peyton Jones and Wadler, Reference Peyton Jones and Wadler1993).

In return for convenience, however, computational effects can introduce weird, counterintuitive behavior into programs and complicate program reasoning and verification. For example, incorporating effects into dependent type theory could easily lead to (Pédrot and Tabareau, Reference Pédrot and Tabareau2020). This fact encourages dependent type systems to separate term-level computation from types (Xi, Reference Xi2007; Casinghino et al., Reference Casinghino, Sjöberg and Weirich2014; Swamy et al., Reference Swamy, Hritcu, Keller, Rastogi, Delignat-Lavaud, Forest, Bhargavan, Fournet, Strub, Kohlweiss, Zinzindohoue and Béguelin2016; Sekiyama and Igarashi, Reference Sekiyama and Igarashi2017; Ahman, Reference Ahman2017; Cong and Asai, Reference Cong and Asai2018). For program reasoning, the state transitions caused by effectful computations have to be tracked (Pitts and Stark, 1998; Ahmed et al., Reference Ahmed, Dreyer and Rossberg2009; Dreyer et al., Reference Dreyer, Neis and Birkedal2010).

These kinds of gaps between pure and effectful computations are also found in our target: polymorphic type assignment. Although pure expressions can safely be assigned polymorphic types (Leivant, Reference Leivant1983), unrestricted polymorphic type assignment to effectful expressions may break type safety. This problem with polymorphic type assignment has been discovered in call-by-value languages with polymorphic effects, which are effects caused by polymorphic operations. For example, ML-style references are an instance of polymorphic effects because the operations for memory cell creation, assignment, and dereference are polymorphic (Milner et al., Reference Milner, Tofte and Harper1990; Leroy et al., Reference Leroy, Doligez, Frisch, Garrigue, Rémy and Vouillon2020). Gordon et al. (Reference Gordon, Milner and Wadsworth1979) showed that the ML-style references cannot cooperate safely with unrestricted polymorphic type assignment owing to the polymorphism of the operations. Another example is control effects, which are triggered by control operators such as call/cc (Clinger et al., Reference Clinger, Friedman, Wand, Nivat and Reynolds1985) and shift/reset (Danvy and Filinski, Reference Danvy and Filinski1990). These operators can be assigned polymorphic types but the polymorphic control operators may cause unsafe behavior in unrestricted polymorphic type assignment (Harper and Lillibridge, Reference Harper and Lillibridge1993). This fault even occurs in let-polymorphic type assignment (Milner, Reference Milner1978) where quantifiers only appear at the outermost positions.

Many approaches to the safe use of polymorphic effects in polymorphic type assignment have been proposed (Tofte, Reference Tofte1990; Leroy and Weis, Reference Leroy and Weis1991; Appel and MacQueen, Reference Appel and MacQueen1991; Hoang et al., Reference Hoang, Mitchell and Viswanathan1993; Wright, Reference Wright1995; Garrigue, Reference Garrigue2004; Asai and Kameyama, Reference Asai and Kameyama2007; Kammar and Pretnar, Reference Kammar and Pretnar2017; Sekiyama and Igarashi, Reference Sekiyama and Igarashi2019). These approaches are classified into two groups. The first group—to which most of the approaches belong—aims at restricting how effects are triggered. For example, the value restriction (Tofte, Reference Tofte1990) restricts polymorphic expressions to be only values in order to prevent polymorphic expressions from triggering effects. The other group aims at restricting how effects are implemented. For example, Sekiyama and Igarashi (Reference Sekiyama and Igarashi2019) proposed a type system that does not restrict the use of effects and, instead, allows only the safe effects, i.e., the effects that do not cause programs to get stuck no matter how they are used. Their type system examines the implementations of effects to judge the safety of the effects.

1.2 Our work

This work explores a new approach to safe polymorphic type assignment for effectful call-by-value languages. A novelty of our approach lies in restriction on effect interfaces. In this work, the effect interfaces are represented by sets of operations coupled with type signatures. For example, an interface for exceptions consists of a single operation raise to raise an exception and its type signature $ \bf{\forall} \, \alpha {.} \, \mathsf{unit} \hookrightarrow \alpha $ , which means that raise takes the unit value as an argument and returns a value of any type $\alpha$ if the control gets back to the caller at all. Quantification in the signature not only provides the clients of the operation with flexibility—they can instantiate $\alpha$ with any desired type and put a call of raise in any context—but also constrains its implementations in that they have to abstract over types.

We discover that the abstract nature of type variables in the type signatures can ensure the safety of the polymorphic effects. Based on this finding, we propose a criterion that decides the safety of an effect only by examining the type signatures of its operations. For example, we can find raise safe by this criterion. Our criterion is simple in that it only mentions the occurrences of bound type variables $\alpha$ in a type signature, robust in that it is independent of how effects are implemented, and permissive in that it is met by many safe effects—including exception, nondeterminism, and input streaming. We call the restriction based on this criterion signature restriction.

To formalize our idea, we choose algebraic effects and handlers (Plotkin and Pretnar, Reference Plotkin and Pretnar2009, Reference Plotkin and Pretnar2013) as a means to represent effects. Algebraic effects and handlers are a programming mechanism to accommodate user-defined control effects in a modular way, splitting an effect into an interface (i.e., a set of operations with type signatures) and an interpretation. Since our idea is to restrict effect interfaces, we can incorporate signature restriction into the framework of algebraic effects and handlers naturally.

We provide two polymorphic type assignment systems for a $\lambda$ -calculus equipped with algebraic effects and handlers. The first is a simple polymorphic type system based on Curry-style System F (Leivant, Reference Leivant1983) (i.e., it supports implicit, full polymorphism Footnote 1 ). This type system allows arbitrary terms (rather than only values) that may invoke effects freely to be polymorphic. Despite the unrestricted use of effects, this type system is sound if signature restriction is enforced. The minimality of this simple type system reveals the essence of signature restriction. The second type assignment system is a polymorphic type-and-effect system. Using this system, we show that signature restriction can be applied to typecheck programs in which both safe and unsafe polymorphic effects may happen. Footnote 2

The contributions of our work are summarized as follows.

  • We define a $\lambda$ -calculus $\lambda_{\text{eff}}$ with algebraic effects and handlers and provide a type system that supports implicit full polymorphism and allows any effectful expression to be polymorphic. We formalize signature restriction for $\lambda_{\text{eff}}$ and prove soundness of the type system under the assumption that all operations satisfy signature restriction.

  • As a technical development to justify signature restriction, we equip the type system with Mitchell’s type containment (Mitchell, Reference Mitchell1988), which is an extension of type instantiation. In the literature (Peyton Jones et al., Reference Peyton Jones, Vytiniotis, Weirich and Shields2007; Dunfield and Krishnaswami, Reference Dunfield and Krishnaswami2013), the proof of type soundness of a calculus equipped with type containment rests on translation to another calculus, such as System F (Reynolds, Reference Reynolds1974; Girard, Reference Girard1972). Footnote 3 Unlike the prior work, we show soundness of our type system directly, i.e., without translation to any other calculus. As far as we know, this is the first work that proves soundness of a type system involving type containment without translation.

  • We extend $\lambda_{\text{eff}}$ and its type system with standard programming features such as products, sums, and lists to demonstrate the generality and extensibility of signature restriction.

  • We develop an effect system for $\lambda_{\text{eff}}$ , which enables a single program to use both safe and unsafe polymorphic effects. In this effect system, an expression can be polymorphic if all the effect operations performed by the expression satisfy signature restriction. It also indicates that signature restriction can cooperate with the value restriction naturally.

We employ implicit full polymorphism and type containment to show type soundness, but either of them makes even type checking undecidable (Wells, Reference Wells1994; Tiuryn and Urzyczyn, Reference Tiuryn and Urzyczyn1996). It is thus desirable to identify a subset of our system where type checking—and type inference as well hopefully—is decidable. To prove the feasibility of this idea, we implement an interpreter for a subset of the extended $\lambda_{\text{eff}}$ in which polymorphism is restricted to let-polymorphism (Milner, Reference Milner1978; Damas and Milner, Reference Damas and Milner1982) (the effect system is not supported either). This restriction on polymorphism ensures that both type checking and type inference are decidable, but it is still expressive so that all of the motivating well-typed examples in this article (except for those in Section 6, which rest on the effect system) are typechecked. The implementation is provided as the supplementary material; alternatively, it can also be found at: https://github.com/skymountain/MLSR .

Finally, we briefly relate our work with the relaxed value restriction (Garrigue, Reference Garrigue2004) here. It is similar to our signature restriction in that both utilize the occurrences of type variables to ensure soundness of polymorphic type assignment in the permissive use of polymorphic effects. Indeed, a strong version of signature restriction (which is introduced in Section 2.4) can be justified similarly to the relaxed value restriction. The strong signature restriction is, however, too restrictive and rejects many useful, safe effects. We generalize it to what we call signature restriction and prove its correctness with different techniques such as type containment. Readers are referred to Section 8.1 for further details.

1.3 Relation to the prior publication

This article revises and extends the paper presented at ICFP’20 (Sekiyama et al., Reference Sekiyama, Tsukada and Igarashi2020). In summary, the following are added.

  • The improvement of certain notations (e.g., for free type variables occurring negatively/positively/strictly positively).

  • A discussion about relaxing the signature restriction (Section 4.6.2).

  • A discussion about design decisions for adapting the signature restriction to effect systems (Section 6.3).

  • A reduction of the restriction on effect implementations (Sekiyama and Igarashi, Reference Sekiyama and Igarashi2019) to the signature restriction (Section 7).

1.4 Organization

The remainder of this article is organized as follows. We start with an overview of this work (Section 2) and then define our base calculus $\lambda_{\text{eff}}$ (Section 3). Section 4 introduces a polymorphic type system for $\lambda_{\text{eff}}$ , formalizes signature restriction, and shows soundness of the polymorphic type system under the assumption that all operations satisfy signature restriction. Section 5 extends $\lambda_{\text{eff}}$ , the polymorphic type system, and signature restriction with products, sums, and lists. Section 6 presents an effect system to allow programs to use both safe and unsafe effects. We finally relate the restriction on effect implementations to the signature restriction in Section 7, discuss other related work in Section 8, and conclude in Section 9.

In this article, we may omit the formal definitions of some well-known notions and the statements and proofs of auxiliary lemmas for type soundness. The full definitions, statements, and proofs are provided in Appendix.

2 Overview

This section presents an overview of our work. After reviewing algebraic effects and handlers, their extension to polymorphic effects, and why a naive extension results in unsoundness, we describe our approach of signature restriction and informally discuss why it resolves the unsoundness problem. All program examples in this article follow ML-like syntax.

2.1 Review: Algebraic effects and handlers

Algebraic effects and handlers (Plotkin and Pretnar, Reference Plotkin and Pretnar2009, Reference Plotkin and Pretnar2013) are a mechanism that enables users to define their own effects. They are successfully able to separate the syntax and semantics of effects. The syntax of an effect is given by a set of operations, which are used to trigger the effect. For example, exception is triggered by the operation raise and store manipulation is triggered by put and get, which are used to write to and read from, respectively, a store. The semantics is given by handlers, which decide how to interpret operations performed by effectful computation.

Our running example is nondeterministic computation which enumerates all of the possible outcomes (Plotkin and Pretnar, Reference Plotkin and Pretnar2009, Reference Plotkin and Pretnar2013). This computation utilizes two operations: select, which chooses an element from a given list, and fail, which signals that the current control flow is undesired and the computation should abort. Footnote 4 For simplicity, we fix the list element type to be the type int of integers here; the polymorphic version shall be discussed in Section 2.2.

For example, consider an implementation of a filtering function using these operations:

The first two lines declare the operations select and fail, which have the type signatures int list $\hookrightarrow$ int and unit $\hookrightarrow$ unit, respectively. A type signature $ A \hookrightarrow B $ of an operation signifies that the operation is called with an argument of type A and, when the control gets back to the caller, it receives a value of B. We refer to A and B as the parameter type and arity type, respectively (Plotkin and Pretnar, Reference Plotkin and Pretnar2008).

The function filter in Lines 4–12 operates select and fail to filter out the elements of a list l that do not meet a given predicate f. Now, let’s take a closer look at the body of the function, which consists of a single handlewith expression of the form handle M with H. This expression installs a handler H during the evaluation of M, which we refer to as the handled expression.

The handled expression (Lines 6–8) chooses an integer selected from the list l by calling select, tests whether the selected integer x satisfies f, and returns x if f x is true; otherwise, it aborts the computation by calling fail. We write $ {\textrm{#}} \mathsf{op} {(} {M} {)} $ to call operation $\mathsf{op}$ with argument M. We now explain the handler in Lines 10–12, which collects all the values in l that satisfy f as a list, along with an intuitive meaning of handlewith expressions.

The handler H in handle M with H consists of a single return clause and zero or more operation clauses. The return clause takes the form return x $\rightarrow$ M and computes the entire result M of the handlewith expression using the value of the handled expression, which M refers to by x. For example, the return clause in this example is return z $\rightarrow$ [z]. Because z will be bound to the result of the handled expression x, the entire result is the singleton list consisting of x. An operation clause of the form op x $\rightarrow$ M for an operation op decides how to interpret the operation op called by the handled expression. Variable x will be bound to the argument of the call to op and M is the entire result of the handlewith expression. For example, the operation clause fail z $\rightarrow$ [ $\,$ ] means that, if fail is called, the computation is aborted—similarly to exception handling—and the entire handlewith expression returns the empty list, meaning that there is no result satisfying f.

Unlike exception handling, which discards the continuation of where an exception is raised, handlers can resume computation from the point at which the operation was called. The ability to resume a computation suspended by the operation call provides algebraic effects and handlers with the expressive power to implement control effects (Bauer and Pretnar, Reference Bauer and Pretnar2015; Leijen, Reference Leijen2017; Forster et al., Reference Forster, Kammar, Lindley and Pretnar2019). In our language, we use the expression resume M to resume the computation of the handled expression with the value of M.

The operation clause for select enumerates all the possible outcomes by using resume. The clause first resumes the computation from the point at which select was called, with each integer y of a given list l as a return value of the call to select. The handled expression in the example calls select only once, so each resumed computation (which is performed under the same handler Footnote 5 ) returns either a singleton list (produced by the return clause) or the empty list (produced by the clause for fail). The next step after the completion of all the resumed computations is to concatenate their results. The two steps are expressed by concat (map l ( $\lambda$ y. resume y)), where the function concat concatenates a list of lists and map returns a new list obtained by applying a given function to each element of a given list.

More formally, the suspended computation is expressed as a delimited continuation (Felleisen, Reference Felleisen1988; Danvy and Filinski, Reference Danvy and Filinski1990), and resume simply invokes it. For example, let us consider evaluating in the last line. This reduces to the following expression:

where H denotes the same handler as that in the example. At the call to select, the run-time system constructs the following delimited continuation c

(where [] is the hole to be filled with a resumption argument), and then evaluates the operation clause for select. The resumption expression in the operation clause invokes the delimited continuation c after filling the hole with an integer in the list [3; 5; 10]. For the case of filling the hole with 3, the remaining computation c[3] to resume is:

Because 3 is an odd number, it satisfies the predicate ( $\lambda$ x. x mod 2 = 1), and therefore the final result of this computation is the singleton list [3]. The case of 5 behaves similarly and produces [5]. In the case of 10, because the even number 10 does not meet the given predicate, the remaining computation $c[\texttt{10}]$ would call fail and, from the operation clause for fail, the final result of $c[\texttt{10}]$ would be the empty list. The operation clause for select concatenates all of these resulting lists of the resumptions and finally returns [3; 5]. This is the behavior that we expect of filter exactly.

The handler in the example works even when select is called more than once, e.g.:

This program returns a list of the values of the handled expression that are computed with $(\texttt{x}, \texttt{y}) \in \{ \texttt{2}, \texttt{3} \} \times \{\texttt{10}, \texttt{20} \} $ such that the multiplication x * y does not exceed 50.

Typechecking.

We also review the procedure to typecheck an operation clause op x $\rightarrow$ M for op of type signature $A \hookrightarrow B$ . Since the operation op is called with an argument of A, the typechecking assigns type A to argument variable x. As the value of M is the result of the entire handlewith expression, the typechecking checks M to have the same type as the other clauses including the return clause. The typechecking of resumption expressions resume M’ is performed as follows. Since the value of M’ will be used as a result of calling op in a handled expression, M’ has to be of the type B, the arity type of the operation op. On the other hand, since the resumption expression returns the evaluation result of the entire handlewith expression, the typechecking assumes it to have the same type as all of the clauses in the handler.

For example, let us consider the typechecking of the operation clause for select in the function filter. Since the type signature of select is int list $\hookrightarrow$ int, the variable l is assigned the type int list. Here, we suppose map and concat to have the following types:

(these types can be inferred automatically). The type of map requires that the arguments l and have the types int list and int $\rightarrow$ int list, respectively, and they do indeed. The requirement for l is met by the type assigned to l. We can derive that has type int $\rightarrow$ int list as follows: first, the typechecking assigns the bound variable y type int and checks resume y to have int list. An argument of a resumption expression has to be of the type int, which is the arity type of select, and y has that type indeed. Then, the typechecking assumes that resume y has the same type as the clauses of the handler, which is the type int list. Thus, $\lambda$ y.resume y has the desired type.

2.2 Polymorphic effects

Polymorphic effects are a particular kind of effects that incorporate polymorphism,Footnote 6 providing a set of operations with polymorphic type signatures. We also call such operations polymorphic.

We write a polymorphic type signature as $ \forall \alpha_{{\mathrm{1}}} . \, ... \, \forall \alpha_{{n}} . \, A \hookrightarrow B $ , which quantifies the type variables $\alpha_{{\mathrm{1}}} \dots \alpha_{{n}}$ occurring in the parameter type A and those in the arity type B. To avoid ambiguity, we denote a type signature with a polymorphic parameter type $ \forall \, \alpha {.} \, A$ by $ {(} \forall \, \alpha {.} \, A {)} \hookrightarrow B $ .

For example, we can assign select and fail polymorphic signatures and write the program as follows:

This program evaluates to the list [2; 3; 20] (30 is filtered out by the call to fail).

Polymorphic type signatures enable operation calls with arguments of different types. For example, #select([2; 3]) and #select([true; false]) are legal operation calls that instantiate the bound type variable $\alpha$ of the type signature with int and bool, respectively. The calls to the same operation are handled by the same operation clause, even if the calls involve different type instantiations. It is also interesting to see that the use of polymorphic type signatures makes programs more natural and succinct: Thanks to its polymorphic arity type, a call to fail can be put anywhere, making it possible to put x in the else-branch, unlike the monomorphic case in Section 2.1.

Another benefit of polymorphic type signatures is that they contribute to the exclusion of undesired operation implementations. For example, the polymorphic signature of fail ensures that, once we call fail, the control never gets back and that of select ensures that no other values than elements in an argument list are chosen. Parametricity (Reynolds, Reference Reynolds1983) enables formal reasoning for this; readers are referred to Biernacki et al. (Reference Biernacki, Piróg, Polesiuk and Sieczkowski2020) for parametricity with the support for polymorphic algebraic effects and handlers.

2.3 Naive polymorphic typechecking is unsound

Naive typechecking of operation clauses for polymorphic operations is obtained by extending the monomorphic setting. The only difference is that the operation clauses have to abstract over types. Namely, an operation clause op x $\rightarrow$ M for op of polymorphic type signature $\forall \alpha.\, A\hookrightarrow B$ is typechecked as follows. The typechecking process allocates a fresh type variable $\alpha$ , which is bound in M, and assigns type A (which may refer to the bound type variable $\alpha$ ) to variable x. Resumption expressions resume M’ in M are typechecked as in the monomorphic setting; that is, the typechecking checks M’ to be of B (which may refer to $\alpha$ ) and assumes the resumption expressions to have the same type as the clauses in the handler. Finally, the typechecking checks whether M is of the same type as the other clauses in the handler. It is easy to see that the polymorphic versions of the select and fail example typecheck.

However, this naive extension is unsound under unrestricted polymorphic type assignment. In what follows, we revisit the counterexample given by Sekiyama and Igarashi (Reference Sekiyama and Igarashi2019), which is an analogue to that found by Harper and Lillibridge (Reference Harper and Lillibridge1993, Reference Harper and Lillibridge1991) for call/cc (Clinger et al., Reference Clinger, Friedman, Wand, Nivat and Reynolds1985).

We first check that this program is well typed. The handled expression first binds the variable f to the result returned by get_id. In polymorphic type assignment, we can assign a polymorphic type $\forall \alpha.\,\alpha \rightarrow \alpha$ to f by allocating a fresh type variable $\alpha$ , instantiating the type signature of get_id with $\alpha$ , and generalizing $\alpha$ finally. The polymorphic type of f allows viewing f both as a function of the type bool $\rightarrow$ bool and of the type int $\rightarrow$ int. Thus, the handled expression is well typed. Turning to the operation clause, since the type signature of get_id is $\forall \alpha.$ unit $\hookrightarrow (\alpha \rightarrow \alpha)$ , typechecking first allocates a fresh type variable $\alpha$ and assigns the type unit to the argument variable x. The signature also requires the arguments of the resumption expressions to have the type $\alpha \rightarrow \alpha$ , and both arguments $\lambda$ z1. $...$ z1 and $\lambda$ z2. z1 do indeed. The latter function is typed at $\alpha\rightarrow \alpha$ because the requirement for the former ensures that z1 has $\alpha$ . Thus, the entire program is well typed.

However, this program gets stuck. The evaluation starts with the call to get_id in the handled expression. It constructs the following delimited continuation:

The run-time system then replaces the resumption expressions with the invocation of the delimited continuation. Namely, the entire program evaluates to

The evaluation of M proceeds as follows.

Subsequently, the term is to be evaluated. The delimited continuation c expects the hole to be filled with a polymorphic function of $\forall \alpha.\, \alpha \rightarrow\alpha$ but the function is not polymorphic. As a result, the term gets stuck:

A standard approach to this problem is to restrict operation calls in polymorphic expressions (Tofte, Reference Tofte1990; Leroy and Weis, Reference Leroy and Weis1991; Appel and MacQueen, Reference Appel and MacQueen1991; Hoang et al., Reference Hoang, Mitchell and Viswanathan1993; Wright, Reference Wright1995; Garrigue, Reference Garrigue2004; Asai and Kameyama, Reference Asai and Kameyama2007). While this kind of approach prevents #get_id() from having a polymorphic type, it disallows calls to any polymorphic operation inside polymorphic expressions even when the calls are safe; interested readers can be referred to Sekiyama and Igarashi (Reference Sekiyama and Igarashi2019) for further discussion. Sekiyama and Igarashi (Reference Sekiyama and Igarashi2019) have proposed a complementary approach to this problem, that is, restricting, by typing, the handler of a polymorphic operation, instead of restricting handled expressions. While this approach allows polymorphic expressions to use any polymorphic effect, it requires all effect handlers to meet the proposed typing discipline. That is, effects implemented with effect handlers violating the discipline cannot be used anywhere—even in monomorphic contexts, although the use of polymorphic effects in such contexts should be safe (Tofte, Reference Tofte1990).

2.4 Our work: Signature restriction

This work takes a new approach to ensuring the safety of any call of an operation. Instead of restricting how it is used or implemented, we restrict its type signature: An operation op : $\forall \alpha.\, A \hookrightarrow B$ should not have a “bad” occurrence of $\alpha$ in A or B. We refer to this restriction as signature restriction.

To see how the signature restriction works, let us explain why type preservation is not easy to prove with the following example, where type abstraction $\Lambda \beta.\, M$ and type application $M\{A\}$ are explicit for the ease of readability:

Here, we suppose the type signature of op to be $\forall \alpha.\, A\hookrightarrow B$ . Notice that the type variable $\alpha$ in the signature $\forall \alpha.\, A \hookrightarrow B$ is instantiated to $\beta$ , which is locally bound by $\Lambda \beta$ . Handling of operation op constructs the following delimited continuation:

The problem is that an appropriate type cannot be assigned to it under the typing context of the handler H: the type of the hole should be $B[\beta/\alpha]$ , but the type variable $\beta$ is not in the scope of H. This is a kind of scope extrusion. We have focused on the scope extrusion via the continuation, but the operation argument v may cause a similar problem when its type $A[\beta/\alpha]$ contains the type variable $\beta$ .

This analysis suggests that polymorphic operations instantiated with closed types, i.e., types without free type variables (especially $\beta$ here), are safe to be performed because then the types of the hole and the operation argument should not contain $\beta$ and, thus, the continuation and the argument could be typed under the typing context of H. Footnote 7 However, allowing only instantiation with closed types is too restrictive. For example, it even disallows a function $\lambda x.\,$ #select(x) wrapping select to have a polymorphic type $\forall \alpha.\,\alpha \, \texttt{list} \rightarrow \alpha$ because, for the function to have this type, the bound type variable of the type signature of select has to be instantiated with a non-closed type $\alpha$ .

As another solution to the scope extrusion, we introduce strong signature restriction, which requires that, for each polymorphic operation op : $\forall \alpha.\, A \hookrightarrow B$ , the type variable $\alpha$ occur only negatively in A and only positively in B. This is a sufficient condition to prove type preservation. Consider, for example, the expression

where v is a value and C is a type with free type variables $\beta_1, \dots, \beta_n$ . The idea is to rewrite this expression, immediately before the call of op, to

(where the rewritten part is shaded). In $M_1'$ , because the type variable $\alpha$ in op : $\forall \alpha.\, A \hookrightarrow B$ is instantiated with a closed type $\forall \beta_1 \dots \beta_n.\, C$ , this operation call should be safe provided that $M_1'$ is well typed. This expression is indeed typable if the strong signature restriction is enforced, as seen below. To ensure that $M_1'$ is typable, we need to have

To this end, we employ type containment (Mitchell, Reference Mitchell1988), which is also known as “subtyping for second-order types” (Tiuryn and Urzyczyn, Reference Tiuryn and Urzyczyn1996). Type containment $ \sqsubseteq $ accepts the following key judgments:

\begin{align*} A[C/\alpha] & \sqsubseteq A[\forall \beta_1 \dots \beta_n.\,C/\alpha] \\ B[\forall \beta_1 \dots \beta_n.\,C/\alpha] & \sqsubseteq B[C/\alpha]\ ,\end{align*}

which follow from the acceptance of type instantiation $(\forall \beta_1 \dots \beta_n.\,C) \sqsubseteq C$ and the strong signature restriction which assumes that $\alpha$ occurs only negatively in A and only positively in B. Since $M_1$ is typable, we have $v : A[C/\alpha]$ and, by subsumption, $v : A[\forall \beta_1 \dots \beta_n.\,C/\alpha]$ . Therefore, the operation #op $\{\forall \beta_1 \dots \beta_n.\, C\}$ is applicable to v and we have #op $\{\forall \beta_1 \dots \beta_n.\, C\}$ (v) ${}: B[\forall \beta_1 \dots \beta_n.\,C/\alpha]$ . Again, by subsumption, #op $\{\forall \beta_1 \dots \beta_n.\, C\}$ (v) ${}: B[C/\alpha]$ as desired. Therefore, $M_1'$ is also typable. Note that the translation from $M_1$ to $M_1'$ does not change the underlying untyped term, but only the types of (sub)expressions; hence, if $M'_1$ does not get stuck, neither does $M_1$ .

However, the strong signature restriction is still unsatisfactory in that the type signatures of many operations do not conform to it. For example, the signature of select : $\forall \alpha.\, \alpha \, \texttt{list} \hookrightarrow \alpha$ in Section 2.2 does not satisfy the requirement of the strong signature restriction, which disallows the positive occurrences of bound type variables in parameter types (the left-hand side of $\hookrightarrow$ ).

Signature restriction is a relaxation of the strong signature restriction, allowing the type variable $\alpha$ in the signature $\forall \alpha.\, A \hookrightarrow B$ to occur at strictly positive positions in A in addition to negative positions. The proof of type preservation in this generalized case is essentially the same

as above but two changes. First, we close the value v by quantifying the type variables $\beta_1, \dots, \beta_n$ . Namely, we further rewrite $M_1'$ to

Second, we use the following type containment for the parameter type A:

\[ \forall \beta_1 \dots \beta_n.\, A[C/\alpha] \sqsubseteq A[\forall \beta_1 \dots \beta_n.\,C/\alpha] ~,\]

which is derivable using the polarity conditions of the signature restriction and an additional type containment rule, known as the distributive law:

\[ \forall \alpha.\, A \rightarrow B \sqsubseteq A \rightarrow \forall \alpha.\, B \quad \text{(if $\alpha$ does not occur free in} \textit{A}\text{)} ~.\]

The signature restriction is relaxed enough to accept many useful effects. For example, the type signature of select conforms to the signature restriction— $\alpha$ only occurs at a strictly positive position in the parameter type $\alpha \,\texttt{list}$ . As a result, we can ensure the safety of the calls to select in polymorphic expressions. Nevertheless, the signature restriction is still sound in that it rejects unsafe operations. For example, get_id does not conform to the signature restriction because, in its type signature $\forall \alpha.$ unit $\hookrightarrow (\alpha \rightarrow \alpha)$ , the bound type variable $\alpha$ occurs negatively in the arity type $\alpha \rightarrow \alpha$ .

The signature restriction has the following advantages over the previous approaches. By contrast with the approaches that restrict the use of effects, it allows polymorphic expressions to invoke any effect meeting the required restriction. By contrast with the approach that restricts effect handlers, the signature restriction is easily adaptable to allow the use of any polymorphic effect in monomorphic contexts, as shown in Section 6. Furthermore, the signature restriction is easy to understand once one admits the notion of polarities of type variables.

3 A $\lambda$ -Calculus with algebraic effects and handlers

This section defines the syntax and semantics of our base language $\lambda_{\text{eff}}$ , a $\lambda$ -calculus extended with algebraic effects and handlers. They are based on those of the core calculus of the language Koka (Leijen, Reference Leijen2017). The only difference is that the Koka core calculus is equipped with let-expressions whereas $\lambda_{\text{eff}}$ is not because we focus on implicit full polymorphism, rather than only on let-polymorphism. We will present a polymorphic type system for $\lambda_{\text{eff}}$ that takes into account signature restriction in Section 4.

3.1 Syntax

Figure 1 presents the syntax of $\lambda_{\text{eff}}$ . We use the metavariables x, y, z, f, k for variables and $\mathsf{op}$ for effect operations. Our language $\lambda_{\text{eff}}$ is parameterized over constants, which are ranged over by c and may include basic values, such as Boolean and integer values, and basic operations for them, such as $\mathsf{not}$ , $+$ , $-$ , $\mathsf{mod}$ , etc.

Fig 1. Syntax of $\lambda_{\text{eff}}$ .

Terms, ranged over by M, are from the $\lambda$ -calculus, augmented with constructs for algebraic effects and handlers. They are composed of: variables; constants; lambda abstractions $ \lambda\! \, x {.} {M}$ , where variable x is bound in M; function applications ${M_{{\mathrm{1}}}} \, {M_{{\mathrm{2}}}}$ ; operation calls $ {\textrm{#}} \mathsf{op} (M) $ with arguments M; and $\mathsf{handle}$ $\mathsf{with}$ expressions $\mathsf{handle} \, {M} \, \mathsf{with} \, {H}$ , which install a handler H to interpret effect operations performed during the evaluation of M. A resumption expression resume M that appears in Section 2 is the syntactic sugar of function application $k \, {M}$ where k is a variable that denotes delimited continuations and is introduced by an operation clause in a handler (we will see the definition of operation clauses shortly). The definition of evaluation contexts, ranged over by E, is standard; it indicates that the semantics of $\lambda_{\text{eff}}$ is call-by-value and terms are evaluated from left to right.

Handlers, ranged over by H, consist of a single return clause and zero or more operation clauses. A return clause takes the form $\mathsf{return} \, x \rightarrow {M}$ , where x is bound in M. The body M is evaluated once a handled expression produces a value, to which x is bound in M. An operation clause $\mathsf{op} {(} x {,} k {)} \rightarrow {M}$ , where x and k are bound in M, is an implementation of the effect operation $\mathsf{op}$ . The body M is evaluated once a handled expression performs $\mathsf{op}$ , referring to the argument of $\mathsf{op}$ by x. Variable k denotes the delimited continuation from the point where $\mathsf{op}$ is called up to the $\mathsf{handle}$ $\mathsf{with}$ expression that installs the operation clause. We suppose that a handler may contain at most one operation clause for each operation.

Here, we introduce a few notions about syntax; they are standard, and therefore we omit their formal definitions. We write $ {M_{{\mathrm{1}}}} [ {M_{{\mathrm{2}}}} / x ] $ for the term obtained by substituting ${M_{{\mathrm{2}}}}$ for x in ${M_{{\mathrm{1}}}}$ in a capture-avoiding manner. A term M is closed if it has no free variable. We also write E [ M ] and E [ E’ ] for the term and evaluation context obtained by filling the hole of E with M and E’, respectively.

3.2 Semantics

This section defines the semantics of $\lambda_{\text{eff}}$ . It consists of two binary relations over closed terms: the reduction relation $ \rightsquigarrow $ , which gives the notion of basic computation such as $\beta$ -reduction, and the evaluation relation $ \longrightarrow $ , which defines how to evaluate programs (namely, closed terms). These relations are defined by the rules shown in Figure 2.

Fig 2. Semantics of $\lambda_{\text{eff}}$ .

The reduction relation is defined by four rules. The rule is for constant applications. The semantics of functional constants are given by $ \zeta $ , which is a partial mapping from pairs of a constant c and a value v to the value that is the result of applying c to v. A function application ${(} \lambda\! \, x {.} {M} {)} \, {v}$ reduces to $ {M} [ {v} / x ] $ , as usual, by . The other two rules are for computation in terms of algebraic effects and handlers. The rule is for the case that a handled expression evaluates to a value. In such a case, the return clause of the installed handler is evaluated with the value of the handled expression. We write $ {H} ^\mathsf{return} $ for the return clause of a handler H. The rule is the core of effectful computation in algebraic effects and handlers. It looks for an operation clause to interpret an operation invoked by a handled expression. The redex is a $\mathsf{handle}$ $\mathsf{with}$ expression that takes the form $\mathsf{handle} \, {E} [ {\textrm{#}} \mathsf{op} {(} {v} {)} ] \, \mathsf{with} \, {H}$ where the handled expression $E[{\#} \mathsf{op} (v)] $ performs the operation $\mathsf{op}$ and E does not install handlers to interpret it. We call evaluation contexts that install no handler to interpret $\mathsf{op}$ $\mathsf{op}$ -transparent, which is formally defined as follows.

Definition 1 ( $\mathsf{op}$ -transparent evaluation contexts). defndefnOpFreeEvalCtx Evaluation context E is $\mathsf{op}$ -transparent, written $\mathsf{op} \, \not\in \, {E}$ , if and only if, there exist no ${E_{{\mathrm{1}}}}$ , ${E_{{\mathrm{2}}}}$ , and H such that ${E} \, = \, {E_{{\mathrm{1}}}} [ \mathsf{handle} \, {E_{{\mathrm{2}}}} \, \mathsf{with} \, {H} ] $ and H has an operation clause for $\mathsf{op}$ .

We also denote the operation clause for $\mathsf{op}$ in H by ${H} {(} \mathsf{op} {)}$ . Then, the conjunction of $\mathsf{op} \, \not\in \, {E}$ and ${H} {(} \mathsf{op} {)} \, = \, \mathsf{op} {(} x {,} k {)} \rightarrow {M}$ in means that the operation clause $\mathsf{op} {(} x {,} k {)} \rightarrow {M}$ installed by the $\mathsf{handle}$ $\mathsf{with}$ expression is the innermost among the operation clauses for $\mathsf{op}$ from the point at which $\mathsf{op}$ is invoked. The $\mathsf{handle}$ $\mathsf{with}$ expression with such an operation clause reduces to the body M of the operation clause after substituting the argument v of the operation call for x and the functional representation of the delimited continuation $ \lambda\! \, y {.} \mathsf{handle} \, {E} [ y ] \, \mathsf{with} \, {H}$ for k.

The evaluation proceeds according to the evaluation rule in Figure 2. A program is decomposed into the evaluation context E and the redex ${M_{{\mathrm{1}}}}$ and evaluates to the term $ {E} [ {M_{{\mathrm{2}}}} ] $ obtained by filling the hole of E with the reduction result ${M_{{\mathrm{2}}}}$ of the redex ${M_{{\mathrm{1}}}}$ .

4 A polymorphic type system for signature restriction

This section defines a polymorphic type system for $\lambda_{\text{eff}}$ that incorporates subsumption by type containment. We then formalize signature restriction and show that the type system is sound if all operations satisfy signature restriction. The type system in this section does not track effect information for simplicity. Therefore, a well-typed program may terminate at an unhandled operation call; we will present an effect system that can reject programs causing unhandled operation calls in Section 6.

4.1 Type language

Figure 3 presents the type language of the polymorphic type system. It is the same as that of System F (Reynolds, Reference Reynolds1974; Girard, Reference Girard1972) with base types. We use metavariables $\alpha$ , $\beta$ , $\gamma$ for type variables and $\iota$ for base types such as $ \mathsf{bool} $ and $ \mathsf{int} $ . Types, ranged over by A, B, C, D, consist of: type variables; base types; function types $A \rightarrow B$ ; and polymorphic types $ \forall \, \alpha {.} \, A$ , where type variable $\alpha$ is bound in type A. Typing contexts, ranged over by $\Gamma$ , are sequences of bindings of variables coupled with their types and type variables. We suppose that the metafunction $ \mathit{ty} $ assigns to each constant c a first-order closed type $ \mathit{ty} ( {c} ) $ of the form $\iota \rightarrow \cdots \rightarrow \iota_{{n}}$ . We state the assumption on the consistency between the types and semantics of constants later (Assumption 1).

Fig 3. The type language.

We use the following shorthand and notions. We write $ \boldsymbol{ \alpha }^{ {\mathit{I}} } $ for $ \boldsymbol{ \alpha } = \alpha_{{\mathrm{1}}}, \cdots, \alpha_{{n}}$ with the index set ${\mathit{I}} = \{ 1,..., n \}$ . We apply this bold-font notation to other syntax categories as well. For example, $ \boldsymbol{ A }^{ {\mathit{I}} } $ denotes a sequence of types. We often omit the index sets ( ${\mathit{I}}$ , ${\mathit{J}}$ , ${\mathit{K}}$ ) if they are clear from the context or irrelevant. For instance, we may abbreviate $ \boldsymbol{ \alpha }^{ {\mathit{I}} } $ to $ \boldsymbol{ \alpha } $ . We also write $ \forall \, \boldsymbol{ \alpha }^{ {\mathit{I}} } {.} \, A$ for $ \forall \alpha_{{\mathrm{1}}} . \, ... \, \forall \alpha_{{n}} . \, A$ with ${\mathit{I}} = \{ 1, ..., n\}$ . We may omit the index sets and write $ \forall \, \boldsymbol{ \alpha } {.} \, A$ simply. We write $ {\boldsymbol{ \forall} , \boldsymbol{ \alpha }^{{I}} {.} \, A }^{ \mathit{J}} $ for a sequence of types $ \forall \, \boldsymbol{ \alpha }^{ {\mathit{I}} } {.} \, A_1$ , …, $ \forall \, \boldsymbol{ \alpha }^{ {\mathit{I}} } {.} \, A_n$ with ${\mathit{J}} = \{1,\ldots,n\}$ . The notions of free type variables and capture-avoiding type substitution are defined as usual. We write $ \mathit{ftv} ( A ) $ for the set of free type variables of type A and $ A [ \boldsymbol{ B } {/} \boldsymbol{ \alpha } ] $ for the type obtained by substituting each type of the sequence $ \boldsymbol{ B }$ for the corresponding type variable of the sequence $\boldsymbol{ \alpha } $ simultaneously (here we suppose that $ \boldsymbol{ B } $ and $ \boldsymbol{ \alpha }$ share the same, omitted index set).

4.2 Polymorphic type system

We present a polymorphic type system for $\lambda_{\text{eff}}$ , which consists of four judgments: well-formedness judgment $\vdash \Gamma$ , which states that a typing context $\Gamma$ is well formed; type containment judgment $\Gamma \vdash A \sqsubseteq B$ , which states that, for the types A and B, which are assumed to be well formed under $\Gamma$ , the inhabitants of A are contained in B; term typing judgment $\Gamma \vdash {M} {:} A$ , which states that term M evaluates to a value of type A after applying an appropriate substitution for variables and type variables in $\Gamma$ ; and handler typing judgment $\Gamma \vdash {H} {:} A \Rightarrow B$ , which states that handler H handles operations called by a handled term of type A and produces a value of type B after applying appropriate substitution according to $\Gamma$ (we refer to A and B as the input and output types of the handler, respectively). These judgments are defined as the smallest relations that satisfy the rules in Figure 4.

Fig 4. Polymorphic type system for $\lambda_{\text{eff}}$ .

The well-formedness rules are standard. A typing context is well formed if (1) variables and type variables bound by it are unique and (2) it assigns well-formed types to the variables. We write $ \mathit{dom} ( \Gamma ) $ for the set of variables and type variables bound by $\Gamma$ . A type A is well formed under typing context $\Gamma$ , which is expressed by $\Gamma \vdash A$ , if and only if $ \mathit{ftv} ( A ) \, \subseteq \, \mathit{dom} ( \Gamma ) $ (i.e., $\Gamma$ binds all of the free type variables in A).

The type containment rules originate from the work of Tiuryn and Urzyczyn (Reference Tiuryn and Urzyczyn1996), which simplifies the rules of type containment of Mitchell (Reference Mitchell1988). The rules and indicate that type containment is a preorder. The rule instantiates polymorphic types with well-formed types. The rule may add a universal quantifier $\forall$ if the quantifier does not bind free type variables. The rules and are for compatibility; note that type containment is a kind of subtyping and hence it is contravariant on the domain types of function types. The rule is a simplified version (Tiuryn and Urzyczyn, Reference Tiuryn and Urzyczyn1996) of the original “distributive” law (Mitchell, Reference Mitchell1988), which is the core of type containment. This rule allows $\forall$ that quantifies a function type to move to its codomain type if the quantified type variable does not occur free in the domain type. This rule is justified by the fact that we can supply a function from $ \forall \, \alpha {.} \, A \rightarrow B$ to $A \rightarrow \forall \, \alpha {.} \, B$ in System F and the result of applying type erasure to it is equivalent to the identity function (Mitchell, Reference Mitchell1988). This rule is crucial for allowing the parameter type of a type signature to refer to quantified type variables in strictly positive positions, which makes signature restriction permissive.

The typing rules for terms are almost standard, coming from Mitchell (Reference Mitchell1988) for polymorphism and Plotkin and Pretnar (Reference Plotkin and Pretnar2013) for effects. The rule converts types by type containment. The rule is for operation calls. We formalize a type signature of an operation as follows.

Definition 2 (Type signature). defndefnTypeSignature The metafunction $ \mathit{ty} $ assigns to each effect operation $\mathsf{op}$ a type signature $\mathit{ty} \, (\mathsf{op})$ of the form $ \forall \alpha_{{\mathrm{1}}} . \, ... \, \forall \alpha_{{n}} . \, A \hookrightarrow B $ for some n, where $\alpha_{{\mathrm{1}}} {,} ... {,} \alpha_{{n}}$ are bound in the parameter type A and arity type B. It may be abbreviated to $ \forall \, \boldsymbol{ \alpha }^{ {\mathit{I}} } {.} \, A \hookrightarrow B $ or, more simply, to $ \forall \,\boldsymbol{ \alpha } {.} \, A \hookrightarrow B $ . We suppose that $ \forall \alpha_{{\mathrm{1}}} . \, ... \, \forall \alpha_{{n}} . \, A \hookrightarrow B $ is closed, i.e., $ \mathit{ftv} ( A ) , \mathit{ftv} ( B ) \subseteq \{ \alpha_{{\mathrm{1}}}, \cdots, \alpha_{{n}} \}$ .

We note that parameter and arity types may involve polymorphic types.

The rule instantiates the type signature of the operation with well-formed types and checks that an argument is typed at the parameter type of the instantiated type signature. We use notation $\Gamma \vdash \boldsymbol{ C } $ for the conjunction of $\Gamma \vdash C_{{\mathrm{1}}}, {\cdots}, \Gamma \vdash C_{{n}}$ when $ \boldsymbol{ C } = C_{{\mathrm{1}}}, {\cdots}, C_{{n}}$ .

The typing rules for handlers are also ordinary (Plotkin and Pretnar, Reference Plotkin and Pretnar2013). A return clause $\mathsf{return} \, x \rightarrow {M}$ is typechecked by , which allows the body M to refer to the values of the handled expression via bound variable x. An operation clause $\mathsf{op} {(} x {,} k {)} \rightarrow {M}$ is typechecked by . Let the type signature of $\mathsf{op}$ be $ \forall \, \boldsymbol{ \alpha } {.} \, C \hookrightarrow D $ . In typechecking M, variable x is assumed to have the parameter type C since variable x will be bound to the arguments to the operation $\mathsf{op}$ . Variable k is given type $D \rightarrow B$ where the type B is the output type of the handler. This is because k will be bound to the functional representations of delimited continuations such that: the delimited continuations suppose that their holes are filled with values of the arity type D of the type signature; and they are wrapped by the $ \mathsf{handle} $ $ \mathsf{with} $ expression installing the handler and therefore they would produce values of the type B.

4.3 Desired properties for type soundness

As mentioned in Section 2.3, the polymorphic type system is unsound—a well-typed program can get stuck—if we impose no further restriction on it. This section details the proof sketch of type preservation provided in Section 2.4 and formulates two propositions such that they do not hold in the polymorphic type system but, if they did, the type system would be sound. In Section 4.4.2, we show that the propositions hold if all operations satisfy signature restriction.

We start by considering an issue that arises when proving soundness of the polymorphic type system. This issue relates to the handling of an operation call by , which enables the following reduction:

(4.1)

where $\mathsf{op} \, \not\in \, {E}$ and ${H} {(} \mathsf{op} {)} \, = \, \mathsf{op} {(} x {,} k {)} \rightarrow {M}$ . The problem is that the RHS term does not preserve the type of the LHS term. If this type preservation were successful, we would be able to prove soundness of the polymorphic type system, but it is contradictory to the existence of the counterexample presented in Section 2.3.

A detailed investigation of this problem reveals two propositions that are lacking but sufficient to make the polymorphic type system sound.

Proposition 1. If $\mathit{ty} \, ( \mathsf{op} ) \, = \, \forall \, \boldsymbol{ \alpha }^{ {\mathit{I}} } {.} \, A \hookrightarrow B $ and $\Gamma \vdash {M} {:} \forall \,$ $ \boldsymbol{ \beta }^{ {\mathit{J}} } $ $ {.} \, A [ \boldsymbol{ C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] $ , then $\Gamma \vdash {M} {:} A [ { \boldsymbol{ \forall } \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] $ .

Proposition 2. If $\mathit{ty} \, {(} \mathsf{op} {)} \, = \, \forall \, \boldsymbol{ \alpha }^{ {\mathit{I}} } {.} \, A \hookrightarrow B $ and $\Gamma \vdash {M} {:} B [ { \boldsymbol{\forall } \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] $ , then $\Gamma \vdash {M} {:} \forall \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, B [ \boldsymbol{ C } ^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] $ .

In what follows, we show how these two propositions allow us to prove type soundness. Before that, we first fix and examine the type information of the terms appearing in the LHS term of reduction (4.1). Assume that $\mathit{ty} \, {(} \mathsf{op} {)} \, = \, \forall \, \boldsymbol{ \alpha }^{ {\mathit{I}} } {.} \, A \hookrightarrow B $ and that the LHS term has a type D under a typing context $\Gamma$ . We can then find that

(4.2) \begin{equation} \Gamma {,} \boldsymbol{ \alpha }^{ {\mathit{I}} } {,} x \, \mathord{:} \, A {,} k \, \mathord{:} \, B \rightarrow D \vdash {M} {:} D \end{equation}

must have held by the use of the typing rule . Turning to the handled expression , we can find two facts about the typing judgment for the value v. The first fact originates from : since the value v is an argument of operation $\mathsf{op}$ , it should be of type $ A [ \boldsymbol{ C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] $ , which is a type obtained by substituting certain types $ \boldsymbol{ C }^{ {\mathit{I}} } $ for type variables $ \boldsymbol{ \alpha }^{ {\mathit{I}} } $ in the parameter type A of the operation $\mathsf{op}$ . The second is from , which allows the generalization of types anywhere. Thus, the value v is well typed under a typing context $\Gamma {,} \boldsymbol{ \beta }^{ {\mathit{J}} } $ , an extension of $\Gamma$ with some type variables $ \boldsymbol{ \beta }^{ {\mathit{J}} } $ (note that ${\mathit{I}} \neq {\mathit{J}}$ in general). In summary, the typing judgment for the value v takes the following form:

(4.3) \begin{equation} \Gamma {,} \boldsymbol{ \beta }^{ {\mathit{J}} } \vdash {v} {:} A [ \boldsymbol{ C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] ~. \end{equation}

Now, we show that Proposition 1 makes $ {M} [ {v} / x ] $ typed at the type D. First, we can derive

\[ \Gamma \vdash {v} {:} \forall \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, A [ \boldsymbol{ C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ]\]

by the typing derivation of judgment (4.3) and . Proposition 1 enables us to prove

(4.4) \begin{equation} \Gamma \vdash {v} {:} A [ {\boldsymbol{ \forall} \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] ~. \end{equation}

We can also derive

\[ \Gamma {,} x \, \mathord{:} \, A \, [ { \boldsymbol{ \forall} \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] {,} k \, \mathord{:} \, B [ { \boldsymbol{ \forall } \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] \rightarrow D \vdash {M} {:} D\]

by substituting $ {\boldsymbol{ \forall} \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, C }^{ {\mathit{I}} } $ for $ \boldsymbol{ \alpha }^{ {\mathit{I}} } $ in the typing judgment (4.2); note that the type variables in $ \boldsymbol{ \alpha }^{ {\mathit{I}} } $ do not occur free in D because they are bound by the type signature. Thus, we can derive

(4.5) \begin{equation} \Gamma {,} k \, \mathord{:} \, B [ {\boldsymbol{ \forall} \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] \rightarrow D \vdash {M} [ {v} / x ] {:} D \end{equation}

using an ordinary substitution lemma with the derivation for judgment (4.4).

Next, we show that Proposition 2 makes $ {M} [ {v} / x ] [ \lambda\! \, y {.} \mathsf{handle} \, {E} [ y ] \, \mathsf{with} \, {H} / k ] $ typed at the type D. This is possible if

\[ \Gamma \vdash \lambda\! \, y {.} \mathsf{handle} \, {E} [ y ] \, \mathsf{with} \, {H} {:} B [ { \boldsymbol{ \forall } \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] \rightarrow D\]

is derivable, jointly with the derivation of typing judgment (4.5). Namely, it suffices to derive

\[ \Gamma {,} y \, \mathord{:} \, B \, [ {\boldsymbol{ \forall } \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] \vdash \mathsf{handle} \, {E} [ y ] \, \mathsf{with} \, {H} {:} D ~.\]

By an observation similar to the value v, we find that is typed at the type $ B [ \boldsymbol{ C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] $ under $\Gamma {,} \boldsymbol{ \beta }^{ {\mathit{J}} } $ (note that B is the arity type of $\mathsf{op}$ ). Thus, for the above typing judgment to hold, it suffices for the variable y to have the same type as . Hence, we will derive

(4.6) \begin{equation} \Gamma {,} y \, \mathord{:} \, B \, [ {\boldsymbol{ \forall} \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] {,} \boldsymbol{ \beta }^{ {\mathit{J}} } \vdash y {:} B [ \boldsymbol{ C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] ~. \end{equation}

Because $\Gamma {,} y \, \mathord{:} \, B \, [ { \boldsymbol{ \forall} \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] {,} \boldsymbol{ \beta }^{ {\mathit{J}} } \vdash y {:} B [ { \boldsymbol{ \forall } \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] $ , we can derive

\[ \Gamma {,} y \, \mathord{:} \, B \, [ { \boldsymbol{ \forall } \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] {,} \boldsymbol{ \beta }^{ {\mathit{J}} } \vdash y {:} \forall \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, B [ \boldsymbol{ C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ]\]

by Proposition 2. Furthermore, by instantiating $ \forall \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, B [ \boldsymbol{ C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] $ to $ B [ \boldsymbol{ C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] $ with $ \boldsymbol{ \beta }^{ {\mathit{J}} } $ in the typing context, we have succeeded in deriving the typing judgment (4.6).

Thus, if Propositions 1 and 2 held, we could derive

\[ \Gamma \vdash {M} [ {v} / x ] [ \lambda\! \, y {.} \mathsf{handle} \, {E} [ y ] \, \mathsf{with} \, {H} / k ] {:} D ~.\]

The polymorphic type system in Section 4.2 does not actually

support these properties, but imposing signature restriction produces a type system that does.

4.4 Signature restriction

This section formalizes signature restriction for $\lambda_{\text{eff}}$ and shows that it implies Propositions 1 and 2.

4.4.1 Definition

As described in Section 2.4, signature restriction rests on the polarity of the occurrences of quantified type variables in a type signature. The polarity is defined in a standard manner, as follows.

Definition 3 (Polarity of type variable occurrence). The sets $ \mathit{ftv} ( A )^+ $ and $ \mathit{ftv} ( A )^- $ of type variables that occur positively and negatively, respectively, in type A are defined by induction on A, as follows.

\[\begin{array}{lll} \mathit{ftv} ( \alpha )^+ &\stackrel{\rm \tiny def}{=}& {\{} \alpha {\}} \\ \mathit{ftv} ( \alpha )^- &\stackrel{\rm \tiny def}{=}& \emptyset \\ \mathit{ftv} ( A \rightarrow B )^{\pm} &\stackrel{\rm \tiny def}{=}& \mathit{ftv} ( A )^{\mp} \, \mathbin{\cup} \, \mathit{ftv} ( B )^{\pm} \\ \mathit{ftv} ( \forall \, \alpha {.} \, A )^{\pm} &\stackrel{\rm \tiny def}{=}& \mathit{ftv} ( A )^{\pm} \, \mathbin{\backslash} \, {\{} \alpha {\}} \end{array} \]

The set $ \mathit{ftv} ( A )^+_\mathbf{ns} $ of type variables that occur non-strictly positively in type A is defined as follows.

\[\begin{array}{lll} \mathit{ftv} ( \alpha )^+_\mathbf{ns} &\stackrel{\rm \tiny def}{=}& \emptyset \\ \mathit{ftv} ( A \rightarrow B )^+_\mathbf{ns} &\stackrel{\rm \tiny def}{=}& \mathit{ftv} ( A )^- \, \mathbin{\cup} \, \mathit{ftv} ( B )^+_\mathbf{ns} \\ \mathit{ftv} ( \forall \, \alpha {.} \, A )^+_\mathbf{ns} &\stackrel{\rm \tiny def}{=}& \mathit{ftv} ( A )^+_\mathbf{ns} \, \mathbin{\backslash} \, {\{} \alpha {\}} \end{array} \]

Now, we define signature restriction. We write ${\{} \boldsymbol{ \alpha }^{ {\mathit{I}} } {\}}$ to view the sequence $ \boldsymbol{ \alpha }^{ {\mathit{I}} } $ as a set by ignoring the order.

Definition 4 (Signature restriction). defndefnSignatureRestriction An operation $\mathsf{op}$ with type signature $\mathit{ty} \, {(} \mathsf{op} {)} \, = \, \forall \, \boldsymbol{ \alpha } {.} \, A \hookrightarrow B $ satisfies the signature restriction if and only if: (1) the occurrences of each type variable of $ \boldsymbol{ \alpha } $ in the parameter type A are only negative or strictly positive (i.e., ${\{} \boldsymbol{ \alpha } {\}} \, \mathbin{\cap} \, \mathit{ftv} ( A )^+_\mathbf{ns} \, = \, \emptyset $ ) and (2) the occurrences of each type variable of $ \boldsymbol{ \alpha } $ in the arity type B are only positive (i.e., ${\{} \boldsymbol{ \alpha } {\}} \, \mathbin{\cap} \, \mathit{ftv} ( B )^- \, = \, \emptyset $ ).

The signature restriction allows quantified type variables to occur at strictly positive positions of the parameter type of a type signature. This is crucial for some operations, such as select, to conform to signature restriction. The rule plays an important role to permit this capability, as seen in the next section.

We can easily confirm whether an operation satisfies the signature restriction. For example, it is easy to determine that get_id does not satisfy the signature restriction: since its type signature is $ \forall \, \alpha {.} \, \mathsf{unit} \hookrightarrow \alpha \rightarrow \alpha $ , the quantified type variable $\alpha$ occurs not only at a positive position but also at a negative position in the arity type $\alpha \rightarrow \alpha$ . By contrast, the operations raise and fail given in Section 2 satisfy the signature restriction because their type signature $ \forall \, \alpha {.} \, \mathsf{unit} \hookrightarrow \alpha $ meets the conditions in Definition 4. To determine whether select satisfies the signature restriction, we need to extend $\lambda_{\text{eff}}$ and the polymorphic type system by introducing other programming constructs such as lists. Particulars of this extension are presented in Section 5, but, briefly speaking, the type signature $ \forall \, \alpha {.} \, \alpha \, \mathsf{list} \hookrightarrow \alpha $ of select satisfies the signature restriction because the type variable $\alpha$ occurs only strictly positively in the parameter type $ \alpha \, \mathsf{list} $ and only positively in the arity type $\alpha$ .

4.4.2 Proofs of the desired properties

The signature restriction enables us to prove Propositions 1 and 2, which are crucial to show that reduction preserves typing. Below is the key lemma for that.

Lemma 1. lemmlemmSubtypingForallMove Assume that $\vdash \Gamma$ and $\alpha \, \not\in \, \mathit{ftv} ( A ) $ .

  1. 1. If $\beta \, \not\in \, \mathit{ftv} ( A )^+_\mathbf{ns} $ , then $\Gamma \vdash \forall \, \alpha {.} \, A [ B {/} \beta ] \sqsubseteq A [ \forall \, \alpha {.} \, B {/} \beta ] $ .

  2. 2. If $\beta \, \not\in \, \mathit{ftv} ( A )^- $ , then $\Gamma \vdash A [ \forall \, \alpha {.} \, B {/} \beta ] \sqsubseteq \forall \, \alpha {.} \, A [ B {/} \beta ] $ .

This lemma means that an operation $\mathsf{op}$ conforming to the signature restriction satisfies Propositions 1 and 2. For Proposition 1: assume $\mathit{ty} \, {(} \mathsf{op} {)} \, = \, \forall \, \boldsymbol{ \alpha }^{ {\mathit{I}} } {.} \, A \hookrightarrow B $ and $\Gamma \vdash {M} {:} \forall \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, A [ \boldsymbol{ C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] $ ; since $\mathsf{op}$ satisfies the signature restriction, we can apply case (1) of Lemma 1, which implies $\Gamma \vdash \forall \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, A [ \boldsymbol{ C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] \sqsubseteq A [ {\boldsymbol{ \forall} \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] $ ; thus, we can derive $\Gamma \vdash {M} {:} A [ { \boldsymbol{ \forall } \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, C }^{ {\mathit{I}} } {/} \boldsymbol{ \alpha }^{ {\mathit{I}} } ] $ by . Proposition 2 is proven similarly by using case (1) of Lemma 1 instead of case (1).

We start by proving that any type A can be regarded as a type constructor contravariant and covariant with respect to a type variable $\alpha$ if $\alpha$ occurs only negatively and positively, respectively, in A.

Lemma 2. lemmlemmSubtypingFunctoriality Assume that $\Gamma \vdash B \sqsubseteq C$ .

  1. 1. If $\alpha \, \not\in \, \mathit{ftv} ( A )^+ $ , then $\Gamma \vdash A [ C {/} \alpha ] \sqsubseteq A [ B {/} \alpha ] $ .

  2. 2. If $\alpha \, \not\in \, \mathit{ftv} ( A )^- $ , then $\Gamma \vdash A [ B {/} \alpha ] \sqsubseteq A [ C {/} \alpha ] $ .

Proof. Straightforward by induction on A.

Now, we prove Lemma 1 (1) using Lemma 2, and then Lemma 1 (1) using Lemma 1 (1) and , which is the key rule for the signature restriction to allow strictly positive occurrences of quantified type variables in the parameter type of a type signature.

Proof of Lemma 1 (2). By , it suffices to show that $\Gamma \vdash A [ \forall \, \alpha {.} \, B {/} \beta ] \sqsubseteq \forall \, \alpha {.} \, A [ \forall \, \alpha {.} \, B {/} \beta ] $ and $\Gamma \vdash \forall \, \alpha {.} \, A [ \forall \, \alpha {.} \, B {/} \beta ] \sqsubseteq \forall \, \alpha {.} \, A [ B {/} \beta ] $ . The former is derived by . The latter is derived as follows, where we have $\vdash \Gamma {,} \alpha $ because we can assume that $\alpha \, \not\in \, \mathit{dom} ( \Gamma ) $ without loss of generality:

Proof of Lemma 1 (1). By induction on type A. Here, we consider only the interesting cases: A is a function type or a polymorphic type; see the supplementary material for the other cases.

Case $A \, = \, C \rightarrow D$ for some C and D: By the assumption $\beta \, \not\in \, \mathit{ftv} ( A )^+_\mathbf{ns} = \mathit{ftv} ( C \rightarrow D )^+_\mathbf{ns} $ , we have $\beta \, \not\in \, \mathit{ftv} ( C )^- $ and $\beta \, \not\in \, \mathit{ftv} ( D )^+_\mathbf{ns} $ . By , it suffices to show the following two type containment judgments:

\[\begin{array}{c} \Gamma \vdash \forall \, \alpha {.} \, C [ B {/} \beta ] \rightarrow D [ B {/} \beta ] \sqsubseteq {(} \forall \, \alpha {.} \, C [ B {/} \beta ] {)} \rightarrow \forall \, \alpha {.} \, D [ B {/} \beta ] \\ \Gamma \vdash {(} \forall \, \alpha {.} \, C [ B {/} \beta ] {)} \rightarrow \forall \, \alpha {.} \, D [ B {/} \beta ] \sqsubseteq C [ \forall \, \alpha {.} \, B {/} \beta ] \rightarrow D [ \forall \, \alpha {.} \, B {/} \beta ] ~. \end{array} \]

The former is derived using with the following two derivations:

and

The latter is derived as follows:

Note that $\alpha \, \not\in \, \mathit{ftv} ( C ) \, \mathbin{\cup} \, \mathit{ftv} ( D ) = \mathit{ftv} ( A ) $ .

Case $A \, = \, \forall \, \gamma {.} \, C$ for some $\gamma$ and C: Without loss of generality, we can assume that $\gamma \, \not\in \, {\{} \alpha {,} \beta {\}} \, \mathbin{\cup} \, \mathit{dom} ( \Gamma ) \, \mathbin{\cup} \, \mathit{ftv} ( B ) $ . Because $\beta \, \not\in \, \mathit{ftv} ( A )^+_\mathbf{ns} $ , we have $\beta \, \not\in \, \mathit{ftv} ( C )^+_\mathbf{ns} $ . Furthermore, $\vdash \Gamma {,} \gamma $ as $\vdash \Gamma$ , and $\alpha \, \not\in \, \mathit{ftv} ( C ) $ as $\alpha \, \not\in \, \mathit{ftv} ( A ) $ . Thus, by the IH, $\Gamma {,} \gamma \vdash \forall \, \alpha {.} \, C [ B {/} \beta ] \sqsubseteq C [ \forall \, \alpha {.} \, B {/} \beta ] $ . By , $\Gamma \vdash \forall \, \gamma {.} \forall \, \alpha {.} \, C [ B {/} \beta ] \sqsubseteq \forall \, \gamma {.} \, C [ \forall \, \alpha {.} \, B {/} \beta ] $ . Because the type containment allows the commutation of universal quantifiers (see Lemma 9 in the supplementary material for detail), we have $\Gamma \vdash \forall \, \alpha {.} \forall \, \gamma {.} \, C [ B {/} \beta ] \sqsubseteq \forall \, \gamma {.} \forall \, \alpha {.} \, C [ B {/} \beta ] $ . Thus, by , $\Gamma \vdash \forall \, \alpha {.} \forall \, \gamma {.} \, C [ B {/} \beta ] \sqsubseteq \forall \, \gamma {.} \, C [ \forall \, \alpha {.} \, B {/} \beta ] $ , that is, $\Gamma \vdash \forall \, \alpha {.} \, A [ B {/} \beta ] \sqsubseteq A [ \forall \, \alpha {.} \, B {/} \beta ] $ .

4.5 Type soundness

This section shows soundness of the polymorphic type system under the assumption that all operations satisfy the signature restriction. As usual, our proof rests on two properties: progress and subject reduction (Wright and Felleisen, Reference Wright and Felleisen1994). As discussed in Sections 4.3 and 4.4, the signature restriction, together with type containment, enables us to prove subject reduction.

Type containment is thus a key notion to prove type soundness, but proving its inversion properties is complicated. In the literature (Peyton Jones et al., Reference Peyton Jones, Vytiniotis, Weirich and Shields2007; Dunfield and Krishnaswami, Reference Dunfield and Krishnaswami2013), type soundness of a language with subtyping based on type containment has been shown by translation to another language—typically, System F—where the use of subtyping is replaced by “coercions” (i.e., certain term representations for type conversion by subtyping). This approach is acceptable in the prior work because the semantics of the source language is determined by the target language. However, this approach is not acceptable in our setting because the terms checked by our type system should be interpreted by the semantics of $\lambda_{\text{eff}}$ as they are. We thus show soundness of the polymorphic type system directly, without translation to other languages.

The most difficult property to prove is the inversion of type containment judgments relating function types.

Lemma 3 (Type containment inversion: monomorphic function types). lemmlemmSubtypingInvFunMono If $\Gamma \vdash A_{{\mathrm{1}}} \rightarrow A_{{\mathrm{2}}} \sqsubseteq B_{{\mathrm{1}}} \rightarrow B_{{\mathrm{2}}}$ , then $\Gamma \vdash B_{{\mathrm{1}}} \sqsubseteq A_{{\mathrm{1}}}$ and $\Gamma \vdash A_{{\mathrm{2}}} \sqsubseteq B_{{\mathrm{2}}}$ .

We cannot prove this lemma as it is by induction on the derivation of $\Gamma \vdash A_{{\mathrm{1}}} \rightarrow A_{{\mathrm{2}}} \sqsubseteq B_{{\mathrm{1}}} \rightarrow B_{{\mathrm{2}}}$ because a premise in the derivation may relate the (monomorphic) function type on one side to a polymorphic function type on the other side. Thus, we need to generalize the assumption to a type containment judgment that may relate polymorphic function types: $\Gamma \vdash \forall \, \boldsymbol{ \alpha }^{ {\mathit{I}} } {.} \, A_{{\mathrm{1}}} \rightarrow A_{{\mathrm{2}}} \sqsubseteq \forall \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, B_{{\mathrm{1}}} \rightarrow B_{{\mathrm{2}}}$ . By investigating the type containment rules, we find that $ \boldsymbol{ \alpha }^{ {\mathit{I}} } $ is split into three sequences $ \boldsymbol{ \alpha_{{\mathrm{01}}} }^{ \text{I}_01}$ , $ \boldsymbol{\alpha}_{\mathrm{02}}^{\text{I}_{02}}$ , and $\boldsymbol{\alpha}_{03}^{ \text{I}_{03}}$ depending on how the rules handle the type variables in $ \boldsymbol{ \alpha }^{ {\mathit{I}} } $ : those of $ \boldsymbol{\alpha}_{01}^{\text{I}_01}$ stay in $ \boldsymbol{ \beta }^{ {\mathit{J}} } $ ; those of $ \boldsymbol{ \alpha}_{02}^{ \text{I}_02}$ are quantified in the return type $B_{{\mathrm{2}}}$ ; and those of $ \boldsymbol{\alpha}_{03}^{ \text{I}_{03}}$ are instantiated with some types $ \boldsymbol{ C}_{0}^{ \text{I}_{03}}$ . Furthermore, we have to take into account certain, unrevealed type variables $ \boldsymbol{ \gamma }^{ {\mathit{K}} } $ that initially emerge at the outermost position by and are subsequently distributed into subcomponent types. For example:

\[ A_{{\mathrm{1}}} \rightarrow A_{{\mathrm{2}}} \sqsubseteq \forall \, \gamma {.} \, A_{{\mathrm{1}}} \rightarrow A_{{\mathrm{2}}} \sqsubseteq {(} \forall \, \gamma {.} \, A_{{\mathrm{1}}} {)} \rightarrow {(} \forall \, \gamma {.} \, A_{{\mathrm{2}}} {)}\]

where $\gamma \, \not\in \, \mathit{ftv} ( A_{{\mathrm{1}}} ) \, \mathbin{\cup} \, \mathit{ftv} ( A_{{\mathrm{2}}} ) $ .

These observations are formulated in the following inversion lemma for type containment, which implies Lemma 3. We write ${\{} \boldsymbol{ \alpha }^{ {\mathit{I}} } {\}} \, \mathbin{\uplus} \, {\{} \boldsymbol{ \beta }^{ {\mathit{J}} } {\}}$ for the union of disjoint sets ${\{} \boldsymbol{ \alpha }^{ {\mathit{I}} } {\}}$ and ${\{} \boldsymbol{ \beta }^{ {\mathit{J}} } {\}}$ .

Lemma 4 (Type containment inversion: polymorphic function types). lemmlemmSubtypingInvFun If $\Gamma \vdash \forall \, \boldsymbol{ \alpha }^{ {\mathit{I}} } {.} \, A_{{\mathrm{1}}} \rightarrow A_{{\mathrm{2}}} \sqsubseteq \forall \, \boldsymbol{ \beta }^{ {\mathit{J}} } {.} \, B_{{\mathrm{1}}} \rightarrow B_{{\mathrm{2}}}$ , then there exist $ \boldsymbol{ \alpha_{{\mathrm{1}}} }^{ {\mathit{I}_{\mathrm{1}}} } $ , $ \boldsymbol{ \alpha_{{\mathrm{2}}} }^{ \text{I}_2}$ , $ \boldsymbol{ \gamma }^{ {\mathit{K}} } $ , and $ \boldsymbol{ C }^{ {\mathit{I}_{\mathrm{1}}} } $ such that

  • ${\{} \boldsymbol{ \alpha }^{ {\mathit{I}} } {\}} \, = \, {\{} \boldsymbol{ \alpha_{{\mathrm{1}}} }^{ {\mathit{I}_{\mathrm{1}}} } {\}} \, \mathbin{\uplus} \, {\{} \boldsymbol{ \alpha_{{\mathrm{2}}}}^{ \mathit{I}_{2}} {\}}$ <,

  • $\Gamma {,} \boldsymbol{ \beta }^{ {\mathit{J}} } {,} \boldsymbol{ \gamma }^{ {\mathit{K}} } \vdash \boldsymbol{ C }^{ {\mathit{I}_{\mathrm{1}}} } $ ,

  • $\Gamma {,} \boldsymbol{ \beta }^{ {\mathit{J}} } \vdash B_{{\mathrm{1}}} \sqsubseteq \forall \, \boldsymbol{ \gamma }^{ {\mathit{K}} } {.} \, A_{{\mathrm{1}}} [ \boldsymbol{ C }^{ {\mathit{I}_{\mathrm{1}}} } {/} \boldsymbol{ \alpha_{{\mathrm{1}}} }^{ {\mathit{I}_{\mathrm{1}}} } ] $ ,

  • $\Gamma {,} \boldsymbol{ \beta }^{ {\mathit{J}} } \vdash \forall \, \boldsymbol{\alpha}_{2}^{ \mathit{I}_{2}} {.}$ $ \forall \, \boldsymbol{ \gamma }^{ {\mathit{K}} } {.} \, A_{{\mathrm{2}}} [ \boldsymbol{ C }^{ {\mathit{I}_{\mathrm{1}}} } {/} \boldsymbol{ \alpha_{{\mathrm{1}}} }^{ {\mathit{I}_{\mathrm{1}}} } ] \sqsubseteq B_{{\mathrm{2}}}$ , and

  • ${\{} \boldsymbol{ \gamma }^{ {\mathit{K}} } {\}} \, \mathbin{\cap} \, {(} \mathit{ftv} ( A_{{\mathrm{1}}} ) \, \mathbin{\cup} \, \mathit{ftv} ( A_{{\mathrm{2}}} ) {)} \, = \, \emptyset $ .

In the statement, the sequence $ \boldsymbol{ \alpha}_{2}^{ \mathit{I}_2}$ corresponds to $ \boldsymbol{ \alpha}_{02}^{ \mathit{I}_{02}}$ in the above informal description and $ \boldsymbol{ \alpha_{{\mathrm{1}}} }^{ {\mathit{I}_{\mathrm{1}}} } $ includes the type variables that remain in $\boldsymbol{ \beta }^{ {\mathit{J}} } $ (i.e., $ \boldsymbol{ \alpha}_{01}^{ \mathit{I}_{01} }$ ) and those instantiated with some types in $ \boldsymbol{ C }^{ {\mathit{I}_{\mathrm{1}}} } $ (i.e., $ \boldsymbol{ \alpha_{{\mathrm{03}}} }^{ \mathit{I}_{03}}$ ). Type substitution $ [ \boldsymbol{ C }^{ {\mathit{I}_{\mathrm{1}}} } {/} \boldsymbol{ \alpha_{{\mathrm{1}}} }^{ {\mathit{I}_{\mathrm{1}}} } ] $ replaces a type variable in $ \boldsymbol{ \alpha_{{\mathrm{01}}} }^{{I}_{01} }$ with itself. We omit the detailed proof of Lemma 4 from the article because of its complexity; interested readers are referred to the supplementary material.

Now, we show progress, subject reduction, and type soundness. In what follows, the metavariable $\Delta$ ranges over typing contexts that consist only of type variable bindings. Note that the polymorphic type system is not equipped with a mechanism to track effects, so the operations that are carried out may not be handled. For proving progress and subject reduction, we assume the consistency between the type and semantics of every functional constant as follows.

Assumption 1. We assume the following for any constants ${c_{{\mathrm{1}}}}$ and ${c_{{\mathrm{2}}}}$ : (1) $ \zeta ( {c_{{\mathrm{1}}}} , {c_{{\mathrm{2}}}} ) $ is defined if and only if $ \mathit{ty} ( {c_{{\mathrm{1}}}} ) \, = \, \iota \rightarrow A$ and $ \mathit{ty} ( {c_{{\mathrm{2}}}} ) \, = \, \iota$ for some $\iota$ and A; and (2) if $ \zeta ( {c_{{\mathrm{1}}}} , {c_{{\mathrm{2}}}} ) $ is defined, $ \zeta ( {c_{{\mathrm{1}}}} , {c_{{\mathrm{2}}}} ) $ is a constant and $ \mathit{ty} ( \zeta ( {c_{{\mathrm{1}}}} , {c_{{\mathrm{2}}}} ) ) \, = \, A$ where $ \mathit{ty} ( {c_{{\mathrm{1}}}} ) \, = \, \iota \rightarrow A$ for some $\iota$ and A.

Lemma 5 (Progress) . If $\Delta \vdash {M} {:} A$ , then:

  • ${M} \longrightarrow {M'}$ for some M’;

  • M is a value; or

  • for some E, $\mathsf{op}$ , and v such that $\mathsf{op} \, \not\in \, {E}$ .

Lemma 6 (Subject reduction). Assume that all operations satisfy the signature restriction.

  1. 1. If $\Delta \vdash {M_{{\mathrm{1}}}} {:} A$ and ${M_{{\mathrm{1}}}} \rightsquigarrow {M_{{\mathrm{2}}}}$ , then $\Delta \vdash {M_{{\mathrm{2}}}} {:} A$ .

  2. 2. If $\Delta \vdash {M_{{\mathrm{1}}}} {:} A$ and ${M_{{\mathrm{1}}}} \longrightarrow {M_{{\mathrm{2}}}}$ , then $\Delta \vdash {M_{{\mathrm{2}}}} {:} A$ .

Proof. By induction on the typing derivation for ${M_{{\mathrm{1}}}}$ . The only interesting cases are for function applications and $\mathsf{handle}$ $\mathsf{with}$ expressions. The case for function applications uses Lemma 4 to relate the type information of function bodies to that of function applications. The case for $\mathsf{handle}$ $\mathsf{with}$ expressions is proven as described in Section 4.3 with Lemma 1. We refer to the supplementary material for the details of the proof.

We write $ \longrightarrow^{*} $ for the reflexive, transitive closure of $ \longrightarrow $ and to mean that there exists no term M’ such that ${M} \longrightarrow {M'}$ .

Theorem 1 (Type soundness). Assume that all operations satisfy the signature restriction. If $\Delta \vdash {M} {:} A$ and ${M} \longrightarrow^{*} {M'}$ and , then:

  • M’ is a value; or

  • for some E, $\mathsf{op}$ , and v such that $\mathsf{op} \, \not\in \, {E}$ .

Proof. By progress (Lemma 5) and subject reduction (Lemma 6).

4.6 Is it possible to relax the signature restriction further?

It is natural to ask whether the signature restriction can be further relaxed. This section examines the condition of strictly positive occurrences of quantified type variables on parameter types (Section 4.6.1) and other criteria for the cases that, given a type signature, its bound type variables occur only in the parameter type (Section 4.6.2) or in the arity type (Section 4.6.3).

4.6.1 The condition of strictly positive occurrences is necessary

Consider a type signature $ \forall \, \alpha {.} \, A \hookrightarrow B $ . We show that a nonstrictly positive occurrence of $\alpha$ in the parameter type A is problematic. Let us consider a calculus with $ \mathsf{int} $ , $ \mathsf{bool} $ , and sum types $ D_{{\mathrm{1}}} + D_{{\mathrm{2}}} $ for simplicity (we write $\mathsf{inl} \, {M}$ and $\mathsf{inr} \, {M}$ for injection into sum types). Consider an operation op of the signature $ \forall \, \alpha {.} \, {(} {(} \alpha \rightarrow \mathsf{int} {)} \rightarrow \alpha {)} \hookrightarrow \alpha $ and let

where E is an evaluation context such that $x \, \mathord{:} \, \mathsf{bool} + \mathsf{int} \vdash {E} [ x ] {:} \mathsf{int} $ and $ {E} [ \mathsf{inr} \, \mathsf{true} ] $ causes a run-time error (it is easy to construct such E). It is not difficult to check that M has type $ \mathsf{int} $ . In , the type variable $\alpha$ bound by the type signature is instantiated with $\beta \rightarrow {(} \beta + \mathsf{int} {)}$ , and thus g has type $ \forall \, \beta {.} \, \beta \rightarrow {(} \beta + \mathsf{int} {)}$ . The type variable $\beta$ is instantiated with $ \mathsf{int} $ in $g \, 0 $ and with $ \mathsf{bool} $ in $g \, \mathsf{true} $ . Then the counterexample is given by

\begin{equation*} \mathsf{handle} \, {M} \, \mathsf{with} \, \mathsf{return} \, x \rightarrow x {;} \mathsf{op} {(} x {,} k {)} \rightarrow k \, {(} x \, k {)} ~:~ \mathsf{int} , \end{equation*}

which is reduced to $\mathsf{handle} \, {E} [ \mathsf{inr} \, \mathsf{true} ] \, \mathsf{with} \, \mathsf{return} \, x \rightarrow x {;} \mathsf{op} {(} x {,} k {)} \rightarrow k \, {(} x \, k {)}$ and causes an error.

4.6.2 Further relaxation for closed arity types is possible

Consider an operation op : $\forall \alpha.\, A \hookrightarrow B$ where the type variable $\alpha$ does not appear in the arity type B. This operation can be regarded as being safe even if $\alpha$ occurs nonstrictly positively in the parameter type A. This is justified by a simple program transformation, regarding the polymorphic operation op : $\forall \alpha.\, A \hookrightarrow B$ as a monomorphic operation op’ : $(\exists \alpha. A) \hookrightarrow B$ . Footnote 8 To justify this translation, a key observation is that, if $\alpha$ has no occurrence in a type D, the polymorphic function type $\forall \alpha.\, C \to D$ is isomorphic to the type $(\exists \alpha.\,C) \to D$ in the sense that a term of the former type also has the latter type.

  • For a caller of the operation, the operation op is seen as a term of type $\forall \alpha.\, A \to B$ ; the translation replaces a term op of a type $\forall \alpha.\, A \to B$ by another term op’ of an isomorphic type $(\exists \alpha.A) \to B$ and hence preserves the typability of the caller.

  • A handler of op : $\forall \alpha.\, A \to B$ is essentially a term of type $\forall \alpha.\, A \to ((B \to C) \to C)$ where C is the output type of the handler, which has no occurrence of $\alpha$ , and $B \to C$ is the type of continuations. Similarly, a handler of op’ is a term of type $(\exists \alpha. A) \to ((B \to C) \to C)$ . Since the two types for handlers are isomorphic, the translation preserves the typability of handlers as well.

In general, given an operation op : $\forall \beta_1 \dots \beta_m. \forall \alpha_1 \dots \alpha_n.\, A \hookrightarrow B$ where the type variables $\alpha_1,\dots,\alpha_n$ do not appear in the arity type B, it suffices for the safety of the operation to check whether $\forall \beta_1 \dots \beta_m. (\exists \alpha_1 \dots \alpha_n.\, A) \hookrightarrow B$ satisfies the signature restriction.

4.6.3 Further relaxation for closed parameter types is harder

One may expect that the safety of an operation op : $\forall \alpha.\, A \hookrightarrow B$ where the type variable $\alpha$ does not appear in the parameter type A is reducible to the safety of op’ : $A \hookrightarrow (\forall \alpha. B)$ . Unfortunately, this is not true. A counterexample is get_id : $\forall \alpha.\, \mathtt{unit} \hookrightarrow (\alpha \to \alpha)$ and get_id’ : $\mathtt{unit} \hookrightarrow (\forall \alpha. \alpha \to \alpha)$ , of which the former is unsafe as we have seen but the latter is safe by the signature restriction. Actually, the translation replacing op with op’ does not preserve the typability of the handler. A handler of op can be seen as a term of type

\begin{equation*} \forall \alpha.\; A \to ((B \to C) \to C), \end{equation*}

where the type C is the output type of the handler, the type $B \to C$ is of continuations, and the type variable $\alpha$ never occurs in the output type C. This type is isomorphic to

\begin{equation*} A \to \forall \alpha. ((B \to C) \to C) \end{equation*}

and

\begin{equation*} A \to (\exists \alpha. (B \to C)) \to C \end{equation*}

but differs from the type for a handler for op

\begin{equation*} A \to ((\forall \alpha. B) \to C) \to C; \end{equation*}

the latter is stronger than the former, i.e., a term of the former type does not necessarily have the latter type, although the converse implication holds.

5 An extension of $\lambda_{\text{eff}}$

This section demonstrates the extensibility of the signature restriction. To this end, we extend $\lambda_{\text{eff}}$ , the polymorphic type system, and the signature restriction with products, sums, and lists and show soundness of the extended polymorphic type system under the extended signature restriction. We also provide a few examples of operations that satisfy the extended signature restriction.

5.1 Extended language

The extension of $\lambda_{\text{eff}}$ and the polymorphic type system is shown in Figures 5 and 6, in which the extended part of the syntax is highlighted. Terms support: pairs; projections; injections; case expressions for sums; the nil constant; $ \mathsf{cons} $ expressions; case expressions for lists; and the fixed-point operator. A case expression matching injections $\mathsf{case} \, {M} \, \mathsf{of} \, \mathsf{inl} \, x \rightarrow {M_{{\mathrm{1}}}} {;} \, \mathsf{inr} \, y \rightarrow {M_{{\mathrm{2}}}}$ binds x in ${M_{{\mathrm{1}}}}$ and y in ${M_{{\mathrm{2}}}}$ ; a case expression matching lists $\mathsf{case} \, {M} \, \mathsf{of} \, \mathsf{nil} \, \rightarrow {M_{{\mathrm{1}}}} {;} \, \mathsf{cons} \, x \rightarrow {M_{{\mathrm{2}}}}$ binds x in ${M_{{\mathrm{2}}}}$ ; the fixed-point operator $\mathsf{fix} \, f {.} \lambda\! \, x {.} {M}$ binds f and x in M. Pairs, injections, and $ \mathsf{cons} $ expressions are values if their immediate subterms are also values. Types are extended with product types, sum types, and list types. The extension of evaluation contexts follows that of terms. For the semantics, the reduction rules for projections, case expressions, and the fixed-point operator are augmented. The extension of the polymorphic type system is also straightforward. Type containment is extended by adding six rules: the three rules on the left in Figure 6 are for compatibility and the three rules on the right are for distributing $\forall$ over immediate subcomponent types. All of the additional typing rules are standard.

Fig 5. The extended part of the syntax and semantics.

Fig 6. The extended part of the type system.

Remark 1. The type containment rule in Figure 6 may look peculiar or questionable. Actually, there exists no term M in (implicitly typed) System F such that $x \, \mathord{:} \, \forall \, \alpha {.} \, {(} A + B {)} \vdash {M} {:} {(} \forall \, \alpha {.} \, A {)} + {(} \forall \, \alpha {.} \, B {)} $ , and thus the expected coercion function of ${(} \forall \, \alpha {.} \, {(} A + B {)} {)} \rightarrow {(} \forall \, \alpha {.} \, A {)} + {(} \forall \, \alpha {.} \, B {)} $ is not definable in System F. A justification can be given by the following fact: for every closed value ${}\vdash {v} : \forall \, \alpha {.} \, {(} A + B {)}$ , one has ${}\vdash {v} : {(} \forall \, \alpha {.} \, A {)} + {(} \forall \, \alpha {.} \, B {)} $ . In fact ${}\vdash {v} : \forall \, \alpha {.} \, {(} A + B {)}$ implies ${v} = \mathsf{inl} \, {v'}$ or $\mathsf{inr} \, {v''}$ . Assuming the former for definiteness, $ \alpha \vdash {v'} {:} A$ and thus ${}\vdash {v'} : \forall \, \alpha {.} \, A$ .

We also extend the polarity of the occurrences of a type variable. The polarity of the occurrences in type variables, function types, and polymorphic types is defined as in Definition 3 and that in product, sum, and list types is defined as follows.

Definition 5 (Polarity of type variable occurrence in product, sum, and list types).

The sets $ \mathit{ftv} ( A )^+ $ and $ \mathit{ftv} ( A )^- $ of type variables that occur positively and negatively, respectively, in type A are extended to product types, sum types, and list types, as follows.

\[\begin{array}{lll} \mathit{ftv} ( A \times B )^{\pm} &\stackrel{\rm \tiny def}{=}& \mathit{ftv} ( A )^{\pm} \, \mathbin{\cup} \, \mathit{ftv} ( B )^{\pm} \\ \mathit{ftv} ( A + B )^{\pm} &\stackrel{\rm \tiny def}{=}& \mathit{ftv} ( A )^{\pm} \, \mathbin{\cup} \, \mathit{ftv} ( B )^{\pm} \\ \mathit{ftv} ( A \, \mathsf{list} )^{\pm} &\stackrel{\rm \tiny def}{=}& \mathit{ftv} ( A )^{\pm} \\ \end{array} \]

The set $ \mathit{ftv} ( A )^+_\mathbf{ns} $ of type variables that occur nonstrictly positively in type A is extended as follows.

\[\begin{array}{lll} \mathit{ftv} ( A \times B )^+_\mathbf{ns} &\stackrel{\rm \tiny def}{=}& \mathit{ftv} ( A )^+_\mathbf{ns} \, \mathbin{\cup} \, \mathit{ftv} ( B )^+_\mathbf{ns} \\ \mathit{ftv} ( A + B )^+_\mathbf{ns} &\stackrel{\rm \tiny def}{=}& \mathit{ftv} ( A )^+_\mathbf{ns} \, \mathbin{\cup} \, \mathit{ftv} ( B )^+_\mathbf{ns} \\ \mathit{ftv} ( A \, \mathsf{list} )^+_\mathbf{ns} &\stackrel{\rm \tiny def}{=}& \mathit{ftv} ( A )^+_\mathbf{ns} \end{array} \]

The signature restriction for the extended language is defined as in Definition 4 except that the polarity of occurrences of type variables is defined by both of Definitions 3 and 5.

The type soundness of the extended language can be proven, as in Section 4.5, under the assumption that all operations conform to the signature restriction extended to product, sum, and list types. See the supplementary material for detail.

5.2 Examples

This section presents two operations that satisfy the signature restriction in the extended language.

The first example is select, which is an operation given in Section 2.1 for nondeterministic computation. The operation has the type signature $ \forall \, \alpha {.} \, \alpha \, \mathsf{list} \hookrightarrow \alpha $ , where the quantified type variable $\alpha$ occurs only at a strictly positive position in the parameter type $ \alpha \, \mathsf{list} $ and only at a positive position in the arity type $\alpha$ . Thus, select satisfies the signature restriction and, therefore, it can be safely called by any polymorphic expression.

The second example is from Leijen (Reference Leijen2017), who implemented parser combinators using algebraic effects and handlers. The effect for parsing provides a basic operation satisfy which has the type signature

\[ \forall \, \alpha {.} \, {(} \mathsf{str} \rightarrow {(} \alpha \times \mathsf{str} {)} + \mathsf{unit} {)} \hookrightarrow \alpha\]

where $ \mathsf{str} $ is the type of strings. This operation takes a parsing function of $ \mathsf{str} \rightarrow {(} \alpha \times \mathsf{str} {)} + \mathsf{unit} $ such that: the parsing function returns the unit value if an input string does not conform to the grammar; otherwise, it returns the parsing result of $\alpha$ and the unparsed, remaining string. The operation satisfy would return the result of parsing if it succeeds. For example, we can give satisfy a parsing function that returns the first character of a given input—and returns the unit value if the input is the empty string—as follows:

Here: $ \mathsf{length} $ is a function of $ \mathsf{str} \rightarrow \mathsf{int} $ that returns the length of a given string; $ \mathsf{first} $ is of $ \mathsf{str} \rightarrow \mathsf{char} $ ( $ \mathsf{char} $ is the type of characters) that returns the first character of a given string; and $ \mathsf{last} $ is of $ \mathsf{str} \rightarrow \mathsf{str} $ that returns the same string as an input except that it does not contain the first character of the input. In this example, the call of satisfy is of the type $ \mathsf{char} $ because the argument function is of the type $ \mathsf{str} \rightarrow {(} \mathsf{char} \times \mathsf{str} {)} + \mathsf{unit} $ , which requires the quantified type variable $\alpha$ to be instantiated to $ \mathsf{char} $ . The operation satisfy satisfies the signature restriction clearly. The quantified type variable $\alpha$ occurs only at a strictly positive position in the parameter type $ \mathsf{str} \rightarrow {(} \alpha \times \mathsf{str} {)} + \mathsf{unit} $ of the type signature, and it also occurs only at a positive position in the arity type $\alpha$ .

6 Cooperation of safe and unsafe effects

This section describes an effect system for $\lambda_{\text{eff}}^{\text{ext}}$ , which enables the type-safe cooperation of safe and unsafe effects in a single program. Our effect system allows expressions to be polymorphic if their evaluation performs only operations that satisfy the signature restriction. This capability makes it possible for the effect system to incorporate value restriction—i.e., any value can be polymorphic—because values perform no operation. The definition of signature restriction changes to take into account effect information on types. Soundness of the effect system ensures that programs handle all the operations performed at run time.

Our effect system is inspired by Kammar et al. (Reference Kammar, Lindley and Oury2013), where the effect system tracks invoked effect operations by their names together with their type signatures. There are, however, two differences between Kammar et al.’s and our effect systems. The first difference comes from that of the evaluation strategies the calculi adopt: the calculus of Kammar et al. is based on call-by-push-value (CBPV) (Levy, Reference Levy2001), and we adopt call-by-value (CBV). This difference influences the design of effect systems because the two strategies have different notions for the value representations of suspended computations and effect systems have to reason about the effects caused by their run. CBPV views functions as (not suspended) computations, and thus Kammar et al. did not equip function types with effect information; instead, they augmented the types of thunks (which are value representations of suspended computations in CBPV) with it. By contrast, because CBV views functions as values that represent suspended computations, our effect system equips function types with effect information. The second difference is that we include only operation names and not their type signatures in the effect information. This is merely for simplifying the presentation but it makes the calculus nonterminating (Kammar and Pretnar, Reference Kammar and Pretnar2017). .

6.1 Effect system

Figure 7 shows only the key part of the effect system; the full definition is found in the supplementary material.

Fig 7. The effect system (excerpt).

The type language includes effect information. Effects, ranged over by $\varepsilon$ , are finite sets of operations. Function types are augmented with effects that may be triggered in applying the functions of those types.

Typing judgments also incorporate effects. A term typing judgment $\Gamma \vdash {M} {:} A \, | \, \varepsilon$ asserts that M is a computation that produces a value of A possibly with effect $\varepsilon$ . A handler typing judgment $\Gamma \vdash {H} {:} A \, | \, \varepsilon \Rightarrow B \, | \, \varepsilon'$ asserts that H handles a computation that produces values of A possibly with effect $\varepsilon$ and the handling produces values of B possibly with effect $\varepsilon'$ . Type containment judgments $\Gamma \vdash A \sqsubseteq B$ and well-formedness judgments $\vdash \Gamma$ take the same forms as those of the polymorphic type system in Section 4.

Most of the typing rules for terms are almost the same as those of the polymorphic type system except that they take into account effect information. The rule shows how effects are incorporated into the typing rules: the effect triggered by a term is determined by its subterms. Besides, requires effect $\varepsilon'$ triggered by a function to be a subset of the effect $\varepsilon$ of the subterms. The rule is the key of the effect system, allowing a term to have a polymorphic type if it triggers only safe effects. The safety of an effect $\varepsilon$ is checked by the predicate $\mathit{SR} \, {(} \varepsilon {)}$ , which asserts that any operation in $\varepsilon$ satisfies the signature restriction for the type language in Figure 7; we will formalize $\mathit{SR} \, {(} \varepsilon {)}$ after explaining the type containment rules. A by-product of adopting is that the effect system incorporates the value restriction (Tofte, Reference Tofte1990) successfully: it allows values to have polymorphic types because the values perform no operation (thus, their effects can be the empty set $ \emptyset $ ) and $\mathit{SR} \, {(} \emptyset {)}$ obviously holds. The rule gives any effect $\varepsilon'$ to the fixed-point operator. This means that the fixed-point operator can be viewed as a pure computation because it only produces a lambda abstraction without triggering effects. The rule weakens the effect information of a term.

There are two rules for deriving a handler typing judgment $\Gamma \vdash {H} {:} A \, | \, \varepsilon \Rightarrow B \, | \, \varepsilon'$ . They state that the effect of a $ \mathsf{handle} $ $ \mathsf{with} $ expression installing H consists of the operations that the handled expression may call but H does not handle and those that the return clause or some operation clause of H may call. The effect $\varepsilon \, \mathbin{\uplus} \, {\{} \mathsf{op} {\}}$ is the same as $\varepsilon \, \mathbin{\cup} \, {\{} \mathsf{op} {\}}$ except that it requires $\mathsf{op} \, \not\in \, \varepsilon$ .

Most of the type containment rules of the effect system are the same as those of the polymorphic type system. The exception is the rules for function types and , which are replaced by and to take into account effect information. The rule for deriving $\Gamma \vdash \forall \, \alpha {.} \, A \rightarrow ^{ \varepsilon } B \sqsubseteq A \rightarrow ^{ \varepsilon } \forall \, \alpha {.} \, B $ has an additional condition that $\mathit{SR} \, {(} \varepsilon {)}$ must hold. This condition originates from . The rule allows that, if a lambda abstraction $ \lambda\! \, x {.} {M}$ has a polymorphic type $ \forall \, \alpha {.} \, A \rightarrow ^{ \varepsilon } B $ , the body M may also have another polymorphic type $ \forall \, \alpha {.} \, B$ . In general, M may be a nonvalue term. In such a case, only justifies that M has a polymorphic type; however, to apply the effect $\varepsilon$ triggered by M has to meet $\mathit{SR} \, {(} \varepsilon {)}$ . This is the reason why requires that $\mathit{SR} \, {(} \varepsilon {)}$ hold.

Now, we formalize the predicate $\mathit{SR} \, {(} \varepsilon {)}$ , which states that any operation in $\varepsilon$ satisfies signature restriction extended by effect information. In what follows, we suppose the notions of positive/negative/nonstrictly positive occurrences of a type variable for the type language in Figure 7; they are defined naturally as in Definitions 3 and 5. In addition, we can decide whether a type occurs at a strictly positive position in a type by generalizing the polarity of the occurrences of type variables to those of types.

Definition 6 (Signature restriction on effects). defndefnEffSignatureRestriction The predicate $\mathit{SR} \, {(} \varepsilon {)}$ holds if and only if, for any $\mathsf{op} \, \in \, \varepsilon$ such that $\mathit{ty} \, {(} \mathsf{op} {)} \, = \, \forall \, \boldsymbol{ \alpha } {.} \, A \hookrightarrow B $ :

  • ${\{} \boldsymbol{ \alpha } {\}} \, \mathbin{\cap} \, \mathit{ftv} ( A )^+_\mathbf{ns} \, = \, \emptyset $ ;

  • ${\{} \boldsymbol{ \alpha } {\}} \, \mathbin{\cap} \, \mathit{ftv} ( B )^- \, = \, \emptyset $ ; and

  • for any function type $ C \rightarrow ^{ \varepsilon' } D $ occurring at a strictly positive position in the type A, if ${\{} \boldsymbol{ \alpha } {\}} \, \mathbin{\cap} \, \mathit{ftv} ( D ) \, \not= \, \emptyset $ , then $\mathit{SR} \, {(} \varepsilon' {)}$ .

The first and second conditions of Definition 6 are the same as those of Definition 4, signature restriction without effect information. The third condition is necessary to apply . The signature restriction in the polymorphic type system allows type variables $ \boldsymbol{ \alpha } $ in type signature $ \forall \, \boldsymbol{ \alpha } {.} \, A \hookrightarrow B $ to occur at a strictly positive position in the type A (see Definition 4). As discussed in Section 4.4.2, this capability originates from . In the effect system, the counterpart is applied to retain this capability, but requires the effect of a function type to satisfy $ \mathit{SR} $ . This is the reason why the signature restriction for the effect system imposes the third condition. Note that, if ${\{} \boldsymbol{ \alpha } {\}} \, \mathbin{\cap} \, \mathit{ftv} ( D ) \, = \, \emptyset $ (as well as ${\{} \boldsymbol{ \alpha } {\}} \, \mathbin{\cap} \, \mathit{ftv} ( C ) \, = \, \emptyset $ ), then we can derive $\Gamma \vdash \forall \, \boldsymbol{ \alpha } {.} \, C \rightarrow ^{ \varepsilon' } D \sqsubseteq C \rightarrow ^{ \varepsilon' } \forall \, \boldsymbol{ \alpha } {.} \, D $ without . Thus, the third condition does not require $\mathit{SR} \, {(} \varepsilon' {)}$ if ${\{} \boldsymbol{ \alpha } {\}} \, \mathbin{\cap} \, \mathit{ftv} ( D ) \, = \, \emptyset $ .

We finally state soundness of the effect system, which ensures that a well-typed program handles all the operations performed at run time. We prove it by progress and subject reduction; their formal statements and proofs are found in the supplementary material.

Theorem 2 (Type soundness.) If $\Delta \vdash {M} {:} A \, | \, \emptyset $ and ${M} \longrightarrow^{*} {M'}$ and , then M’ is a value.

6.2 Example

The effect system allows us to use both safe and unsafe effects in a single program. For example, let us consider the following program (which can be represented in $\lambda_{\text{eff}}^{\text{ext}}$ ).

This example would be rejected if we were to enforce all operations to follow the signature restriction as in Section 4 because it uses the unsafe operation get_id. By contrast, the effect system accepts it because: the polymorphic expression calls no operation (because it is a value) and #select([ $\lambda$ x. x; f]) calls only select, which satisfies the signature restriction, during the evaluation; therefore, they can have the polymorphic type by . Note that the effect system still rejects the counterexample given in Section 2.3 because it disallows polymorphic expressions to call operations that do not satisfy the signature restriction, such as get_id.

6.3 Alternative designs

When defining the effect system presented thus far, we kept simplicity in mind, which affected the design of the effect system. Specifically, we decided that 1) the type signatures of operations are assumed to be assigned globally and 2) type containment does not involve subeffecting (it is used only for type instantiation). This section informally discusses the alternatives of these decisions: local assignment of type signatures and type containment with subeffecting.

6.3.1 Local assignment of type signatures

In the formalized system, effects are sets only of operations, and their type signatures are uniquely determined by metafunction $ \mathit{ty} $ . We call this assignment of type signatures global. The global type signature assignment models the treatment of effects in programming languages, such as Koka (Leijen, Reference Leijen2023) and Frank (Lindley et al., Reference Lindley, McBride, McLaughlin and Convent2022), where every effect operation has to be declared with a type signature before used.

An alternative is to represent effects as sets of pairs of an operation and its type signature (Kammar et al., Reference Kammar, Lindley and Oury2013), as

\[ \varepsilon_\mathrm{local} ~{::=}~ \{ \mathsf{op}_{{\mathrm{1}}} : \forall \, \boldsymbol{ \alpha_{{\mathrm{1}}} }^{ {\mathit{I}_{\mathrm{1}}} } {.} \, A_{{\mathrm{1}}} \hookrightarrow B_{{\mathrm{1}}} , ~\dots, ~\mathsf{op}_{{n}} : \forall \,\boldsymbol{ \alpha_{{n}} } ^{ {\mathit{I}_{\mathrm{n}}} } {.} \, A_{{n}} \hookrightarrow B_{{n}} \} ~.\]

In this representation, we can assign different type signatures to different occurrences of the same operation. Hence, we call this type assignment local. For example, consider the following function application:

where the function part supposes operation $\mathsf{op}$ ’s type signature to be $ \mathsf{int} \hookrightarrow A $ for some type A, while the argument part supposes it to be $ \mathsf{bool} \hookrightarrow B $ for some type B. The handlers ${H_{{\mathrm{1}}}}$ and ${H_{{\mathrm{2}}}}$ should involve operation clauses conforming to these type signatures, respectively. More interestingly, the same operation can be given different type signatures per occurrence even in the same effect. For example, consider the following effect:

\[ \{ \mathsf{op} : A_{{\mathrm{1}}} \hookrightarrow {(} B_{{\mathrm{1}}} \rightarrow ^{ \{ \mathsf{op} : C_{{\mathrm{1}}} \hookrightarrow C_{{\mathrm{2}}} \} } B_{{\mathrm{2}}} {)} \} ~.\]

It states that operation $\mathsf{op}$ returns a function of the type $ B_{{\mathrm{1}}} \rightarrow ^{ \{ \mathsf{op} : C_{{\mathrm{1}}} \hookrightarrow C_{{\mathrm{2}}} \} } B_{{\mathrm{2}}} $ , that is, when the returned function is applied and then invokes operation $\mathsf{op}$ with an argument of type $C_{{\mathrm{1}}}$ , the caller expects the operation to return a value of type $C_{{\mathrm{2}}}$ . One critical difference between the local and global assignment of type signatures is in program termination: one can write divergent programs under the global assignment, whereas the local assignment can guarantee well-typed programs terminating (Kammar and Pretnar, Reference Kammar and Pretnar2017). The local assignment is employed by, e.g., the links programming language (The Links team, 2022).

To adapt the signature restriction to the local type signature assignment, we need to make changes to the definitions of the polarities of type variables, type containment’s distributive law, and type generalization, in addition to a minor change that the type signature of an operation is found in an effect, not assigned by the metafunction $ \mathit{ty} $ . We describe the details of the three major changes below, but it is left open whether only these changes (including the minor one) can ensure soundness of an effect system that assigns type signatures locally.

Change 1: Polarities of type variables.

Effects in the local assignment may contain free type variables. Therefore, we need to extend the polarities of type variables to take effects into account, as follows:

\[\begin{array}{lll} \mathit{ftv} ( A \rightarrow ^{ \varepsilon_\mathrm{local} } B )^{\pm} &\stackrel{\rm \tiny def}{=}& \mathit{ftv} ( A )^{\mp} \, \mathbin{\cup} \, \mathit{ftv} ( B )^{\pm} \, \mathbin{\cup} \, \mathit{ftv} ( \varepsilon_\mathrm{local} )^{\pm} \\[.5ex] \mathit{ftv} ( \varepsilon_\mathrm{local} )^{\pm} &\stackrel{\rm \tiny def}{=}& {(} {(} \mathit{ftv} ( A_{{\mathrm{1}}} )^{\mp} \, \mathbin{\cup} \, \mathit{ftv} ( B_{{\mathrm{1}}} )^{\pm} {)} \, \mathbin{\backslash} \, {\{} \boldsymbol{ \alpha_{{\mathrm{1}}} }^{ {\mathit{I}_{\mathrm{1}}} } {\}} {)} \,\cup\, \dots \,\cup\, \\ && {(} {(} \mathit{ftv} ( A_{{n}} )^{\mp} \, \mathbin{\cup} \, \mathit{ftv} ( B_{{n}} )^{\pm} {)} \, \mathbin{\backslash} \, {\{} \boldsymbol{ \alpha_{{n}} }^{ {\mathit{I}_{\mathrm{n}}} } {\}} {)} \\[1ex] \mathit{ftv} ( A \rightarrow ^{ \varepsilon_\mathrm{local} } B )^+_\mathbf{ns} &\stackrel{\rm \tiny def}{=}& \mathit{ftv} ( A )^- \, \mathbin{\cup} \, \mathit{ftv} ( B )^+_\mathbf{ns} \, \mathbin{\cup} \, \mathit{ftv} ( \varepsilon_\mathrm{local} )^+_\mathbf{ns} \\ \mathit{ftv} ( \varepsilon_\mathrm{local} )^+_\mathbf{ns} &\stackrel{\rm \tiny def}{=}& {(} {(} \mathit{ftv} ( A_{{\mathrm{1}}} )^- \, \mathbin{\cup} \, \mathit{ftv} ( B_{{\mathrm{1}}} )^+_\mathbf{ns} {)} \, \mathbin{\backslash} \, {\{} \boldsymbol{ \alpha_{{\mathrm{1}}} }^{ {\mathit{I}_{\mathrm{1}}} } {\}} {)} \,\cup\, \dots \,\cup\, \\ && {(} {(} \mathit{ftv} ( A_{{n}} )^- \, \mathbin{\cup} \, \mathit{ftv} ( B_{{n}} )^+_\mathbf{ns} {)} \, \mathbin{\backslash} \, {\{}\boldsymbol{ \alpha_{{n}} }^{ {\mathit{I}_{\mathrm{n}}} } {\}} {)} \\ \end{array}\]

where $\varepsilon_\mathrm{local}$ is supposed to be $\{ \mathsf{op}_{{\mathrm{1}}} : \forall \, \boldsymbol{ \alpha_{{\mathrm{1}}} }^{ {\mathit{I}_{\mathrm{1}}} } {.} \, A_{{\mathrm{1}}} \hookrightarrow B_{{\mathrm{1}}} , ~\dots, ~\mathsf{op}_{{n}} : \forall \, \boldsymbol{ \alpha_{{n}} }^{ {\mathit{I}_{\mathrm{n}}} } {.} \, A_{{n}} \hookrightarrow B_{{n}} \}$ .

Change 2: Type containment’s distributive law.

The distributive law can be modified so that $\forall$ quantifying a function type moves not only to its codomain type but also to the arity types of the type signatures in its latent effect. Namely, the adapted distributive law can be given as

\[ \frac{\begin{array}{c} { \varepsilon_\mathrm{local} = \{ \mathsf{op}_{{\mathrm{1}}} : \forall \, \boldsymbol{ \beta_{{\mathrm{1}}} }^{ {\mathit{I}_{\mathrm{1}}} } {.} \, C_{{\mathrm{1}}} \hookrightarrow D_{{\mathrm{1}}} , ~\dots, ~\mathsf{op}_{{n}} : \forall \, \boldsymbol{ \beta_{{n}} }^{ {\mathit{I}_{\mathrm{n}}} } {.} \, C_{{n}} \hookrightarrow D_{{n}} \}}\\ { \varepsilon_\mathrm{local}' = \{ \mathsf{op}_{{\mathrm{1}}} : \forall \, \boldsymbol{ \beta_{{\mathrm{1}}} } ^{ {\mathit{I}_{\mathrm{1}}} } {.} \, C_{{\mathrm{1}}} \hookrightarrow \forall \, \alpha {.} \, D_{{\mathrm{1}}} , ~\dots, ~\mathsf{op}_{{n}} : \forall \, \boldsymbol{ \beta_{{n}} }^{ {\mathit{I}_{\mathrm{n}}} } {.} \, C_{{n}} \hookrightarrow \forall \, \alpha {.} \, D_{{n}} \}}\\ { \vdash \Gamma \quad \alpha \, \not\in \, \mathit{ftv} ( A ) \cup \mathit{ftv} ( C_{{\mathrm{1}}} ) \cup \dots \cup \mathit{ftv} ( C_{{n}} ) \quad \mathit{SR} \, {( \varepsilon_{\mathrm{local}} )} }\end{array}}{\Gamma \vdash \forall \, \alpha {.} \, A \rightarrow ^{ \varepsilon_{\mathrm{local}} } B \sqsubseteq A \rightarrow ^{ \varepsilon_{\mathrm{local}}' } \forall \, \alpha {.} \, B}\]

First, this rule means that, as , given a function of a type $ \forall \, \alpha {.} \, A \rightarrow ^{ \varepsilon_\mathrm{local} } B $ , its body can be regarded as a polymorphic computation of the type $ \forall \, \alpha {.} \, B$ . Suppose that the body performs operation, say, $\mathsf{op}_{{i}}$ . The effect $\varepsilon_\mathrm{local}$ in the LHS type requires $\mathsf{op}_{{i}}$ to return a value of type $D_{{i}}$ where type variable $\alpha$ has been replaced by, say, a type A’, while the effect $\varepsilon_\mathrm{local}'$ in the RHS type means that an implementation of the operation has to return a polymorphic value of the type $ \forall \, \alpha {.} \, D_{{i}}$ . This gap is bridged as follows: given a value of type $ \forall \, \alpha {.} \, D_{{i}}$ , the body can instantiate it with the type A’ used to instantiate the body. Because the instantiated value should be of type $ D [ A' {/} \alpha ] $ , it meets the requirement of the LHS type.

The above rule can be generalized slightly using existential types: when existential types of the form $ \text{}$ $ \, \alpha {.} \, A$ are available, we can allow $\alpha$ to occur in the parameter types $C_{{\mathrm{1}}}, \dots, C_{{n}}$ and instead set the type signature of each $\mathsf{op}_{{i}}$ in $\varepsilon_\mathrm{local}'$ to $ \forall \, \boldsymbol{ \beta_{{i}} } ^{ \text{I}_{i}}$ $ {.} \, {(} \text{}$ $ \, \alpha {.} \, C_{{i}} {)} \hookrightarrow \forall \, \alpha {.} \, D_{{i}} $ . Because an operation clause conforming to this type signature must be independent of the concrete type for $\alpha$ in $C_{{i}}$ and return a value polymorphic over $\alpha$ in $D_{{i}}$ , it can interpret any call to $\mathsf{op}_{{i}}$ in the function body no matter what type A’ is used to instantiate the body.

The two presented variants of the distributive law are designed so that the latent effect $\varepsilon_\mathrm{local}'$ satisfies the signature restriction. However, it is open whether such a property is necessary to prove type soundness. If it turns out to be unnecessary, the typing rule could be further generalized by setting the type signature of $\mathsf{op}_{{i}}$ in $\varepsilon_\mathrm{local}'$ to $ \forall \, \boldsymbol{ \beta_{{i}} }^{ \text{} }$ I_i $ {.} \forall \, \alpha {.} \, ( C_{{i}} \hookrightarrow D_{{i}} ) $ . Note that $ \forall \, \boldsymbol{ \beta_{{i}} }^{ \text{I}_{i}}$ $ {.} \forall \, \alpha {.} \, ( C_{{i}} \hookrightarrow D_{{i}} ) $ invalidates the signature restriction if $\alpha$ occurs nonstrictly positively in $C_{{i}}$ or negatively in $D_{{i}}$ . Because $ \forall \, \boldsymbol{ \beta_{{i}} }^{ \text{I}_{i}}$ $ {.} \, {(} \text{}$ $ \, \alpha {.} \, C_{{i}} {)} \hookrightarrow \forall \, \alpha {.} \, D_{{i}} $ is a “subtype” of $ \forall \,\boldsymbol{ \beta_{{i}} }^{ \text{ I}_{i}}$ $ \forall \,\boldsymbol{ \beta}_{i} ^{{I}_{i}}$ , the former imposes more restrictions on operation clauses for $\mathsf{op}_{{i}}$ than the latter.

Change 3: Type generalization.

A simple way to adapt type generalization to the local assignment is to allow type generalization only when effects do not refer to type variables being quantified:

\[ \frac{ \Gamma {,} \alpha \vdash {M} {:} A \, | \, \varepsilon_\mathrm{local} \quad \mathit{SR} \, {(} \varepsilon_\mathrm{local} {)} \quad \alpha \, \not\in \, \mathit{ftv} ( \varepsilon_\mathrm{local} ) \\}{\Gamma \vdash {M} {:} \forall \, \alpha {.} \, A \, | \, \varepsilon_\mathrm{local} }\]

where $ \mathit{ftv} ( \varepsilon_\mathrm{local} ) $ is the set of type variables that occur free in $\varepsilon_\mathrm{local}$ . This rule can also be generalized to allow $\alpha$ to occur in $\varepsilon_\mathrm{local}$ , as discussed in the previous paragraph, by assigning M an effect $\varepsilon_\mathrm{local}'$ where: the parameter and arity types of the type signatures quantify $\alpha$ existentially and universally, respectively; or the type signatures universally quantify $\alpha$ (if $\varepsilon_\mathrm{local}'$ does not have to satisfy the signature restriction to show type soundness).

6.3.2 Type containment with subeffecting

The type containment rule for function types requires the latent effects of the RHS and LHS types to be the same. However, we can relax this requirement by involving subeffecting in type containment, which allows the latent effect of the LHS type to be a subset of that of the RHS type, as in the previous work (Bauer and Pretnar, Reference Bauer and Pretnar2014). Although our type containment does not adopt subeffecting for simplicity, we can simulate it by eta-expansion. For example, given a function v of a type $ A \rightarrow ^{ \varepsilon } B $ and effect $\varepsilon' \, \supseteq \, \varepsilon$ , the eta-expansion $ \lambda\! \, x {.} {v} \, x$ of v can be of type $ A \rightarrow ^{ \varepsilon' } B $ because the body ${v} \, x$ can be typed with $\varepsilon'$ by . Therefore, we suspect that there is no challenge to support subeffecting in type containment.

7 Restriction on signatures versus restriction on handlers

Sekiyama and Igarashi (Reference Sekiyama and Igarashi2019) proposed another approach to safe polymorphic algebraic effects, which ensures the safety by posing an additional constraint on handler implementations. Table 1 summarizes the differences between their approach and ours (as well as the naive unsound approach). Perhaps surprisingly, despite these differences, the two approaches to sound polymorphic algebraic effects are closely related. This section aims to give a brief discussion on this connection, namely a translation from the Sekiyama-Igarashi (SI) type system to our type system.

Table 1. Features of type systems for polymorphic algebraic effects

Let us first explain the basic idea of the SI type system. The exposition here is informal and incomplete; see the paper (Sekiyama and Igarashi, Reference Sekiyama and Igarashi2019) for the formal and complete description of the type system.

Recall the following counterexample to the safety of the naive polymorphic algebraic effect system.

Since this is not type safe, a sound type system must reject this example. Sekiyama and Igarashi (Reference Sekiyama and Igarashi2019) focused on the handler implementation:

This handler has the two occurrences of resume, which takes arguments of the same type $\alpha \rightarrow \alpha$ , and Sekiyama and Igarashi (Reference Sekiyama and Igarashi2019) revealed that the source of the problem is the types for the arguments of the two occurrences of resume being the same. Actually, in the problematic run of the above program illustrated in Section 2.3, the type of the argument of the outer resume is instantiated to $ \mathsf{bool} \rightarrow \mathsf{bool} $ but that of the inner resume is $ \mathsf{int} \rightarrow \mathsf{int} $ . Therefore, their proposal is to regard the two occurrences of $\alpha \rightarrow \alpha$ as different types, say $\alpha_{{\mathrm{1}}} \rightarrow \alpha_{{\mathrm{1}}}$ for the argument of the outer resume and $\alpha_{{\mathrm{2}}} \rightarrow \alpha_{{\mathrm{2}}}$ for the argument of the inner resume. Then the above handler is not typable, since the argument of the inner resume has type $\alpha_{{\mathrm{2}}} \rightarrow \alpha_{{\mathrm{1}}}$ while it is expected to have $\alpha_{{\mathrm{2}}} \rightarrow \alpha_{{\mathrm{2}}}$ . We call a type system extended only with this idea (i.e, assigns fresh type variables to each occurrence of resume) the SI $_0$ system; the SI system is more powerful as seen shortly.

The idea of the SI $_0$ system can be explained in terms of the type signature of the effect get_id. Instead of the above given signature $ \forall \, \alpha {.} \, \mathsf{unit} \hookrightarrow {(} \alpha \rightarrow \alpha {)} $ , we should regard the type of get_id as $ \mathsf{unit} \hookrightarrow {(} \forall \, \alpha {.} \, \alpha \rightarrow \alpha {)}$ . Then the types of the two occurrences of the arguments of resume are $ \forall \, \alpha {.} \, \alpha \rightarrow \alpha$ . Since the type variable $\alpha$ in the type is bound, $\alpha$ for the outer resume actually differs from $\alpha$ for the inner resume. The resulting type signature satisfies the signature restriction (since both the argument and return types have no free type variable), and hence the type safety of the program is ensured by the argument of this article.

In general, the following two conditions are equivalent for every handler:

  • it is typable in the SI $_0$ system as a handler of op : $ \forall \, \alpha {.} \, A \hookrightarrow B $ ; and

  • it is typable in our system as a handler of op : $(\exists \, \alpha.\, A) \hookrightarrow {(} \forall \, \alpha {.} \, B {)}$ .

The safety of the latter follows from the signature restriction. Hence, our type system explains the SI system’s mechanism of fresh type variable assignment for resume.

However, the SI system is more powerful than the SI $_0$ system. To explain the difference, consider the following example, which is a minor modification of the previous example:

Note that the type of the argument of the operation get_id’ has the type variable $\alpha$ . This program is safe independent of an expression between handle and with (except for the case that the expression itself is unsafe). Unfortunately, this program cannot be typed in the SI $_0$ system, which only assigns fresh type variables to each occurrence of resume. Let $\alpha_{{\mathrm{1}}} \rightarrow \alpha_{{\mathrm{1}}}$ and $\alpha_{{\mathrm{2}}} \rightarrow \alpha_{{\mathrm{2}}}$ be the types of the arguments of the outer and inner resume, respectively. Then one occurrence of x requires that $\texttt{x} : \alpha_{{\mathrm{1}}}$ whereas the other implies $\texttt{x} : \alpha_{{\mathrm{2}}}$ , a contradiction.

The SI system has another mechanism that makes the above safe program well-typed. As we have seen, if the type of resume has a type variable $\alpha$ , each occurrence of resume in a handler introduces its fresh copy, say $\alpha_i$ . Their type system puts a special status to the arguments of the operator (x in the above example): a type variable $\alpha$ for the arguments can be identified with any copy $\alpha_i$ . This identification does not need to be consistent, i.e., $\texttt{x} : \alpha$ can be seen as $\texttt{x} : \alpha_{{\mathrm{1}}}$ in an occurrence of resume and $\texttt{x} : \alpha_{{\mathrm{2}}}$ in another occurrence.

One can mimic this mechanism in our type system by program transformation. The second mechanism allows an argument x of the operation may have many different types $\alpha, \alpha_1, \alpha_2, \dots$ depending on the occurrence of x; the number of the types for x is . We regard that x of different types are actually different variables (or different copies of x); each occurrence of resume takes a new copy of x. The translation $\longmapsto$ is given by

\begin{equation*} \begin{array}{lcl} \texttt{op} : \forall\,\alpha.\,A \hookrightarrow B &\quad\longmapsto\quad& \texttt{op}' : (\exists\,\alpha.\,A) \hookrightarrow (\forall\,\alpha.\,A \to B) \\ \texttt{op}(M) &\quad\longmapsto\quad& \texttt{let}\,x = M\,\texttt{in}\,\texttt{op}'(x)\,x \\ \mathtt{op}(x) \to \ldots (\texttt{resume}\,M) \ldots &\quad\longmapsto\quad& \mathtt{op}'(x) \to \ldots (\texttt{resume}\,(\lambda x. M)) \ldots . \end{array}\end{equation*}

After the translation, the caller passes the same argument twice and each resume in the handler takes a copy of x. This translation maps a well-typed program in the SI system to a well-typed program in our system. Footnote 9

8 Related work

8.1 Restriction for the use of effects in polymorphic type assignment

The problem that type safety is broken in naively combining polymorphic effects and polymorphic type assignment was initially discovered in a language with polymorphic references (Gordon et al., Reference Gordon, Milner and Wadsworth1979) and later in one with polymorphic control operators (Harper and Lillibridge, Reference Harper and Lillibridge1991, Reference Harper and Lillibridge1993). Researchers have developed many approaches to reconcile these conflicting features thus far (Tofte, Reference Tofte1990; Leroy and Weis, Reference Leroy and Weis1991; Appel and MacQueen, Reference Appel and MacQueen1991; Hoang et al., Reference Hoang, Mitchell and Viswanathan1993;Wright, Reference Wright1995; Garrigue, Reference Garrigue2004; Asai and Kameyama, Reference Asai and Kameyama2007; Sekiyama and Igarashi, Reference Sekiyama and Igarashi2019).

A major direction shared among them is to prevent the generalization of type variables assigned to an expression if the type variables are used to instantiate polymorphic effects triggered by the expression. Leroy and Weis (Reference Leroy and Weis1991) called such type variables dangerous. The value restriction (Tofte, Reference Tofte1990;Wright, Reference Wright1995), which allows only syntactic values to be polymorphic, is justified by this idea because these values trigger no effect and therefore no dangerous type variable exists. Similarly, Asai and Kameyama (Reference Asai and Kameyama2007) and Leijen (Reference Leijen2017) allowed only observationally pure expressions to be polymorphic. Tofte (Reference Tofte1990) proposed another approach that classifies type variables into applicative ones, which cannot be used to instantiate effects, and imperative ones, which may be used, and allows the generalization of only applicative type variables. Weak polymorphism (Appel and MacQueen, Reference Appel and MacQueen1991; Hoang et al., Reference Hoang, Mitchell and Viswanathan1993) extends this idea by assigning to a type variable the number of function applications necessary to trigger effects instantiated with the type variable. If the numbers assigned to type variables are positive, effects instantiated with the type variables are not triggered; therefore, they are not dangerous and can be generalized safely. Leroy and Weis (Reference Leroy and Weis1991) prevented the generalization of dangerous type variables by making the type information of free variables in closures accessible. These approaches focused on a specific effect (especially, the ML-style reference effect), but they can be applied to other effects as well.

One view for relating our work to these prior works is that, while the prior works suppose that no dangerous type variables can be generalized safely, our work discovers that they can be if the polymorphic effect of interest meets the signature restriction. Note that the assumption of the prior works is natural because they focus on the reference effect, which does not comply with the signature restriction. To see it, assume that we are given a type constructor $ A \, \mathsf{ref} $ for references pointing to values of type A. We also suppose that the reference effect supports an operation to create a new reference cell, and it is equipped with type signature $\forall \alpha. \alpha \hookrightarrow \alpha \, \mathsf{ref} $ . Because the polarities of the type variables appearing in a reference type $ A \, \mathsf{ref} $ are invariant (i.e., positive and negative), the type signature does not meet the signature restriction.

Garrigue (Reference Garrigue2004) proposed the relaxed value restriction, which allows the generalization of type variables assigned to an expression if the type variables occur only at positive positions in the type of the expression. The polarity condition on generalized type variables makes it possible to use the empty type as a surrogate of the type variables and, as a result, prevents instantiating effects with the type variables. The relaxed value restriction is similar to signature restriction in that both utilize the polarity of type variables. In fact, the strong signature restriction, introduced in Section 2.4, is explainable by using the empty type ${\mathsf{zero}}$ and subtyping $<:$ for it (i.e., deeming ${\mathsf{zero}}$ a subtype of any type) as in the relaxed value restriction. First, let us recall the key idea of the strong signature restriction: it is to rewrite an operation call $\Lambda \beta_1 \dots \beta_n.\,$ #op $\{C\}$ (v) for op : $\forall \alpha.\, A \hookrightarrow B$ to $\Lambda \beta_1 \dots \beta_n.\,$ #op $\{ \forall \beta_1 \dots \beta_n. \, C\}$ (v) to close the type argument C and to use provable type containment judgments $A[C/\alpha] \mathrel{ \sqsubseteq } A[\forall \beta_1 \dots \beta_n.\,C/\alpha]$ and $B[\forall \beta_1 \dots \beta_n.\,C/\alpha] \mathrel{ \sqsubseteq } B[C/\alpha]$ for typing the latter term. We can rephrase this idea with ${\mathsf{zero}}$ , instead of $\forall \beta_1 \dots\beta_n. \, C$ , as follows: the operation call is rewritten to $\Lambda\beta_1 \dots \beta_n.\,$ #op $\{ \mathsf{zero} \}$ (v), and this term can be typed by using the subtyping judgments $A[C/\alpha] \mathrel{<:} A[{\mathsf{zero}}/\alpha]$ and $B[{\mathsf{zero}}/\alpha] \mathrel{<:} B[C/\alpha]$ , which are provable owing to the polarity condition of the strong signature restriction (i.e., the type variable $\alpha$ occurs only negatively in the type A and only positively in the type B). However, this argument does not extend to the (non-strong) signature restriction because it allows the bound type variable $\alpha$ to occur at strictly positive positions in the parameter type A and then $A[C/\alpha]\mathrel{<:} A[{\mathsf{zero}}/\alpha]$ no longer holds. Thus, our technical contributions include the findings that the type argument C and value argument v can be closed by quantifying them and that $\forall \beta_1 \dots \beta_n.\,A[C/\alpha] \mathrel{ \sqsubseteq } A[\forall \beta_1 \dots \beta_n.\,C/\alpha]$ is provable by type containment, where the distributive law plays a key role. This change renders the signature restriction quite permissive.

Sekiyama and Igarashi (Reference Sekiyama and Igarashi2019) followed another line of research: they restricted the definitions of effects instead of their usage. As discussed in Section 7, their type system can be explained in our type system without effects. Furthermore, we provide an effect system that allows the use of both of the operations that satisfy and those that do not satisfy the restriction criterion—inasmuch as they are performed appropriately. The effect system utilizes the benefit of the signature restriction that it only depends on the type interfaces of effects.

Effect systems have been used to safely introduce effects in polymorphic type assignment thus far. Asai and Kameyama (Reference Asai and Kameyama2007) and Leijen (Reference Leijen2017) utilized effect systems for the control operators shift/reset (Danvy and Filinski, Reference Danvy and Filinski1990) and algebraic effects and handlers, respectively, to ensure that polymorphic expressions are observationally pure. Kammar and Pretnar (Reference Kammar and Pretnar2017) proposed an effect system for parameterized algebraic effects, which are declared with type parameters and invoked with type arguments. Unlike polymorphic effects, parameterized effects invoked with different type arguments are deemed different. Kammar and Pretnar utilized the effect system to prevent the generalization of the type variables involved by type arguments of parameterized effects.

8.2 User-defined effects

Our work employs algebraic effects and handlers as a technical development to describe a variety of effects. Algebraic effects were originally proposed as a denotational framework to describe the meaning of an effect by separating the interface of an effect, which is given by a set of operations, and its interpretation, which is given by the equational theory over the operations (Plotkin and Power, Reference Plotkin and Power2003). Plotkin and Pretnar (Reference Plotkin and Pretnar2013, Reference Plotkin and Pretnar2009) introduced effect handlers in order to represent the semantics of exception handling in an equational theory. The idea of separating an effect interface and its interpretation makes it possible to handle user-defined effects in a modular way and encourages the emergence of languages equipped with algebraic effect handlers, such as Eff (Bauer and Pretnar, Reference Bauer and Pretnar2015), Koka (Leijen, Reference Leijen2017), Frank (Lindley et al., Reference Lindley, McBride and McLaughlin2017), and Multicore OCaml (Dolan et al., Reference Dolan, Eliopoulos, Hillerström, Madhavapeddy, Sivaramakrishnan and White2017). We also utilize the separation and restrict only effect interfaces in order to achieve type safety in polymorphic type assignment.

Another approach to user-defined effects is to use control operators, which enable programmers to make access to continuations. Many control operators have been developed thus far—e.g., call/cc (Clinger et al., Reference Clinger, Friedman, Wand, Nivat and Reynolds1985), control/prompt (Felleisen, Reference Felleisen1988), shift/reset (Danvy and Filinski, Reference Danvy and Filinski1990), fcontrol/run (Sitaram, Reference Sitaram1993), and cupto/prompt (Gunter et al., Reference Gunter, Rémy and Riecke1995). These operators are powerful and generic, but, in return for that, it is unsafe to naively combine them with polymorphic type assignment (Harper and Lillibridge, Reference Harper and Lillibridge1993). They do not provide a means to assign fine-grained type interfaces to individual effects. Thus, it is not clear how to apply the idea of signature restriction for the effects implemented by control operators.

Monads can also express the interpretation of an effect in a denotational manner (Moggi, Reference Moggi1991) and have been used as a long-established, programmable means for user-defined effects (Wadler, Reference Wadler1992; Peyton Jones and Wadler, Reference Peyton Jones and Wadler1993). Filinski (Reference Filinski2010) extracted the essence of monadic effects and proposed a language equipped with a type system and an operation semantics for them. We expect our idea of restriction on effect interfaces to be applicable to monadic effects as well, but for that we would first need to consider how to introduce polymorphic effects into a monadic language because Filinski’s language supports parametric effects but not polymorphic effects.

9 Conclusion

This work addresses a classic problem with polymorphic effects in polymorphic type assignment. Our key idea is to restrict the type interfaces of effects. We formalized our idea with polymorphic algebraic effects and handlers, propose the signature restriction, which restricts the type signatures of operations by the polarity of occurrences of quantified type variables, and proved that a polymorphic type system is sound if all operations satisfy the signature restriction. We also gave an effect system in which operations performed by polymorphic expressions have to satisfy the signature restriction but those performed by monomorphic expressions do not have. This effect system enables us to use both the operations that satisfy and those that do not satisfy the signature restriction in a single program safely.

There are several directions for future work. First, we are interested in analyzing the signature restriction from a more semantic perspective. For example, the semantics of a language with control effects is often given by transformation to continuation-passing style (CPS). It would be interesting to study CPS transformation for implicit polymorphism by taking the signature restriction into account. Recently, Sekiyama and Tsukada (Reference Sekiyama and Tsukada2021) developed a type-preserving CPS transformation for Curry-style System F with the call-by-value semantics. The crux of their CPS transformation is that System F uses continuations only linearly. Type-preserving CPS transformation for the signature restriction would need a finer-grained constraint on continuations because the presence of algebraic effects and handlers allows the multiple uses of continuations. Another direction is to apply the signature restriction to evaluation strategies other than call-by-value. Harper and Lillibridge (Reference Harper and Lillibridge1993) showed that polymorphic type assignment and the polymorphic version of the control operator call/cc can be reconciled safely in call-by-name at the small cost of the expressive power and by changing the timing of type instantiation slightly. However, it is unclear—and we would imagine impossible—whether similar reconcilement is achievable in other strategies such as call-by-need and call-by-push-value. Exporting the idea of signature restriction to other evaluation strategies would be beneficial also for testing the robustness and developing a more in-depth understanding of signature restriction.

Acknowledgments

We would like to thank Yusuke Matsushita for a fruitful discussion at an early stage of the research and the anonymous reviewers of ICFP 2020 PC/AEC and JFP for their close reading and valuable comments. This work was supported in part by ERATO HASUO Metamathematics for Systems Design Project (No. JPMJER1603), JST and JSPS KAKENHI Grant Numbers JP19K20247 (Sekiyama), JP19K20211 (Tsukada), and JP15H05706 (Igarashi).

Conflicts of interest

None.

Supplementary material

For supplementary material for this article, please visit https://doi.org/10.1017/S0956796824000054.

Footnotes

1 We mean by full polymorphism that the type constructor $\forall$ can appear at any position of types, as in System F (Reynolds, Reference Reynolds1974; Girard, Reference Girard1972). Polymorphism is implicit if no type annotations are required, unlike System F.

2 As we will show in the article, signature restriction is permissive and actually we find no useful effect that invalidates it. However, the universal enforcement of signature restriction might give rise to inconvenience in some cases, and we consider the capability of avoiding such (potential) inconvenience important in designing a general-purpose programming language.

3 The translation inserts, as a replacement for type containment, functions that are computationally meaningless but work as type conversion statically.

4 This describes only intended semantics; one can also give an unintended handler, e.g., one that always returns an integer 42 for a call to select. Certain unintended handlers can be excluded in a polymorphic setting, as is shown in Section 2.2.

5 In this article, we suppose deep effect handlers (Kammar et al., Reference Kammar, Lindley and Oury2013), which remain in captured continuations.

6 Another way to incorporate polymorphism is parameterized effects, where the declaration of an operation is parameterized over types (Wadler, Reference Wadler1992).

7 More precisely, (the typing derivation for) the argument may refer to free type variables even when the type of the argument does not. However, we could address this situation successfully by eliminating them with closing type substitution as in Sekiyama and Igarashi (Reference Sekiyama and Igarashi2019).

8 We assume a calculus extended with existential types here and in Section 7.

9 What is left is the preservation of the operational semantics by the translation $\longmapsto$ . We have not given any formal proof of the semantics preservation, which is left for future development. This property should be obvious for some special cases, e.g., the case that arguments of resume are values that are hereditary effect-free.

References

Ahman, D. (2017) Fibred Computational Effects. Ph.D. thesis. University of Edinburgh.Google Scholar
Ahmed, A., Dreyer, D. & Rossberg, A. (2009) State-dependent representation independence. In Proceedings of the 36th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, POPL 2009, pp. 340353.CrossRefGoogle Scholar
Appel, A. W. & MacQueen, D. B. (1991) Standard ML of New Jersey. In 3rd International Symposium Programming Language Implementation and Logic Programming, PLILP 1991, Proceedings, pp. 1–13.CrossRefGoogle Scholar
Asai, K. & Kameyama, Y. (2007) Polymorphic delimited continuations. In 5th Asian Symposium Programming Languages and Systems, APLAS 2007, Proceedings, pp. 239254.CrossRefGoogle Scholar
Bauer, A. & Pretnar, M. (2014) An effect system for algebraic effects and handlers. Log. Methods Comput. Sci. 10(4).Google Scholar
Bauer, A. & Pretnar, M. (2015) Programming with algebraic effects and handlers. J. Log. Algebr. Methods Program. 84(1), 108123.CrossRefGoogle Scholar
Biernacki, D., Piróg, M., Polesiuk, P. & Sieczkowski, F. (2020) Binders by day, labels by night: effect instances via lexically scoped handlers. PACMPL. 4(POPL), 48:148:29.Google Scholar
Casinghino, C., Sjöberg, V. & Weirich, S. (2014) Combining proofs and programs in a dependently typed language. The 41st Annual ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, POPL 2014, pp. 33–46.CrossRefGoogle Scholar
Clinger, W. D., Friedman, D. P. & Wand, M. (1985) A scheme for a higher-level semantic algebra. In Algebraic Methods in Semantics, Nivat, M. & Reynolds, J. C. (eds), chapter 6, Cambridge University Press, pp. 237–250.Google Scholar
Cong, Y. & Asai, K. (2018) Handling delimited continuations with dependent types. PACMPL. 2(ICFP), 69:169:31.Google Scholar
Damas, L. & Milner, R. (1982) Principal type-schemes for functional programs. In Conference Record of the Ninth Annual ACM Symposium on Principles of Programming Languages, pp. 207212.CrossRefGoogle Scholar
Danvy, O. & Filinski, A. (1990) Abstracting control. In LISP and Functional Programming, pp. 151–160.CrossRefGoogle Scholar
Dolan, S., Eliopoulos, S., Hillerström, D., Madhavapeddy, A., Sivaramakrishnan, K. C. & White, L. (2017) Concurrent system programming with effect handlers. In Trends in Functional Programming - 18th International Symposium, TFP 2017, Revised Selected Papers, pp. 98–117.Google Scholar
Dreyer, D., Neis, G. & Birkedal, L. (2010) The impact of higher-order state and control effects on local relational reasoning. In Proceeding of the 15th ACM SIGPLAN International Conference on Functional Programming, ICFP 2010, pp. 143–156.CrossRefGoogle Scholar
Dunfield, J. & Krishnaswami, N. R. (2013) Complete and easy bidirectional typechecking for higher-rank polymorphism. In ACM SIGPLAN International Conference on Functional Programming, ICFP 2013, pp. 429–442.CrossRefGoogle Scholar
Felleisen, M. (1988) The theory and practice of first-class prompts. In Conference Record of the Fifteenth Annual ACM Symposium on Principles of Programming Languages, POPL 1988, pp. 180–190.CrossRefGoogle Scholar
Filinski, A. (2010) Monads in action. In Proceedings of the 37th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, POPL 2010, pp. 483494.CrossRefGoogle Scholar
Forster, Y., Kammar, O., Lindley, S. & Pretnar, M. (2019) On the expressive power of user-defined effects: Effect handlers, monadic reflection, delimited control. J. Funct. Program. 29, e15.CrossRefGoogle Scholar
Garrigue, J. (2004) Relaxing the value restriction. In 7th International Symposium Functional and Logic Programming, FLOPS 2004, Proceedings, pp. 196–213.CrossRefGoogle Scholar
Girard, J. Y. (1972) Interprétation fonctionnelle et élimination des coupures de l’arithmétique d’ordre supérieur. Thèse de doctorat d’état. Université Paris 7.Google Scholar
Gordon, M. J. C., Milner, R. & Wadsworth, C. P. (1979) Edinburgh LCF. vol. 78. Lecture Notes in Computer Science. Springer.CrossRefGoogle Scholar
Gunter, C. A., Rémy, D. & Riecke, J. G. (1995) A generalization of exceptions and control in ml-like languages. In Proceedings of the Seventh International Conference on Functional Programming Languages and Computer Architecture, FPCA 1995, pp. 12–23.CrossRefGoogle Scholar
Harper, R. & Lillibridge, M. (1991) ML with callcc is unsound. Announcement on the Types Electronic Forum.Google Scholar
Harper, R. & Lillibridge, M. (1993) Explicit polymorphism and CPS conversion. In Conference Record of the Twentieth Annual ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, pp. 206219.CrossRefGoogle Scholar
Harper, R. & Lillibridge, M. (1993) Polymorphic type assignment and CPS conversion. Lisp Symb. Comput. 6(3-4), 361380.Google Scholar
Hoang, M., Mitchell, J. C. & Viswanathan, R. (1993) Standard ML-NJ weak polymorphism and imperative constructs. In Proceedings of the Eighth Annual Symposium on Logic in Computer Science (LICS ’93), pp. 1525.CrossRefGoogle Scholar
Kammar, O., Lindley, S. & Oury, N. (2013) Handlers in action. In ACM SIGPLAN International Conference on Functional Programming, ICFP 2013, pp. 145158.CrossRefGoogle Scholar
Kammar, O. & Pretnar, M. (2017) No value restriction is needed for algebraic effects and handlers. J. Funct. Program. 27, e7.CrossRefGoogle Scholar
Leijen, D. (2017) Type directed compilation of row-typed algebraic effects. In Proceedings of the 44th ACM SIGPLAN Symposium on Principles of Programming Languages, POPL 2017, pp. 486–499.CrossRefGoogle Scholar
Leijen, D. (2023) The Koka programming langauge. https://koka-lang.github.io/koka/doc/index.html.Google Scholar
Leivant, D. (1983) Polymorphic type inference. In Conference Record of the Tenth Annual ACM Symposium on Principles of Programming Languages, POPL 1983, pp. 8898.CrossRefGoogle Scholar
Leroy, X., Doligez, D., Frisch, A., Garrigue, J., Rémy, D. & Vouillon, J. (2020) The OCaml system release 4.10: Documentation and user’s manua.Google Scholar
Leroy, X. & Weis, P. (1991) Polymorphic type inference and assignment. In Proceedings of the 18th Annual ACM Symposium on Principles of Programming Languages, pp. 291302.CrossRefGoogle Scholar
Levy, P. B. (2001) Call-by-push-value. Ph.D. thesis. Queen Mary University of London, UK.Google Scholar
Lindley, S., McBride, C. & McLaughlin, C. (2017) Do be do be do. In Proceedings of the 44th ACM SIGPLAN Symposium on Principles of Programming Languages, POPL 2017, pp. 500514.CrossRefGoogle Scholar
Lindley, S., McBride, C., McLaughlin, C. & Convent, L. (2022) The Frank programming langauge https://github.com/frank-lang/frank.Google Scholar
Milner, R. (1978) A theory of type polymorphism in programming. J. Comput. Syst. Sci. 17(3), 348375.CrossRefGoogle Scholar
Milner, R., Tofte, M. & Harper, R. (1990) The Definition of Standard ML. MIT Press.Google Scholar
Mitchell, J. C. (1988) Polymorphic type inference and containment. Inf. Comput. 76(2/3), 211249.CrossRefGoogle Scholar
Moggi, E. (1991) Notions of computation and monads. Inf. Comput. 93(1), 5592.CrossRefGoogle Scholar
Pédrot, P. & Tabareau, N. (2020) The fire triangle: how to mix substitution, dependent elimination, and effects. PACMPL. 4(POPL), 58:158:28.Google Scholar
Peyton Jones, S. L., Vytiniotis, D., Weirich, S. & Shields, M. (2007) Practical type inference for arbitrary-rank types. J. Funct. Program. 17(1), 182.CrossRefGoogle Scholar
Peyton Jones, S. L. & Wadler, P. (1993) Imperative functional programming. In Conference Record of the Twentieth Annual ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, pp. 7184.CrossRefGoogle Scholar
Pitts, A. & Stark, I. (1998) Operational reasoning for functions with local state. In Higher Order Operational Techniques in Semantics, Gordon, A. & Pitts, A. (eds). Publications of the Newton Institute, Cambridge University Press, pp. 227–273. Available at: http://www.inf.ed.ac.uk/ stark/operfl.html.Google Scholar
Plotkin, G. D. & Power, J. (2003) Algebraic operations and generic effects. Appl. Categor. Struct. 11(1), 6994.CrossRefGoogle Scholar
Plotkin, G. D. & Pretnar, M. (2008) A logic for algebraic effects. In Proceedings of the Twenty-Third Annual IEEE Symposium on Logic in Computer Science, LICS. IEEE Computer Society, pp. 118129.CrossRefGoogle Scholar
Plotkin, G. D. & Pretnar, M. (2009) Handlers of algebraic effects. In 18th European Symposium on Programming Programming Languages and Systems, ESOP 2009, Held as Part of the Joint European Conferences on Theory and Practice of Software, ETAPS 2009, Proceedings, pp. 80–94.CrossRefGoogle Scholar
Plotkin, G. D. & Pretnar, M. (2013) Handling algebraic effects. Logical Methods in Computer Science. 9(4).Google Scholar
Reynolds, J. C. (1974) Towards a theory of type structure. In Programming Symposium, Proceedings Colloque sur la Programmation, pp. 408423.CrossRefGoogle Scholar
Reynolds, J. C. (1983) Types, abstraction and parametric polymorphism. In IFIP Congress, pp. 513–523.Google Scholar
Sekiyama, T. & Igarashi, A. (2017) Stateful manifest contracts. In Proceedings of the 44th ACM SIGPLAN Symposium on Principles of Programming Languages, POPL 2017, pp. 530544.CrossRefGoogle Scholar
Sekiyama, T. & Igarashi, A. (2019) Handling polymorphic algebraic effects. In Programming Languages and Systems – 28th European Symposium on Programming, ESOP 2019, Held as Part of the European Joint Conferences on Theory and Practice of Software, ETAPS 2019, Proceedings, pp. 353–380.CrossRefGoogle Scholar
Sekiyama, T. & Tsukada, T. (2021) CPS transformation with affine types for call-by-value implicit polymorphism. Proc. ACM Program. Lang. 5(ICFP), 130.CrossRefGoogle Scholar
Sekiyama, T., Tsukada, T. & Igarashi, A. (2020) Signature restriction for polymorphic algebraic effects. Proc. ACM Program. Lang. 4(ICFP), 117:1117:30.CrossRefGoogle Scholar
Sitaram, D. (1993) Handling control. In Proceedings of the ACM SIGPLAN’93 Conference on Programming Language Design and Implementation (PLDI), pp. 147–155.CrossRefGoogle Scholar
Swamy, N., Hritcu, C., Keller, C., Rastogi, A., Delignat-Lavaud, A., Forest, S., Bhargavan, K., Fournet, C., Strub, P., Kohlweiss, M., Zinzindohoue, J. K. & Béguelin, S. Z. (2016) Dependent types and multi-monadic effects in F. In Proceedings of the 43rd Annual ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, POPL 2016, pp. 256270.CrossRefGoogle Scholar
The Links team. (2022) The Links programming langauge https://links-lang.org/.Google Scholar
Tiuryn, J. & Urzyczyn, P. (1996) The subtyping problem for second-order types is undecidable. Proceedings, 11th Annual IEEE Symposium on Logic in Computer Science (LICS ’96), pp. 7485.CrossRefGoogle Scholar
Tofte, M. (1990) Type inference for polymorphic references. Inf. Comput. 89(1), 134.CrossRefGoogle Scholar
Wadler, P. (1992) The essence of functional programming. In Conference Record of the Nineteenth Annual ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, pp. 114.CrossRefGoogle Scholar
Wells, J. B. (1994) Typability and type-checking in the second-order lambda-calculus are equivalent and undecidable. In Proceedings of the Ninth Annual Symposium on Logic in Computer Science (LICS ’94), pp. 176185.CrossRefGoogle Scholar
Wright, A. K. (1995) Simple imperative polymorphism. Lisp Symb. Comput. 8(4), 343355.Google Scholar
Wright, A. K. & Felleisen, M. (1994) A syntactic approach to type soundness. Inf. Comput. 115(1), 3894.CrossRefGoogle Scholar
Xi, H. (2007) Dependent ML an approach to practical programming with dependent types. J. Funct. Program. 17(2), 215286.CrossRefGoogle Scholar
Figure 0

Fig 1. Syntax of $\lambda_{\text{eff}}$.

Figure 1

Fig 2. Semantics of $\lambda_{\text{eff}}$.

Figure 2

Fig 3. The type language.

Figure 3

Fig 4. Polymorphic type system for $\lambda_{\text{eff}}$.

Figure 4

Fig 5. The extended part of the syntax and semantics.

Figure 5

Fig 6. The extended part of the type system.

Figure 6

Fig 7. The effect system (excerpt).

Figure 7

Table 1. Features of type systems for polymorphic algebraic effects

Supplementary material: File

Sekiyama et al. supplementary material

Sekiyama et al. supplementary material

Download Sekiyama et al. supplementary material(File)
File 401.8 KB
Submit a response

Discussions

No Discussions have been published for this article.