Temporal Verification with Answer-Effect Modification

Type-and-effect systems are a widely-used approach to program verification, verifying the result of a computation using types, and the behavior using effects. This paper extends an effect system for verifying temporal, value-dependent properties on event sequences yielded by programs to the delimited control operators shift0/reset0. While these delimited control operators enable useful and powerful programming techniques, they hinder reasoning about the behavior of programs because of their ability to suspend, resume, discard, and duplicate delimited continuations. This problem is more serious in effect systems for temporal properties because these systems must be capable of identifying what event sequences are yielded by captured continuations. Our key observation for achieving effective reasoning in the presence of the delimited control operators is that their use modifies answer effects, which are temporal effects of the continuations. Based on this observation, we extend an effect system for temporal verification to accommodate answer-effect modification. Allowing answer-effect modification enables easily reasoning about traces that captured continuations yield. Another novel feature of our effect system is the support for dependently-typed continuations, which allows us to reason about programs more precisely. We prove soundness of the effect system for finite event sequences via type safety and that for infinite event sequences using a logical relation.

READ FULL TEXT VIEW PDF
04/26/2018

Temporal Answer Set Programming on Finite Traces

In this paper, we introduce an alternative approach to Temporal Answer S...
11/29/2018

Sequential Effect Systems with Control Operators

Sequential effect systems are a class of effect system that exploits inf...
07/23/2021

Type-based Enforcement of Infinitary Trace Properties for Java

A common approach to improve software quality is to use programming guid...
08/28/2020

On modularity in reactive control architectures, with an application to formal verification

Modularity is a central principle throughout the design process for cybe...
05/20/2021

From Verification to Causality-based Explications

In view of the growing complexity of modern software architectures, form...
01/14/2020

A unified method to decentralized state inference and fault diagnosis/prediction of discrete-event systems

The state inference problem and fault diagnosis/prediction problem are f...
02/16/2022

Galois connecting call-by-value and call-by-name

We establish a general framework for reasoning about the relationship be...

1. Introduction

1.1. Background: Type-and-Effect System for Temporal Verification

Type-and-effect (or, simply effect) systems are a widely-used approach to program verification, verifying the result of a computation using types, and the behavior using effects. Their usefulness and applicability have been proven in broad areas, such as memory management (Tofte/Talpin_1997_IC), deadlock-freedom (Padovani/Novara_2015_FORTE), and safe use of exceptions (Marino/Millstein_2009_TLDI) and continuations (Danvy/Filinski_1990_LFP). A benefit shared among these existing, various effect systems is compositionality: the verification of an expression rests only on the types and effects of its subexpressions.

Safety and liveness are major classes of verification properties addressed by many effect systems developed thus far. Safety means that nothing “bad” happens during the program execution. For example, the effect systems cited above focus on safety. A safety property can be ensured by formalizing “bad” things as “stuck” program states and then by proving that a well-typed program does not get stuck (Milner_1978_JCSS). Liveness properties state that something good will happen eventually. For instance, termination is a liveness property that can be ensured by effect systems (Boudol_2010_IC).

Safety and liveness generalize to temporal properties,111In this paper, we mean linear-time temporal properties by temporal properties. which specify sets of possibly infinite sequences (called traces) of events that programs yield. For instance, resource usage safety and starvation freedom are formulated as temporal properties.

Several works have proposed type and effect systems that expand the benefit of compositionality to the verification of temporal properties. Igarashi/Kobayashi_2002_POPL addressed the problem of resource usage analysis, which is a temporal safety property. Typestate-oriented programming (Aldrich/Sunshine/Saini/Sparks_2009_OOPSLA) is an approach to resource usage analysis and has a success in object-oriented programming. Skalka/Smith_2004_APLAS provided an effect system for reasoning about finite traces, and Gordon_2017_ECOOP; Gordon_2021_TOPLAS defined a generic framework that can model a variety of effect systems, including that proposed by Skalka and Smith, for verifying temporal safety properties. Kobayashi/Ong_2009_LICS proposed an expressive type system for general temporal properties.222More precisely, Kobayashi and Ong addressed branching-time temporal properties, which subsume linear-time ones. Their system supports only finite data domains, and infinite data domains such as integers cannot be handled directly. The effect system of Hofmann/Chen_2014_CSL-LICS can verify temporal properties expressed in an -regular language. Koskinen/Terauchi_2014_CSL-LICS proposed the notion of temporal effects, which manage the sets of finite and infinite event traces separately as effects, and presented a temporal effect system for higher-order functional programs with recursion. Their system is restricted by neither data domains nor the class of temporal properties. Nanjo/Unno/Koskinen/Terauchi_2018_LICS refined and generalized Koskinen and Terauchi’s temporal effect system to dependent temporal effects, which can specify finite and infinite event traces using value-dependent predicates.

While these systems address higher-order recursive programs, they are not yet expressive enough to verify temporal properties of programs in practical, real languages. Especially crucial among a number of missing features are control operators, which are capable of suspending, resuming, discarding, and duplicating a part of running computation, called a continuation. This ability of control operators enables useful and powerful programming techniques such as exceptions, generators, backtracking, modeling of nondeterminism and state, and any other monadic effects (Filinski_1994_POPL). Therefore, support for control operators leads to a general verification framework that accommodates these features. On the other hand, the use of the control operators hinders reasoning about the behavior of programs because reasoning methods must be aware of the manipulation of continuations. A few studies have focused on verification of temporal safety properties in the presence of control effects. Iwama/Igarashi/Kobayashi_2006_PEPM extended Igarashi/Kobayashi_2002_POPL’s type system to exceptions, and Gordon_2020_ECOOP extended the previous work (Gordon_2017_ECOOP) to certain tagged delimited control operators. However, to the best of our knowledge, there has been no work on verification of general temporal (especially, liveness) properties in the presence of control operators.

1.2. This Work

The aim of this work is to develop an effect system that verifies temporal properties of higher-order functional programs with control operators. Specifically, we focus on delimited control operators. As the name suggests, continuations captured by this kind of operators are delimited and behave as functions that execute the computations up to the closest delimiters. Therefore, the captured delimited continuations are composable. This is in contrast to the behavior of undelimited continuations captured by undelimited control operators such as call/cc (Clinger/Friedman/Wand_1985) because undelimited continuations never return the control to call sites. The composability is a key factor for delimited control operators to facilitate functional programming and become mainstream in control operators.

In general, temporal effect systems should be flow sensitive because they need to track event traces that arise according to the order of computation. However, it is challenging to build a flow sensitive effect system for control operators as their use makes control flow much complicated. For example, consider a program , which executes an expression and raises an event using the operation . The behavior of this program depends on how the expression operates its continuation. If captures and discards the continuation, the event will never happen because the operation is involved in the continuation. By contrast, if invokes the captured continuation twice, the event will also be raised twice. This indicates that precise temporal verification requires a methodology to reason about not only how expressions manipulate continuations, but also what traces the continuations generate.

Our key idea to track the information about continuations precisely is to extend the notion of answer types to answer effects. Answer types are the types of values returned by contexts up to closest delimiters (Danvy/Filinski_1990_LFP). Because answer types tell what captured continuations return, the tracking of answer types is crucial to ensure safe use of delimited continuations. Because this work is interested in temporal verification, we introduce a new notion of answer (temporal) effects, which represent traces yielded by the delimited contexts. The use of answer effects makes it possible to reason about the traces that captured continuations generate.

Correct and precise verification with answer effects, however, poses two challenges. First, we need a means to verify that an answer effect assumed by a call site of the continuation-capture operation specifies correctly what event will happen in what order in the remaining context. Second, for precise approximation, we need to address Answer-Effect Modification (AEM), which is a variant of Answer-Type Modification (ATM) (Danvy/Filinski_1990_LFP) for temporal effects. Briefly speaking, AEM, as well as ATM, is caused by the ability of delimited control operators to manipulate captured continuations in a flexible manner. Therefore, on one hand, this ability is a source of expressivity of delimited control operators. However, on the other hand, it allows modifying answer effects and hinders reasoning. We need a means to track how answer effects are modified for precise verification of programs utilizing delimited control operators.

In this paper, we present a dependent temporal effect system that accommodates AEM for temporal effects. Our system is an extension of Materzok/Biernacki_2011_ICFP’s effect system (MB), which allows ATM in the presence of the delimited control operators shift0/reset0 (Danvy/Filinski_1989_TR; Shan_2004_SFP), to temporal verification. Inspired by MB (and Danvy/Filinski_1990_LFP, which is the first work that proposes an effect system accommodating ATM), our effect system enriches typing judgments with both answer (types and) effects before and after modification, and propagates how answer effects are modified to outer contexts. Intuitively, answer effects before modification represent requirements for contexts, and answer effects after modification represent guarantees for meta-contexts (that is, the contexts of the closest delimited contexts). This require-and-guarantee view of AEM is also useful to address the first challenge mentioned above. In fact, we represent the assumption on continuations imposed by a call site of the continuation-capture operator shift0 as an answer effect before modification. Then, our effect system checks that the delimited context of the call site satisfies the assumption.

In our system, answer effects are temporal effects in the style of Nanjo/Unno/Koskinen/Terauchi_2018_LICS and represent finite and infinite traces yielded by programs. Nanjo et al.’s system can reason about what traces recursive functions yield. In addition to this ability, our effect system can address subtle interaction between recursive functions and contexts. Except for this point, we can adapt MB smoothly to reason about finite traces. This is unsurprising because predicting finite traces is a safety property (that is, predicting what happens when programs terminate) and MB is designed for type safety. Indeed, we prove soundness of the effect system with respect to finite traces as type safety. By contrast, reasoning about infinite traces involves a subtlety. In designing the effect system, we need to take into account the fact that an infinite trace is observable at the top-level of a program wherever it happens (e.g., even when it happens under one or more delimiters).

Our effect system is dependent in that it can address value-dependent predicates over traces (and first-order values) as in Nanjo/Unno/Koskinen/Terauchi_2018_LICS. In general, one must be careful to address effectful features in dependent type systems because their integration without restriction leads to inconsistency (Herbelin_2005_TLCA). Fortunately, it has been shown in literature that value-dependent (or, more generally, pure-computation-dependent) type systems can safely address various effectful features, including control operators (Herbelin_2012_LICS; Swamy-et.al_2016_POPL; Lepigre_2016_ESOP; Miquey_2017_ESOP; Ahman_2018_POPL; Cong/Asai_2018_ICFP).

A novelty of our system as a dependent type system is in the typing of captured continuations: it enables the types of captured continuations to depend on arguments. This new dependency empowers the effect system to express the traces yielded by a continuation using the arguments passed to it. The full use of this ability leads to more precise analysis of programs.

The contributions of this paper are summarized as follows.

  • We provide a dependent temporal effect system for the control operators shift0/reset0. By accommodating AEM, our effect system can effectively track finite and infinite traces of higher-order programs that use delimited continuations fully. We also demonstrate the usefulness of allowing AEM via examples.

  • Our system assigns dependent function types to captured continuations. This type assignment enables expressing a precise relationship between the input and output of the continuations.

  • We prove type safety of our language via progress and subject reduction (Felleisen/Hieb_1992_TCS). It implies not only that well-typed expressions never get stuck, but also that the effect system is sound with respect to reasoning about finite traces.

  • We prove soundness of the effect system with respect to infinite traces by defining a logical relation that relates only expressions yielding infinite traces specified by temporal effects, and then showing that it contains all well-typed expressions.

  • We have implemented the proposed effect system as a tool that can generate the constraints for temporal effects and can generate and solve the constraints for refinement types.

Organization of the remainder of this paper.

The rest of this paper is organized as follows. Section 2 provides an overview of our work with motivating examples. Section 3 defines the syntax and semantics of our language. Section 4 formalizes our effect system, presents typing examples, and states type safety. Section 5 presents our logical relation and shows the soundness property for infinite traces. Section 6 discusses related work, and Section 7 concludes. This paper only states key properties of the metatheory and omits the formal definitions of some well-known notions, auxiliary lemmas, and detailed proofs. The full definitions, lemmas, and proofs are found in the supplementary material. The supplementary material also includes an extension of the calculus to predicate polymorphism. The implementation of the effect system will be available as an artifact.

2. Overview

This section reviews dependent temporal effects and the delimited control operators shift0/reset0 and then presents challenges involved in integrating them via a few examples.

2.1. Temporal Effects

Temporal effects specify finite and infinite event traces yielded by expressions. In Nanjo/Unno/Koskinen/Terauchi_2018_LICS, a (dependent) temporal effect is a pair of a predicate on finite traces denoted by and predicate on infinite traces denoted by . An expression is assigned a type if: its terminating run produces a value of type and generates a finite trace such that is true; and its diverging run generates an infinite trace such that is true.

For example, consider the following function f in an ML-like language.

 let rec f n = if n = 0 then () else (ev[]; f (n-1))

This function uses the construct ev[], which raises the event and then returns the unit value (). Given a nonnegative number , the function f raises the event -times and then terminates. Therefore, the run of f n terminates with the sequence of event with length , for short. Otherwise, if is negative, the application f n diverges and yields the sequence of infinite repetition of event ; we write for it. Therefore, the behavior of the function f can be specified by a dependent function type .333The traces and can be expressed using the least and great fixpoint operators in the formalization. See Section 3.1.

Temporal effects enable temporal verification. Consider the following program.

 let rec wait ready =
   if ready () then (ev[]; ()) else (ev[]; wait ready)
 let rec send x ready receiver =
   wait ready; ev[]; receiver x; send (x+1) ready receiver
 let ready () = if * then true else false in
 let receiver x = print_int x in
 send 0 ready receiver

The function wait calls a given function ready repeatedly and finishes only when it returns true. Because wait raises the event if ready returns true, and the event otherwise, wait can be assigned a temporal effect , where the notation denotes the set of finite repetitions of , and, for a set of finite traces and a finite or infinite trace , denotes the set . The function send repeats the process of waiting for a receiver to be ready, raising the event , and sending a value to the receiver. The last three lines implement the functions ready and receiver, and then call send with them. The implementation of ready uses the nondeterministic Boolean choice *. The program send 0 ready receiver diverges with two possibilities. First, after finitely repeating waiting and sending, a call to the function wait diverges. Second, the waiting and sending actions are repeated infinitely. Therefore, a temporal effect of the program is

(1)

which indicates that the program diverges because no finite trace satisfies the false and that the event is always raised (i.e., some value is sent to the receiver) when has been raised (i.e., the receiver has become ready).

2.2. Delimited Control Operators shift0/reset0 and Answer-Type Modification

This section explains the behavior of the delimited control operators shift0/reset0. We suppose that reset0 is implemented by constructs of the form e$\rangle$, which evaluates expression e under a delimited context, and that shift0 is by k.e, which binds variable k to the delimited continuation up to the closest reset0 construct and then “shifts” the control from the reset0 construct to expression e.

For example, consider program f  with the function f defined as follows.

 let raise x = k.x
 let div x y = if y = 0 then raise "div_by_0" else x / y
 let f y = let z = div 42 y in if z mod 2 = 0 then "even" else 

"odd"

The function raise implements exception raising, and the function div raises an exception if divisor y is zero. The evaluation of the program f  starts with reducing the body of the reset0 construct:

The shift0 expression k."div_by_0" is at the redex position. Then, the reset0 expression is replaced with the body "div_by_0". Therefore, the program f  finally evaluates to the value "div_by_0".

As an example using continuations, consider an implementation of the nondeterministic choice.

 let choice () = k.(k true) @ (k false) in
 let x = choice () in let y = choice () in [x && y]

The operator @ concatenates given two lists. The first call to the function choice in the second line captures the delimited continuation let x =  in let y = choice () in [x && y] (where denotes the hole) and binds the variable k in the body (k true)  @ (k false) of the shift0 expression to the continuation. Then, k true represents the expression let x = true in let y = choice () in [x && y] obtained by filling the hole in with the argument true. The second call to choice in k true captures the continuation let y =  in [true && y] and concatenates the results of applying the continuation to true and false. Therefore, k true evaluates to [true && true; true && false], i.e., [true; false]. Similarly, k false evaluates to [false && true; false && false], i.e., [false; false], because x is replaced by false. Because the entire reset0 expression evaluates to (k true) @ (k false) with the substitution of for k, its result is [true; false] @ [false; false]. This is the list of all the possible outcomes of the expression x && y for any .

In the examples we have shown thus far, the type of a reset0 construct matches the type of its body. However, there exist programs that do not conform to this convention, as follows:

 let get_int () = k.fun (x:int) -> k (string_of_int x) in
 "Input number is " ^ (get_int ()) 42

where the function string_of_int converts integers to strings, and the operator ^ concatenates given strings. The program invokes shift0 via get_int. Therefore, the entire reset0 expression evaluates to the body of shift0, which is a function that invokes the captured continuation "Input number is " ^  with the string representation of a given integer x. Because the reset0 expression is applied to number 42, it evaluates to "Input number is 42". The notable point of this example is that the body of the reset0 expression is of the type string, but it returns a function. This type mismatch between the return values of reset0 constructs and their bodies is known as Answer-Type Modification (ATM).444ATM was first discussed for shift/reset (Danvy/Filinski_1990_LFP). Because, unlike shift0, shift delimit its body when invoked, ATM for shift/reset means that the types of reset bodies are modified at run time.

2.3. Temporal Effects Extended to Delimited Control Operators

2.3.1. Answer Effects and Answer-Effect Modification

The use of the delimited control operators makes reasoning about traces more complicated. For example, consider a program send 0 ready f with some function f, and send and ready defined in Section 2.1. As aforementioned, the program should diverge if the function f does not use shift0. However, otherwise, the program may terminate. For example, the program send 0 ready raise with the function raise in Section 2.2 diverges with the infinite trace or terminates with a finite trace in because: once ready returns true, the program calls raise after raising the events and ; the call to raise discards the delimited continuation; as a result, the run of the reset0 expression terminates.

To reason about the temporal behavior of such a program, we introduce the notion of answer effects, which are temporal effects of the delimited continuations. For example, consider a simple program k.; ev[]. For the shift0 construct in the program, the answer effect is because its delimited continuation ; ev[] termiantes after raising the event . The answer effect is used as the latent temporal effect of the continuation variable (i.e., the tempral effect caused by calling ). Hence, if the body only calls -times, the answer effect tells that the program yields trace .

It is noteworhy that the temporal effect of the entire reset0 expression is modified from the temporal effect of its body. The latter looks as if only is raised once, while the former may raise zero or more times and even may generate any other finite or infinite traces (depending on ). Inspired by ATM, we call this phenomenon Answer-Effect Modification (AEM).

Our effect system introduced in Section 4 accommodates AEM. This ability enables reasoning about our motivating example send 0 ready raise. The body (send 0 ready raise) looks as if it yields a trace conforming to the temporal effect (1). However, the function raise discards the delimited continuation and modifies the temporal effect of the entire reset0 to , which exactly specifies the traces that may be yielded before calling raise. We will detail this verification process in Section 4.3 after defining the effect system.

Remark.

AEM is ubiquitous in temporal verification for delimited control operators. It is caused by two features of them. One is the capability of capturing continuations. It leads to the necessity of knowing what happens in invoking captured continuations. The other is the ability to replace the continuations with other computation. AEM arises by using together these features indispensable to delimited control operators. Because temporal verification aims to reason about the intermediate states of program execution, addressing AEM seems unavoidable for precise verification. Note that it is not mandatory to support ATM for our aim. Indeed, ATM does not happen in all the above examples except for the one presented to explain ATM. In Section 4.3, we will introduce notation for verifying programs without ATM, which reduces complexity and improves readability.

2.3.2. Dependently Typed Continuations.

Our effect system also allows the types of captured continuations to depend on arguments. To see its usefulness, consider the program [wait choice] with the functions wait and choice defined in Section 2.1 and 2.2, respectively. This program calls choice to ask if a receiver is ready. The function choice captures the delimited continuation, binds it to variable k, and passes the value true and then false to it. The invocation of the continuation k with true immediately finishes after raising the event . The invocation with false calls wait recursively after raising , and then the same process will be repeated. Thus, the program diverges with the infinite trace . To verify this behavior, the effect system needs to ensure that the application k true terminates with finite trace and k false diverges with infinite trace . The ability of our effect system to allow captured continuations to be dependently typed enables this reasoning by specifying the behavior of k depending on which value, true or false, is passed.

3. : An event-raising -calculus with shift0/reset0

This section presents the syntax and semantics of our language , which is a call-by-value -calculus equipped with the control operators shift0/reset0, the event-raising operator, and recursion. In Nanjo/Unno/Koskinen/Terauchi_2018_LICS, all computations are sequentialized by the construct, and their language has a big-step semantics. We follow the former convention because it easily enforces predicates to be value-dependent. However, the semantics of our language is small-step, which enables us to prove type safety via progress and subject reduction.

3.1. Syntax

Figure 1. Syntax.

The syntax of is shown in Figure 1. We use the metavariables for variables ranging over values and terms, for predicate variables, for functions of terms, for events, for finite traces, and for infinite traces. Let be the finite set of all events. Then, and denote the sets of all the finite and infinite traces, respectively, of events in . We write for the empty trace, and and for the concatenation of and and that of and , respectively. Throughout this paper, we employ the overline notation for representing possibly empty finite sequences, and write for the length of a finite sequence. For example, is a finite sequence of variables, and is its length.

We first introduce a logic to represent temporal effects. It is a fixpoint logic over finite and infinite traces as well as first-order values such as integers. Terms are either variables or applications of term functions. We suppose that constants, finite and infinite traces, and their operations can be expressed as terms. Sorts, ranged over by , represent the types of terms and include base types . Predicates, ranged over by , consist of predicate variables, the least fixpoint operator , the greatest fixpoint operator , and primitive predicates such as the equality of constants and traces. We assume that in and occurs only positively in . Formulas, ranged over by , are standard. For example, the formula presented in Section 2.1 is expressed as and the formula is expressed as .

Programs are represented by expressions, ranged over by , and values, ranged over by . Expressions consist of: values; primitive operations with arguments ; function applications ; -expressions ; -expressions , which bind in ; event-raising expressions , which yield the event ; shift0 expressions , which bind in to continuations captured at run time; reset0 expressions , which delimit the context of expression ; and divergence at infinite trace , which is introduced as a technical device to prove soundness for infinite traces (see Section 5 for detail). Values include variables, constants (ranged over by ), and possibly partially applied -abstractions and recursive functions. We suppose that constants include Boolean values and . A -abstraction may take multiple arguments, binding argument variables in . We write for the function application when . Then, a function application is a value if and only if it is partial, that is, ; the same convention is also applied to recursive functions. For a recursive function , variables and denote arguments and the recursive function itself, respectively. The predicates and represent the finite and infinite traces yielded by the body , respectively. If , the predicate expresses the finite traces observable by the -th closest meta-context of a call site of the function (traces in are observed by the caller). Similarly, each predicate in stands for infinite traces observable for a certain (meta-)context. For example, the function wait in Section 2.1 is given the predicates corresponding to and as the ones for the caller. If wait interacts with meta-contexts via argument functions, and can contain more predicates. We will present such examples in Section 4. We use predicate variables and , together with the least and greatest fixpoint operators, to identify and , respectively. These predicate variables are replaced by the corresponding predicates at run time. Although our calculus is equipped with those kinds of the information about predicates (i.e., , , , and ) as annotations for the metatheory, it can be inferred automatically by constraint generation implemented in our tool.

This work distinguishes between -abstractions and recursive functions because it is convenient to prove soundness of the effect system for infinite traces. As shown in Section 5, our proof for the soundness property uses -abstractions to approximate a recursive function. In the proof, we need to distinguish between other recursive functions and the approximations. Introducing -abstractions as a different constructor enables it easily.

We define the notions of free variables, free predicate variables, and substitution of values, terms, and predicates as usual. We suppose that the metafunctions and return the free variables and free predicate variables, respectively, in a given syntactic entity (expressions, formulas, terms, etc. as well as types and effects introduced in Section 4). The entity is closed if and both return the empty set. Otherwise, it is open. We write (resp.  and ) for the expression obtained by substituting values (resp. predicate and term ) for the corresponding variables (resp.  and ) in in a capture-avoiding manner. We use the similar notation for other syntax categories such as formulas, types, and effects.

3.2. Semantics

Reduction rules


Evaluation rules


Figure 2. Semantics.

Figure 2 presents the call-by-value, small-step semantics of . It is a straightforward variant of the semantics of the languages in the previous work (Materzok/Biernacki_2011_ICFP; Nanjo/Unno/Koskinen/Terauchi_2018_LICS). Our semantics is defined by two relations: the reduction relation , which means that expression reduces to expression without raising events, and the evaluation relation , which means that evaluates to with finite trace .

Reduction is defined in a straightforward manner, following the previous work. The reduction of primitive operation depends on the metafunction , which maps tuples of operation and arguments to constants. Application of a -abstraction and recursive function reduces only when they are fully applied. In the application of a recursive function , the predicates are substituted for in the body because represent the finite parts of the temporal effects of , as mentioned in Section 3.1. Similarly, the predicates on infinite traces are substituted for .

The behavior of a reset0 expression depends on the evaluation result of the body . If evaluates to a value , then is the result of the entire reset0 expression. If invokes the shift0 operator, its context up to the closest reset0 construct is captured as the continuation. Such a context is formalized as pure evaluation contexts, ranged over by , which are evaluation contexts that contain no reset0 construct enclosing the hole . Evaluation contexts, ranged over by , and pure evaluation contexts are both defined at the top of Figure 2. Notice that only -expressions and reset0 expressions allow non-value expressions to be placed at redex positions. We write and for the expressions obtained by filling the holes in and with expression , respectively.

We can now formalize the interaction between shift0 and reset0. The reduction of an expression proceeds as follows. First, the pure evaluation context from the shift0 construct up to the closest reset0 construct is captured. Subsequently, the body is evaluated with the binding of to , which is a functional representation of the remaining context .

Evaluation is defined as the relation satisfying the rules shown at the middle in Figure 2. These rules imply that an expression evaluates by reducing its subterm or raising an event at a redex position. We write when expression evaluates to with finite trace in a finite number of steps. Formally, if and only if there exist some such that (if , ).

Finally, we define (valid) termination and divergence of an expression. We define valid evaluation results, ranged over by , as either values or the call to shift0 not enclosed by reset0. We write if and only if the evaluation of expression terminates at result with finite trace . We also define the divergence of expressions. In this work, as Koskinen/Terauchi_2014_CSL-LICS and Nanjo/Unno/Koskinen/Terauchi_2018_LICS, we assume that non-terminating evaluation yields infinite traces. This assumption can be enforced easily by, e.g., inserting an event-raising operation for every redex in a program. Under this assumption, an expression diverges at infinite trace , defined at the bottom of Figure 2 as , if and only if either of the following holds: for any finite prefix of , the evaluation of yields ; or, the evaluation of terminates at expression with finite trace such that (In this manner, the expression behaves as the “divergence” with ).

4. Dependent Temporal Effect System for

This section introduces a dependent temporal effect system for . It is based on the effect systems in the two previous works: Materzok/Biernacki_2011_ICFP, which enabled ATM and subtyping for shift0/reset0, and Nanjo/Unno/Koskinen/Terauchi_2018_LICS, which introduced dependent temporal effects. Our effect system extends these systems to handle AEM and allow dependent typing of continuations.

4.1. Types and Effects

Figure 3. Type syntax.

Figure 3 presents the syntax of types and effects in this work.

Value types, ranged over by , specify values. A refinement type , which binds in , specifies constants satisfying the predicate (i.e., is true). We write simply if is not important. A dependent function type , which binds in , specifies (partially applied) -abstractions and recursive functions that, given a value of , perform the computation specified by the type depending on the argument . We write if does not occur free in .

A computation type specifies the behavior of expressions, consisting of three components: a value type, which specifies the value of an expression (if its evaluation terminates); a temporal effect, which specifies finite and infinite traces yielded by the expression; and a control effect, which specifies the usage of the control operators in the expression.

Temporal effects, ranged over by , take the form of , where is a predicate on finite traces and is on infinite traces . Our effect system ensures that, if an expression is assigned temporal effect , the finite trace yielded by the terminating evaluation of satisfies (i.e., is true) and the infinite trace yielded by its diverging evaluation satisfies (i.e., is true). Our formalism with the small-step semantics also implies that finite traces yielded on the course of evaluating the expression are prefixes of some trace contained in or . We write simply to mean the temporal effect .

Control effects, ranged over by , characterize the use of the control operators in expressions. They take either the form or . The control effect , which we call pure, means that an expression never invokes the shift0 operator. An expression that operates shift0 is assigned an impure control effect , which binds the variable in the type ; we write if does not occur free in . Control effects are reminiscent of type representations for ATM in the previous work. Control effects without temporal effects correspond to effect annotations in Materzok/Biernacki_2011_ICFP, and dropping both temporal and control effects from results in pairs of initial and final answer types considered in Danvy/Filinski_1990_LFP.

First, we explain what control effects of the simple form mean; we call control effects of this form nondependent. Roughly speaking, the type represents what an invocation of shift0 requires for the context up to the closest reset0 construct, and represents what the invocation guarantees for the meta-context, i.e., the context of the reset0 construct. For detail, consider an expression where the expression is assigned a control effect . Then, the type expresses the requirement for the context . Namely, given an appropriate value , the resulting expression of filling the hole with must follow the type . Thus, the body supposes the variable , which is bound to , to be of a function type , where the type is of the appropriate values (it is decided by the context ). The type guarantees that the result of operating shift0 behaves as expected by the context of the reset0 construct. Because reduces to , the expression must follow the expectation of the outer context, that is, it must follow the type . For example, recall the program given in Section 2.3 (note that the sequential composition is encoded using the -constructor). Assume that the expression of type only calls -times. Then, the shift0 expression has a control effect . The temporal effects and represent the fact that the delimited continuation raises the event only once and the entire reset0 construct yields the trace , respectively.

While nondependent control effects are expressive enough to accommodate AEM, they cannot utilize the expressivity of dependent typing fully. Specifically, it is critical that the requirement for contexts cannot depend on values passed to the contexts. To see the problem, consider an expression , where repeats -times. This expression reduces to with and finally generates the trace . Therefore, we expect that the effect system assigns the temporal effect to the expression. This assignment is possible if the continuation variable is of the type , which states that the finite trace yielded by the continuation depends on the argument . However, nondependent control effects do not allow to have such a type; a control effect given to shift0 only allows continuation variables to nondependent function types of the form .

We solve this problem using dependent control effects of the form . The variable in this form stands for values passed to contexts. Because an expression with a value type passes a value of to its context when terminating, the type of is determined by the computation type involving the control effect. In general, a computation type represents that: the value of an expression follows type ; the traces yielded by the expression follow ; the context of the expression up to the closest reset0 construct must follow type when a value of is passed; and the closest reset0 construct behaves as specified by type . Dependent control effects allow the types of continuations to depend on arguments. For a shift0 expression with a control effect , if its context expects values of type to be passed, the continuation variable is given the dependent function type .

Let us now revisit the above example. Let be the delimited context under which the shift0 expression is placed, that is, . Given an integer value , the context raises event -times. Dependent control effects can describe this behavior as the requirement for the context. For example, the shift0 expression can be assigned the control effect for some and . Then, the continuation variable is assigned the dependent function type . This dependent type implies that, when terminating, the expressions and yield the finite traces and , respectively. Therefore, the body is assigned the temporal effect . The type of the body corresponds to the type in the control effect of the shift0 expression, and it specifies how the closest reset0 construct behaves. Therefore, the entire expression has the temporal effect , from which we can deduce that its evaluation terminates with the finite trace .

It is notable that the dependency of the control effects is added systematically, not ad-hoc, from Continuation Passing Style (CPS) transformation. To see it, we consider computation types which omit temporal effects. By adapting the CPS transformation for shift0/reset0 (Materzok/Biernacki_2011_ICFP), a computation type is transformed to . A computation type with a dependent control effect can be obtained by making the argument function type of dependent: . Furthermore, ones might consider that the entire function type can similarly be made dependent, as . This idea might be worth considering in general dependent type systems. However, it is meaningless in our system because our types and effects can depend only on first-order values, following the convention in many refinement type systems (Rondon/Kawaguchi/Jhala_2008_PLDI; Bengtson/Bhargavan/Fournet/Gordon/Maffeis_2011_TOPLAS; Unno/Kobayashi_2009_PPDP). The formal investigation of the relationship between dependent control effects and their CPS transformation is beyond the scope of this work, and is left for future work.

Typing contexts, ranged over by , are finite sequences of bindings of the form (variable is of value type ), ( denotes predicates on terms of sorts ), or ( is of sort ).

We introduce certain notation in what follows. We write and for the formulas and when . We also write for . When , , , and denote , , and , respectively. We write for where . A typing context , where and are fresh, is expressed as . Furthermore, denotes the set of variables and predicate variables bound by . We write when a closed formula is valid. It is extended to the validity of a formula with free variables bound in by quantifying the free variables with their sorts and assuming the refinement predicates. See the supplementary material for the formal semantics of the fixpoint logic and the extension of the validity to open formulas.

4.2. Type-and-Effect System

Our effect system consists of three kinds of judgments: well-formedness judgments for type-level constructs; subtyping judgments for types and effects; and typing judgments for expressions.

4.2.1. Well-formedness

Well-formedness is defined for every type-level construct. This paper only presents the judgment forms for well-formedness and omits the rules for them because most of the rules are standard or easy to understand; the full definitions are found in the supplementary material. The only exception is the rule for dependent control effects, which we explain in what follows. A judgment states that typing context is well formed. Judgments and state that type and formula , respectively, are well formed under . A judgment states that control effect with value type is well formed under . For a dependent control effect , a judgment can be derived if and . This rule indicates that continuations can depend on arguments of the type . A judgment states that predicate is a well-formed predicate on terms of sorts under . A judgment states that term is a well-formed term of sort under .

4.2.2. Typing

Typing rules   

[1.5ex]

[1.5ex]

[1.5ex]

[1.5ex]

[1.5ex]

[1.5ex]

[1.5ex]

[1.5ex]

[1.5ex]

Figure 4. Type-and-effect system.

Typing judgments take the form . Because the temporal effect implies that an expression terminates with the empty trace, and the control effect implies that an expression does not invoke the shift0 operator, the purity of an expression is represented by a judgment