Abstract
Traditionally, reasoning about programs under varying evaluation regimes (callbyvalue, callbyname etc.) was done at the metalevel, treating them as term rewriting systems. Levy’s callbypushvalue (CBPV) calculus provides a more powerful approach for reasoning, by treating CBPV terms as a common intermediate language which captures both callbyvalue and callbyname, and by allowing equational reasoning about changes to evaluation order between or within programs.
We extend CBPV to additionally deal with callbyneed, which is nontrivial because of shared reductions. This allows the equational reasoning to also support callbyneed. As an example, we then prove that callbyneed and callbyname are equivalent if nontermination is the only sideeffect in the source language.
We then show how to incorporate an effect system. This enables us to exploit static knowledge of the potential effects of a given expression to augment equational reasoning; thus a program fragment might be invariant under change of evaluation regime only because of knowledge of its effects.
You have full access to this open access chapter, Download conference paper PDF
Similar content being viewed by others
Keywords
1 Introduction
Programming languages based on the calculus have different semantics depending on the reduction strategy employed. Three common variants are callbyvalue, callbyname and callbyneed (with the third sometimes also referred to as “lazy evaluation” when data constructors defer evaluation of arguments until the data structure is traversed). Reasoning about such programs and their equivalence under varying reduction strategies can be difficult as we have to reason about metalevel reduction strategies and not merely at the object level.
Levy [17] introduced callbypushvalue (CBPV) to improve the situation. CBPV is a calculus with separated notions of value and computation. A characteristic feature is that each CBPV program encodes its own evaluation order. It is best seen as an intermediate language into which lambdacalculusbased sourcelanguage programs can be translated. Moreover, CBPV is powerful enough that programs employing callbyvalue or callbyname (or even a mixture) can be simply translated into it, giving an objectcalculus way to reason about the metalevel concept of reduction order.
However, CBPV does not enable us to reason about callbyneed evaluation. An intuitive reason is that callbyneed has “action at a distance” in that reduction of one subterm causes reduction of all other subterms that originated as copies during variable substitution. Indeed callbyneed is often framed using mutable stores (graph reduction [32], or reducing a thunk which is accessed by multiple pointers [16]). CBPV does not allow these to be encoded.
This work presents extended callbypushvalue (ECBPV), a calculus similar to CBPV, but which can capture callbyneed reduction in addition to callbyvalue and callbyname. Specifically, ECBPV adds an extra primitive which runs , with being evaluated the first time is used. On subsequent uses of , the result of the first run is returned immediately. The term is evaluated at most once. We give the syntax and type system of ECBPV, together with an equational theory that expresses when terms are considered equal.
A key justification for an intermediate language that can express several evaluation orders is that it enables equivalences between the evaluation orders to be proved. If there are no (side)effects at all in the source language, then callbyneed, callbyvalue and callbyname should be semantically equivalent. If the only effect is nondeterminism, then need and value (but not name) are equivalent. If the only effect is nontermination then need and name (but not value) are equivalent. We show that ECBPV can be used to prove such equivalences by proving the latter using an argument based on Kripke logical relations of varying arity [12].
These equivalences rely on the language being restricted to particular effects. However, one may wish to switch evaluation order for subprograms restricted to particular effects, even if the language itself does not have such a restriction. To allow reasoning to be applied to these cases, we add an effect system [20] to ECBPV, which allows the sideeffects of subprograms to be statically estimated. This allows us to determine which parts of a program are invariant under changes in evaluation order. As we will see, support for callbyneed (and action at a distance more generally) makes describing an effect system significantly more difficult than for callbyvalue.
Contributions. We make the following contributions:

We describe extended callbypushvalue, a version of CBPV containing an extra construct that adds support for callbyneed. We give its syntax, type system, and equational theory (Sect. 2).

We describe two translations from a lambdacalculus source language into ECBPV: one for callbyname and one for callbyneed (the first such translation) (Sect. 3). We then show that, if the source language has nontermination as the only effect, callbyname and callbyneed are equivalent.

We refine the type system of ECBPV so that its types also carry effect information (Sect. 4). This allows equivalences between evaluation orders to be exploited, both at ECBPV and source level, when subprograms are statically limited to particular effects.
2 Extended CallbyPushValue
We describe an extension to callbypushvalue with support for callbyneed. The primary difference between ordinary CBPV and ECBPV is the addition of a primitive that allows computations to be added to the environment, so that they are evaluated only the first time they are used. Before describing this change, we take a closer look at CBPV and how it supports callbyvalue and callbyname.
CBPV stratifies terms into values, which do not have sideeffects, and computations, which might. Evaluation order is irrelevant for values, so we are only concerned with how computations are sequenced. There is exactly one primitive that causes the evaluation of more than one computation, which is the computation . This means run the computation M, bind the result to x, and then run the computation N. (It is similar to in Haskell.) The evaluation order is fixed: M is always eagerly evaluated. This construct can be used to implement callbyvalue: to apply a function, eagerly evaluate the argument and then evaluate the body of the function. No other constructs cause the evaluation of more than one computation.
To allow more control over evaluation order, CBPV allows computations to be thunked. The term is a value that contains the thunk of the computation . Thunks can be duplicated (to allow a single computation to be evaluated more than once), and can be converted back into computations with . This allows callbyname to be implemented: arguments to functions are thunked computations. Arguments are used by forcing them, so that the computation is evaluated every time the argument is used. Effectively, there is a construct , which evaluates each time the variable is used by , rather than eagerly evaluating. (The variable is underlined here to indicate that it refers to a computation rather than a value: uses of it may have sideeffects.)
To support callbyneed, extended callbypushvalue adds another construct . This term runs the computation , with the computation is used. On subsequent uses of , the result of the first run is returned immediately. The computation is evaluated at most once. This new construct adds the “action at a distance” missing from ordinary CBPV.
We briefly mention that adding general mutable references to callbypushvalue would allow callbyneed to be encoded. However, reasoning about evaluation order would be difficult, and so we do not take this option.
2.1 Syntax
The syntax of extended callbypushvalue is given in Fig. 1. The parts are new here. The rest of the syntax is similar to CBPV.^{Footnote 1}
We assume two sets of variables: value variables and computation variables . While ordinary CBPV does not include computation variables, they do not of themselves add any expressive power to the calculus. The ability to use callbyneed in ECBPV comes from the construct used to bind the variable.^{Footnote 2}
There are two kinds of terms, value terms V, W which do not have sideeffects (in particular, are strongly normalizing), and computation terms M, N which might have sideeffects. Value terms include constants , and specifically the constant . There are no constant computation terms; value constants suffice (see Sect. 3 for an example). The value term suspends the computation ; the computation term runs the suspended computation . Computation terms also include ary tuples (where ranges over finite sets); the th projection of a tuple is . Functions send values to computations, and are computations themselves. Application is written , where is the argument and is the function to apply. The term is a computation that just returns the value , without causing any sideeffects. Eager sequencing of computations is given by , which evaluates until it returns a value, then places the result in and evaluates . For example, in , the term is evaluated once, and the result is duplicated. In , the term is still evaluated once, but its result is never used. Syntactically, both and (explained below) are rightassociative (so means ).
The primary new construct is . This term evaluates . The first time is evaluated (due to a use of inside ) it behaves the same as the computation . If returns a value , then subsequent uses of behave the same as . Hence only the first use of will evaluate . If is not used then is not evaluated at all. The computation variable bound inside the term is primarily used by eagerly sequencing it with other computations. For example,
uses twice: once where the result is bound to , and once where the result is bound to . Only the first of these uses will evaluate , so this term has the same semantics as . The term does not evaluate at all, and has the same semantics as .
With the addition of it is not in general possible to determine the order in which computations are executed statically. Uses of computation variables are given statically, but not all of these actually evaluate the corresponding computation dynamically. In general, the set of uses of computation variables that actually cause effects depends on runtime behaviour. This will be important when describing the effect system in Sect. 4.
The standard captureavoiding substitution of value variables in value terms is denoted \({V}[{x} \mapsto {W}]\). We similarly have substitutions of value variables in computation terms, computation variables in value terms, and computation variables in computation terms. Finally, we define the callbyname construct mentioned above as syntactic sugar for other CBPV primitives:
where is not free in .
Types are stratified into value types and computation types . Value types include the unit type, products and sum types. (It is easy to add further base types; we omit Levy’s empty types for simplicity.) Value types also include thunk types , which are introduced by and eliminated by . Computation types include ary product types for finite I, function types , and returner types . The latter are introduced by , and are the only types of computation that can appear on the left of either or (which are the eliminators of returner types). The type constructors and form an adjunction in categorical models. Finally, contexts map value variables to value types, and computation variables to computation types of the form . This restriction is due to the fact that the only construct that binds computation variables is , which only sequences computations of returner type. Allowing computation variables to be associated with other forms of computation type in typing contexts is therefore unnecessary. Typing contexts are ordered lists.
The syntax is parameterized by a signature, containing the constants c.
Definition 1
(Signature). A signature consists of a set of constants of type A for each value type A. All signatures contain .
2.2 Type System
The type system of extended callbypushvalue is a minor extension of the type system of ordinary callbypushvalue. Assume a fixed signature . There are two typing judgements, one for value types and one for computation types. The rules for the value typing judgement and the computation typing judgement are given in Fig. 2. Rules that add a new variable to the typing context implicitly require that the variable does not already appear in the context. The type system admits the usual weakening and substitution properties for both value and computation variables.
It should be clear that ECBPV is actually an extension of callbypushvalue. CBPV terms embed as terms that never use the highlighted forms. We translate callbyneed by encoding callbyneed functions as terms of the form
where \(x'\) is not free in M. This is a callbypushvalue function that accepts a thunk as an argument. The thunk is added to the context, and the body of the function is executed. The first time the argument is used (via ), the computation inside the thunk is evaluated. Subsequent uses do not run the computation again. A translation based on this idea from a callbyneed source language is given in detail in Sect. 3.2.
2.3 Equational Theory
In this section, we present the equational theory of extended callbypushvalue. This is an extension of the equational theory for CBPV given by Levy [17] to support our new constructs. It consists of two judgement forms, one for values and one for computations:
These mean both terms are well typed, and are considered equal by the equational theory. We frequently omit the context and type when they are obvious or unimportant.
The definition is given by the axioms in Fig. 3. Note that these axioms only hold when the terms they mention have suitable types, and when suitable constraints on free variables are satisfied. For example, the second sequencing axiom holds only if is not free in N. These conditions are left implicit in the figure. The judgements are additionally reflexive (assuming the typing holds), symmetric and transitive. They are also closed under all possible congruence rules. There are no restrictions on congruence related to evaluation order. None are necessary because ECBPV terms make the evaluation order explicit: all sequencing of computations uses and . Finally, note that enriching the signature with additional constants will in general require additional axioms capturing their behaviour; Sect. 3 exemplifies this for constants representing nontermination.
For the equational theory to capture callbyneed, we might expect computation terms that are not of the form to never be duplicated, since they should not be evaluated more than once. There are two exceptions to this. Such terms can be duplicated in the axioms that duplicate value terms (such as the laws for sum types). In this case, the syntax ensures such terms are thunked. This is correct because we should allow these terms to be executed once in each separate execution of a computation (and separate executions arise from duplication of thunks). We are only concerned with duplication within a single computation. Computation terms can also be duplicated across multiple elements of a tuple of computation terms. This is also correct, because only one component of a tuple can be used within a single computation (without thunking), so the effects still will not happen twice. (There is a similar consideration for functions, which can only be applied once.) The remainder of the axioms never duplicate bound terms that might have effects.
The majority of the axioms of the equational theory are standard. Only the axioms involving are new; these are highlighted. The first new sequencing axiom (in Fig. 3c) is the crucial one. It states that if a computation will next evaluate , where is a computation variable bound to M, then this is the same as evaluating M, and then using the result for subsequent uses of . In particular, this axiom (together with the law for ) implies that .
The second sequencing axiom does garbage collection [22]: if a computation bound by is not used (because the variable does not appear), then the binding can be dropped. This equation implies, for example, that
The next four sequencing axioms (two from CBPV and two new) state that binding a computation with or commutes with the remaining forms of computation terms. These allow and to be moved to the outside of other constructs except thunks. The final four axioms (one from CBPV and three new) capture associativity and commutativity involving and ; again these parallel the existing simple associativity axiom for .
Note that associativity between different evaluation orders is not necessarily valid. In particular, we do not have
(The first term might not evaluate \(M_1\), the second always does.) This is usually the case when evaluation orders are mixed [26].
These final two groups allow computation terms to be placed in normal forms where bindings of computations are on the outside. (Compare this with the translation of sourcelanguage answers given in Sect. 3.2.) Finally, the law for (in Fig. 3a) parallels the usual \(\beta \) law for : it gives the behaviour of computation terms that return values without having any effects.
The above equational theory induces a notion of contextual equivalence between ECBPV terms. Two terms are contextually equivalent when they have no observable differences in behaviour. When we discuss equivalences between evaluation orders in Sect. 3, is the notion of equivalence between terms that we consider.
Contextual equivalence is defined as follows. The ground types G are the value types that do not contain thunks:
A valueterm context is a computation term with a single hole (written \(\)), which occurs in a position where a value term is expected. We write for the computation term that results from replacing the hole with V. Similarly, computationterm contexts are computation terms with a single hole where a computation term is expected, and is the term in which the hole is replaced by M. Contextual equivalence says that the terms cannot be distinguished by closed computations that return ground types. (Recall that \(\diamond \) is the empty typing context.)
Definition 2
(Contextual equivalence). There are two judgement forms of contextual equivalence.

1.
Between value terms: if , , and for all ground types G and valueterm contexts such that and we have

2.
Between computation terms: if , , and for all ground types G and computationterm contexts such that and we have
3 CallbyName and CallbyNeed
Extended callbypushvalue can be used to prove equivalences between evaluation orders. In this section we prove a classic example: if the only effect in the source language is nontermination, then callbyname is equivalent to callbyneed. We do this in two stages.
First, we show that callbyname is equivalent to callbyneed within ECBPV (Sect. 3.1). Specifically, we show that
(Recall that is syntactic sugar for .)
Second, an important corollary is that the metalevel reduction strategies are equivalent (Sect. 3.2). We show this by describing a lambdacalculusbased source language together with a callbyname and a callbyneed operational semantics and giving sound (see Theorem 2) callbyname and callbyneed translations into ECBPV. The former is based on the translation into the monadic metalanguage given by Moggi [25] (we expect Levy’s translation [17] to work equally well). The callbyneed translation is new here, and its existence shows that ECBPV does indeed subsume callbyneed. We then show that given any sourcelanguage expression, the two translations give contextually equivalent ECBPV terms.
To model nontermination being our sole sourcelanguage effect, we use the ECBPV signature which contains a constant for each value type A, representing a thunked diverging computation. It is likely that our proofs still work if we have general fixedpoint operators as constants, but for simplicity we do not consider this here. The constants \(\bot _A\) enable us to define a diverging computation for each computation type :
We characterise nontermination by augmenting the equational theory of Sect. 2.3 with the axiom
for each context , value type A and computation type . In other words, diverging as part of a larger computation causes the entire computation to diverge. This is the only change to the equational theory we need to represent nontermination. In particular, we do not add additional axioms involving .
3.1 The Equivalence at the Object (Internal) Level
In this section, we show our primary result that
As is usually the case for proofs of contextual equivalence, we use logical relations to get a strong enough inductive hypothesis for the proof to go through. However, unlike the usual case, it does not suffice to relate closed terms. To see why, consider a closed term M of the form
If we relate only closed terms, then we do not learn anything about itself (since may be free in it). We could attempt to proceed by considering the closed term . For example, if this returns a value V then cannot have been evaluated and M should have the same behaviour as . However, we get stuck when proving the last step. This is only a problem because is a nonterminating computation: every terminating computation of returner type has the form (up to ), and when these are bound using we can eliminate the binding using the equation
The solution is to relate terms that may have free computation variables (we do not need to consider free value variables). The free computation variables should be thought of as referring to nonterminating computations (because we can remove the bindings of variables that refer to terminating computations). We relate open terms using Kripke logical relations of varying arity, which were introduced by Jung and Tiuryn [12] to study lambda definability.
We need a number of definitions first. A context \({\varGamma }'\) weakens another context \({\varGamma }\), written , whenever \({\varGamma }\) is a sublist of \({\varGamma }'\). For example, . We define as the set of equivalence classes (up to the equational theory ) of terms of value type A in context \({\varGamma }\), and similarly define for computation types:
Since weakening is admissible for both typing judgements, implies that and (note the contravariance).
A computation context, ranged over by \({\varDelta }\), is a typing context that maps variables to computation types (i.e. has the form ). Variables in computation contexts refer to nonterminating computations for the proof of contextual equivalence. A Kripke relation is a family of binary relations indexed by computation contexts that respects weakening of terms:
Definition 3
(Kripke relation). A Kripke relation R over a value type A (respectively a computation type ) is a family of relations (respectively ) indexed by computation contexts \({\varDelta }\) such that whenever we have .
Note that we consider binary relations on equivalence classes of terms because we want to relate pairs of terms up to (to prove contextual equivalence). The relations we define are partial equivalence relations (i.e. symmetric and transitive), though we do not explicitly use this fact.
We need the Kripke relations we define over computation terms to be closed under sequencing with nonterminating computations. (For the rest of this section, we omit the square brackets around equivalence classes.)
Definition 4
A Kripke relation R over a computation type is closed under sequencing if each of the following holds:

1.
If and then .

2.
The pair is in \(R^{\varDelta }\).

3.
For all and , all four of the following pairs are in \(R^{\varDelta }\):
$$\begin{aligned} (N \mathbin {\mathsf {need}}\underline{y}.\,M,~N \mathbin {\mathsf {need}}\underline{y}.\,M') \quad&\quad ({M}[{\underline{y}} \mapsto {N}],~{M'}[{\underline{y}} \mapsto {N}]) \\ ({M}[{\underline{y}} \mapsto {N}],~N \mathbin {\mathsf {need}}\underline{y}.\,M') \quad&\quad (N \mathbin {\mathsf {need}}\underline{y}.\,M,~{M'}[{\underline{y}} \mapsto {N}]) \end{aligned}$$
For the first case of the definition, recall that the computation variables in \({\varDelta }\) refer to nonterminating computations. Hence the behaviour of M and \(M'\) are irrelevant (they are never evaluated), and we do not need to assume they are related.^{Footnote 3} The second case implies (using axiom Omega) that
mirroring the first case. The third case is the most important. It is similar to the first (it is there to ensure that the relation is closed under the primitives used to combine computations). However, since we are showing that is contextually equivalent to substitution, we also want these to be related. We have to consider computation variables in the definition (as possible terms N) only because of our use of Kripke logical relations. For ordinary logical relations, there would be no free variables to consider.
The key part of the proof of contextual equivalence is the definition of the Kripke logical relation, which is a family of relations indexed by value and computation types. It is defined in Fig. 4 by induction on the structure of the types. In the figure, we again omit square brackets around equivalence classes.
The definition of the logical relation on ground types (\(\mathbf {unit}\), sum types and product types) is standard. Since the only way to use a thunk is to force it, the definition on thunk types just requires the two forced computations to be related.
For returner types, we want any pair of computations that return related values to be related. We also want the relation to be closed under sequencing, in order to show the fundamental lemma (below) for and . We therefore define as the smallest such Kripke relation. For products of computation types the definition is similar to products of value types: we require that each of the projections are related. For function types, we require as usual that related arguments are sent to related results. For this to define a Kripke relation, we have to quantify over all computation contexts \({\varDelta }'\) that weaken \({\varDelta }\), because of the contravariance of the argument.
The relations we define are Kripke relations. Using the sequencing axioms of the equational theory, and the \(\beta \) and \(\eta \) laws for computation types, we can show that \(R_{\underline{C}}\) is closed under sequencing for each computation type \(\underline{C}\). These facts are important for the proof of the fundamental lemma.
Substitutions are given by the following grammar:
We have a typing judgement \({\varDelta } \vdash \sigma : {\varGamma }\) for substitutions, meaning in the context \({\varDelta }\) the terms in \(\sigma \) have the types given in \({\varGamma }\). This is defined as follows:
We write \(V[\sigma ]\) and \(M[\sigma ]\) for the applications of the substitution \(\sigma \) to value terms V and computation terms M. These are defined by induction on the structure of the terms. The key property of the substitution typing judgement is that if \({\varDelta } \vdash \sigma : {\varGamma }\), then implies and implies . The equational theory gives us an obvious pointwise equivalence relation on welltyped substitutions. We define sets of equivalence classes of substitutions, and extend the logical relation by defining :
As usual, the logical relations satisfy a fundamental lemma.
Lemma 1
(Fundamental)

1.
For all value terms \({\varGamma } \vdash _\mathrm {v} V : A\),

2.
For all computation terms ,
The proof is by induction on the structure of the terms. We use the fact that each is closed under sequencing for the and cases. For the latter, we also use the fact that the relations respect weakening of terms.
We also have the following two facts about the logical relation. The first roughly is that \(\mathsf {name}\) is related to by the logical relation, and is true because of the additional pairs that are related in the definition of closedundersequencing (Definition 4).
Lemma 2
For all computation terms and we have
The second fact is that related terms are contextually equivalent.
Lemma 3

1.
For all value terms \({\varGamma } \vdash _\mathrm {v} V : A\) and \({\varGamma } \vdash _\mathrm {v} V' : A\), if for all then

2.
For all computation terms and , if for all then
This gives us enough to achieve the goal of this section.
Theorem 1
For all computation terms and , we have
3.2 The Metalevel Equivalence
In this section, we show that the equivalence between callbyname and callbyneed also holds on the metalevel; this is a consequence of the objectlevel theorem, rather than something that is proved from scratch as it would be in a term rewriting system.
To do this, we describe a simple lambdacalculusbased source language with divergence as the only sideeffect and give it a callbyname and a callbyneed operational semantics. We then describe two translations from the source language into ECBPV. The first is a callbyname translation based on the embedding of callbyname in Moggi’s [25] monadic metalanguage. The second is a callbyneed translation that uses our new constructs. The latter witnesses the fact that ECBPV does actually support callbyneed. Finally, we show that the two translations give contextually equivalent ECBPV terms.
The syntax, type system and operational semantics of the source language are given in Fig. 5. Most of this is standard. We include only booleans and function types for simplicity. In expressions, we include a constant \({\mathsf {diverge}_{A}}\) for each type A, representing a diverging computation. (As before, it should not be difficult to replace these with general fixedpoint operators.) In typing contexts, we assume that all variables are distinct, and omit the required sidecondition from the figure. There is a single set of variables \(x, y, \dots \); we implicitly map these to ECBPV value or computation variables as required.
The callbyname operational semantics is straightforward; its smallstep reductions are written .
The callbyneed operational semantics is based on Ariola and Felleisen [2]. The only differences between the source language and Ariola and Felleisen’s calculus are the addition of booleans, \({\mathsf {diverge}_{A}}\), and a type system. It is likely that we can translate other callbyneed calculi, such as those of Launchbury [16] and Maraist et al. [22]. Callbyneed smallstep reductions are written \(e \overset{\mathrm {need}}{\mathbin {\rightsquigarrow }}e'\).
The callbyneed semantics needs some auxiliary definitions. An evaluation context \(E[]\) is a sourcelanguage expression with a single hole, picked from the grammar given in the figure. The hole in an evaluation context indicates where reduction is currently taking place: it says which part of the expression is currently needed. We write E[e] for the expression in which the hole is replaced with e. A (sourcelanguage) value is the result of a computation (the word value should not be confused with the value terms of extended callbypushvalue). An answer is a value in some environment, which maps variables to expressions. These can be thought of as closures. The environment is encoded in an answer using application and lambda abstraction: the answer \((\lambda x.\,a)\,e\) means the answer a where the environment maps x to e. Encoding environments in this way makes the translation slightly simpler than if we had used a Launchburystyle [16] callbyneed language with explicit environments. In the latter case, the translation would need to encode the environments. Here they are already encoded inside expressions. Answers are terminal computations: they do not reduce.
The first two reduction axioms (on the left) of the callbyneed semantics (Fig. 5d) are obvious. The third axiom is the most important: it states that if the subexpression currently being evaluated is a variable x, and the environment maps x to a sourcelanguage value v, then that use of x can be replaced with v. Note that E[v] may contain other uses of x; the replacement only occurs when the value is actually needed. This axiom roughly corresponds to the first sequencing axiom of the equational theory of ECBPV (in Fig. 3c). The fourth and fifth axioms of the callbyneed operational semantics rearrange the environment into a standard form. Both use a syntactic restriction to answers so that each expression has at most one reduct (this restriction is not needed to ensure that captures callbyneed). The rule on the right of the Fig. 5d states that the reduction relation is a congruence (a needed subexpression can be reduced).
The two translations from the source language to ECBPV are given in Fig. 6. The translation of types (Fig. 6a) is shared between callbyname and callbyneed. The two translations differ only for contexts and expressions. Types A are translated into value types . The type becomes the twoelement sum type \(\mathbf {unit}+ \mathbf {unit}\). The translation of a function type \(A \rightarrow B\) is a thunked CBPV function type. The argument is a thunk of a computation that returns an , and the result is a computation that returns a .
For callbyname (Fig. 6b), contexts \({\varGamma }\) are translated into contexts that contain thunks of computations. We could also have used contexts containing computation variables (omitting the thunks), but choose to use thunks to keep the translation as close as possible to previous translations into callbypushvalue. A welltyped expression is translated into a ECBPV computation term that returns , in context . The translation of variables just forces the relevant variable in the context. The diverging computations \({\mathsf {diverge}_{A}}\) just use the diverging constants from our ECBPV signature. The translations of \(\mathsf {true}\) and \(\mathsf {false}\) are simple: they are computations that immediately return one of the elements of the sum type \(\mathbf {unit}+ \mathbf {unit}\). The translation of first evaluates , then uses the result to choose between and . Lambdas are translated into computations that just return a thunked computation. Finally, application first evaluates the computation that returns a thunk of a function, and then forces this function, passing it a thunk of the argument.
For callbyneed (Fig. 6c), contexts \({\varGamma }\) are translated into contexts , containing computations that return values. The computations in the context are all bound using . An expression is translated to a computation that returns in the context . The typing is therefore similar to callbyname. The key case is the translation of lambdas. These become computations that immediately return a thunk of a function. The function places the computation given as an argument onto the context using , so that it is evaluated at most once, before executing the body. The remainder of the cases are similar to callbyname.
Under the callbyneed translation, the expression is translated into a term that executes the computation , and executes only when needed. This is the case because, by the \(\beta \) rules for thunks, functions, and returner types:
As a consequence, translations of answers are particularly simple: they have the following form (up to ):
which intuitively means the value V in the environment mapping each to \(M_i\).
It is easy to see that both translations produce terms with the correct types. We prove that both translations are sound: if \(e \overset{\mathrm {name}}{\mathbin {\rightsquigarrow }}e'\) then , and if \(e \overset{\mathrm {need}}{\mathbin {\rightsquigarrow }}e'\) then . To do this for callbyneed, we first look at translations of evaluation contexts. The following lemma says the translation captures the idea that the hole in an evaluation context corresponds to the term being evaluated.
Lemma 4
Define, for each evaluation context \(E[]\), the term by:
For each expression e we have:
This lemma omits the typing of expressions for presentational purposes. It is easy to add suitable constraints on typing. Soundness is now easy to show:
Theorem 2 (Soundness)
For any two welltyped sourcelanguage expressions :

1.
If then .

2.
If \(e \overset{\mathrm {need}}{\mathbin {\rightsquigarrow }}e'\) then .
Now that we have sound callbyname and callbyneed translations, we can state the metalevel equivalence formally. Suppose we are given a possibly open sourcelanguage expression . Recall that the callbyneed translation uses a context containing computation variables (i.e. ) and the callbyname translation uses a context containing value variables, which map to thunks of computations. We have two ECBPV computation terms of type in context : one is just , the other is with all of its variables substituted with thunked computations. The theorem then states that these are contextually equivalent.
Theorem 3 (Equivalence between callbyname and callbyneed)
For all sourcelanguage expressions e satisfying
Proof
The proof of this theorem is by induction on the typing derivation of e. The interesting case is lambda abstraction, where we use the internal equivalence between callbyname and callbyneed (Theorem 1).
4 An Effect System for Extended CallbyPushValue
The equivalence between callbyname and callbyneed in the previous section is predicated on the only effect in the language being nontermination. However, suppose the primitives of language have various effects (which means that in general the equivalence fails) but a given subprogram may be statically shown to have at most nontermination effects. In this case, we should be allowed to exploit the equivalence on the subprogram, interchanging callbyneed and callbyname locally, even if the rest of the program uses other effects. In this section, we describe an effect system [20] for ECBPV, which statically estimates the sideeffects of expressions, allowing us to exploit equivalences which hold only within subprograms. Effect systems can also be used for other purposes, such as proving the correctness of effectdependent program transformations [7, 29]. The ECBPV effect system also allows these.
Callbyneed makes statically estimating effects difficult. Computation variables bound using might have effects on their first use, but on subsequent uses do not. Hence to precisely determine the effects of a term, we must track which variables have been used. McDermott and Mycroft [23] show how to achieve this for a callbyneed effect system; their technique can be adapted to ECBPV. Here we take a simpler approach. By slightly restricting the effect algebras we consider, we remove the need to track variable usage information, while still ensuring the effect information is not an underestimate (an underestimate would enable incorrect transformations). This can reduce the precision of the effect information obtained, but for our use case (determining equivalences between evaluation orders) this is not an issue, since we primarily care about which effects are used (rather than e.g. how many times they are used).
4.1 Effects
The effect system is parameterized by an effect algebra, which specifies the information that is tracked. Different effect algebras can be chosen for different applications. There are various forms of effect algebra. We follow Katsumata [15] and use preordered monoids, which are the most general.
Definition 5
(Preordered monoid). A preordered monoid consists of a monoid and a preorder on , such that the binary operation is monotone in each argument separately.
Since we do not track variable usage information, we might misestimate the effect of a callbyneed computation variable evaluated for a second time (whose true effect is ). To ensure this misestimate is an overestimate, we assume that the effect algebra is pointed (which is the case for most applications).
Definition 6
(Pointed preordered monoid). A preordered monoid is pointed if for all we have .
The elements of the set are called effects. Each effect abstractly represents some potential sideeffecting behaviours. The order provides approximation of effects. When this means behaviours represented by are included in those represented by \(f'\). The binary operation represents sequencing of effects, and \(1\) is the effect of a sideeffectfree expression.
Traditional (Giffordstyle) effect systems have some set \({\varSigma }\) of operations (for example, ), and use the preordered monoid . In these cases, an effect \(f\) is just a set of operations. If a computation has effect then contains all of the operations the computation may perform. They can therefore be used to enforce that computations do not use particular operations. Another example is the preordered monoid , which can be used to count the number of possible results a nondeterministic computation can return (or to count the number of times an operation is used).
In our example, where we wish to establish whether the effects of an expression are restricted to nontermination for our main example, we use the twoelement preorder with join for sequencing and . The effect \(\mathsf {diveff}\) means sideeffects restricted to (at most) nontermination, and \(\top \) means unrestricted sideeffects. Thus we would enable the equivalence between callbyname and callbyneed when the effect is \(\mathsf {diveff}\), and not when it is . All of these examples are pointed. Others can be found in the literature.
4.2 Effect System and Signature
The effect system includes effects within types. Specifically, each computation of returner type will have some sideeffects when it is run, and hence each returner type is annotated with an element f of \(\mathcal {F}\). We write the annotated type as . Formally we replace the grammar of ECBPV computation types (and similarly, the grammar of typing contexts) with
(The highlighted parts indicate the differences.) The grammar used for value types is unchanged, except that it uses the new syntax of computation types.
The definition of ECBPV signature is similarly extended to contain the effect algebra as well as the set of constants:
Definition 7
(Signature). A signature consists of a pointed preordered monoid of effects and, for each value type A, a set of constants of type A, including .
We assume a fixed effect system signature for the remainder of this section.
Since types contain effects, which have a notion of subeffecting, there is a natural notion of subtyping. We define (in Fig. 7) two subtyping relations: \({A} <:_\mathrm {v} {B}\) for value types and for computation types.
We treat the type constructor as an operation on computation types by defining computation types .
This is an action of the preordered monoid on computation types. Its purpose is to give the typing rule for sequencing of computations. The sequencing of a computation with effect \(f\) with a computation of type \(\underline{C}\) has type .
The typing judgements have exactly the same form as before (except for the new syntax of types). The majority of the typing rules, including all of the rules for value terms, are also unchanged. The only rules we change are those for computation variables, \(\mathop {\mathsf {return}} \), and , which are replaced with the first four rules in Fig. 8. We also add two subtyping rules, one for values and one for computations. These are the last two rules of Fig. 8.
The equational theory does not need to be changed to use it with the new effect system (except that the types appearing in each axiom now include effect information). For each axiom of the equational theory, the two terms still have the same type in the effect system. In particular, for the axiom
if and then the lefthand side has type . For the righthandside, we have , because of the assumption that the preordered monoid is pointed (which implies \(\mathop {\mathsf {return}} y\) can have any effect by subtyping, not just the unit effect \(1\)). Hence the righthandside also has type . This axiom is the reason for our pointedness requirement. In particular, if we drop from the language, the pointedness requirement is not required. Thus the rules we give also describe a fully general effect system for CBPV in which the effect algebra can be any preordered monoid.
4.3 Exploiting EffectDependent Equivalences
Our primary goal in adding an effect system to ECBPV is to exploit (local, effectjustified) equivalences between evaluation orders even without a wholelanguage restriction on effects. We sketch how to do this for our example.
When proving the equivalence between callbyname and callbyneed in Sect. 3 we assumed that the only constants in the language were \({()}\) and . To relax this restriction, we use the effect algebra with preorder described above, and change the type of to . We can include other effectful constants, and give them the effect (e.g. ).
The statement of the internal (objectlevel) equivalence becomes:
The premise restricts the effect of M to \(\mathsf {diveff}\) so that nontermination is its only possible sideeffect. To prove this equivalence, we need a logical relation for the effect system, which means we have to define a Kripke relation for each effect \(f\). For we use the same definition as before (the definition of ). The definition of depends on the specific other effects included.
To state and prove a metalevel equivalence for a source language that includes other sideeffects, we need to define an effect system for the source language. This would use the same effect algebra as the ECBPV effect system, and be such that the translation of source language expressions preserves effects. To do this for the source language of Sect. 3, we replace the syntax of function types with , where \(f\) is the effect of the argument (required due to lazy evaluation), and \(f'\) is the latent effect of the function (the effect it has after application). The translation is then
Just as for the objectlevel equivalence, the statement of the metalevel equivalence similarly requires the sourcelanguage expression to have the effect \(\mathsf {diveff}\). We omit the details here.
5 Related Work
Metalanguages for Evaluation Order. Callbypushvalue is similar to Moggi’s monadic metalanguage [25], except for the distinction between computations and values. Both support several evaluation orders, but neither supports callbyneed. Polarized type theories [34] also take the approach of stratifying types into several kinds to capture multiple evaluation orders. Downen and Ariola [10] recently described how to capture callbyneed using polarity. They take a different approach to ours, by splitting up terms according to their evaluation order, rather than whether they might have effects. This means they have three kinds of type, resulting in a more complex language than ours. They also do not apply their language to reasoning about the differences between evaluation orders, which was the primary motivation for ECBPV. It is not clear whether their language can also be used for this purpose.
Multiple evaluation orders can also be captured in a Moggistyle language by using joinads instead of monads [28]. It is possible that there is some joinad structure implicit in extended callbypushvalue.
Reasoning About CallbyNeed. The majority of work on reasoning about callbyneed source languages has concentrated on operational semantics based on environments [16], graphs [30, 32], and answers [2, 3, 9, 22]. However, these do not compare callbyneed with other evaluation orders. The only typebased analysis of a lazy source language we know of apart from McDermott and Mycroft’s effect system [23] is [31, 33].
Logical Relations. Kripke logical relations have previously been applied to the problems of lambda definability [12] and normalization [1, 11]. Previous proofs of contextual equivalence relate only closed terms. We were forced to relate open terms because of the construct.
Reasoning about effects using logical relations often runs into a difficulty in ensuring the relations are closed under sequencing of computations. We are able to work around this due to our specific choice of effects. It is possible that considering other effects would require a technique such as Lindley and Stark’s leapfrog method [18, 19].
Effect Systems. Effect systems have a long history, starting with Giffordstyle effect systems [20]. We use preordered monoids as effect algebras following Katsumata [15]. Almost all of the previous work on effect systems has concentrated on callbyvalue only. Kammar and Plotkin [13, 14] describe a Giffordstyle callbypushvalue effect system, though their formulation does not generalise to other effect algebras. Our effect system is the first general effect system for a CBPVlike language. The only previous work on callbyneed effects is [23].
There has also been much work on reasoning about program transformations using effect systems, e.g. [4,5,6,7,8, 29]. We expect it to be possible to recast much of this in terms of extended callbypushvalue, and therefore apply these transformations for various evaluation orders.
6 Conclusions and Future Work
We have described extended callbypushvalue, a calculus that can be used for reasoning about several evaluation orders. In particular, ECBPV supports callbyneed via the addition of the construct . This allows us to prove that callbyname and callbyneed reduction are equivalent if nontermination is the only effect in the source language, both inside the language itself, and on the metalevel. We proved the latter by giving two translations of a source language into ECBPV: one that captures callbyname reduction, and one that captures callbyneed reduction. We also defined an effect system for ECBPV. The effect system statically bounds the sideeffects of terms, allowing equivalences between evaluation orders to be used without restricting the entire language to particular effects. We close with a description of possible future work.
Other Equivalences Between Evaluation Orders. We have proved one example of an equivalence between evaluation orders using ECBPV, but there are others that we might also expect to hold. For example, we would expect callbyneed and callbyvalue to be equivalent if the effects are restricted to nondeterminism, allocating state, and reading from state (but not writing). It should be possible to use ECBPV to prove these by defining suitable logical relations. More generally, it might be possible to characterize when particular equivalences hold in terms of the algebraic properties of the effects we restrict to.
Denotational Semantics. Using logical relations to prove contextual equivalence between terms directly is difficult. Adequate denotational semantics would allow us to reduce proofs of contextual equivalence to proofs of equalities in the model. Composing the denotational semantics with the callbyneed translation would also result in a callbyneed denotational semantics for the source language. Some potential approaches to describing the denotational semantics of ECBPV are Maraist et al.’s [21] translation into an affine calculus, combined with a semantics of linear logic [24], and also continuationpassingstyle translations [27]. None of these consider sideeffects however.
Notes
 1.
The only difference is that eliminators of product and sum types are value terms rather than computation terms (which makes value terms slightly more general). Levy [17] calls this CBPV with complex values.
 2.
Computation variables are not strictly required to support callbyneed (since we can use instead of ), but they simplify reasoning about evaluation order, and therefore we choose to include them.
 3.
This is why it suffices to consider only computation contexts. If we had to relate M to \(M'\) then we would need to consider relations between terms with free value variables.
References
Altenkirch, T., Hofmann, M., Streicher, T.: Categorical reconstruction of a reduction free normalization proof. In: Pitt, D., Rydeheard, D.E., Johnstone, P. (eds.) CTCS 1995. LNCS, vol. 953, pp. 182–199. Springer, Heidelberg (1995). https://doi.org/10.1007/3540601643_27
Ariola, Z.M., Felleisen, M.: The callbyneed lambda calculus. J. Funct. Program. 7(3), 265–301 (1997)
Ariola, Z.M., Maraist, J., Odersky, M., Felleisen, M., Wadler, P.: Acallbyneed lambda calculus. In: Proceedings of the 22nd ACM SIGPLANSIGACT Symposium on Principles of Programming Languages, pp. 233–246. ACM (1995). https://doi.org/10.1145/199448.199507
Benton, N., Hofmann, M., Nigam, V.: Effectdependent transformations for concurrent programs. In: Proceedings of the 18th International Symposium on Principles and Practice of Declarative Programming, pp. 188–201. ACM (2016). https://doi.org/10.1145/2967973.2968602
Benton, N., Kennedy, A.: Monads, effects and transformations. Electron. Notes Theor. Comput. Sci. 26, 3–20 (1999). https://doi.org/10.1016/S15710661(05)802804
Benton, N., Kennedy, A., Hofmann, M., Nigam, V.: Counting successes: effects and transformations for nondeterministic programs. In: Lindley, S., McBride, C., Trinder, P., Sannella, D. (eds.) A List of Successes That Can Change the World. LNCS, vol. 9600, pp. 56–72. Springer, Cham (2016). https://doi.org/10.1007/9783319309361_3
Benton, N., Kennedy, A., Russell, G.: Compiling standard ML to Java bytecodes. In: Proceedings of the Third ACM SIGPLAN International Conference on Functional Programming, pp. 129–140. ACM (1998). https://doi.org/10.1145/289423.289435
Birkedal, L., Sieczkowski, F., Thamsborg, J.: A concurrent logical relation. In: Cégielski, P., Durand, A. (eds.) 21st EACSL Annual Conference on Computer Science Logic, CSL 2012. Leibniz International Proceedings in Informatics (LIPIcs), vol. 16, pp. 107–121. Schloss DagstuhlLeibnizZentrum für Informatik, Dagstuhl (2012). https://doi.org/10.4230/LIPIcs.CSL.2012.107
Chang, S., Felleisen, M.: The callbyneed lambda calculus, revisited. In: Seidl, H. (ed.) ESOP 2012. LNCS, vol. 7211, pp. 128–147. Springer, Heidelberg (2012). https://doi.org/10.1007/9783642288692_7
Downen, P., Ariola, Z.M.: Beyond polarity: towards a multidiscipline intermediate language with sharing. In: 27th EACSL Annual Conference on Computer Science Logic, CSL 2018, pp. 21:1–21:23 (2018). https://doi.org/10.4230/LIPIcs.CSL.2018.21
Fiore, M.: Semantic analysis of normalisation by evaluation for typed lambda calculus. In: Proceedings of the 4th ACM SIGPLAN International Conference on Principles and Practice of Declarative Programming, pp. 26–37. ACM (2002). https://doi.org/10.1145/571157.571161
Jung, A., Tiuryn, J.: A new characterization of lambda definability. In: Bezem, M., Groote, J.F. (eds.) TLCA 1993. LNCS, vol. 664, pp. 245–257. Springer, Heidelberg (1993). https://doi.org/10.1007/BFb0037110
Kammar, O.: Algebraic theory of typeandeffect systems. Ph.D. thesis, University of Edinburgh, UK (2014)
Kammar, O., Plotkin, G.D.: Algebraic foundations for effectdependent optimisations. In: Proceedings of the 39th Annual ACM SIGPLANSIGACT Symposium on Principles of Programming Languages, pp. 349–360. ACM (2012). https://doi.org/10.1145/2103656.2103698
Katsumata, S.: Parametric effect monads and semantics of effect systems. In: Proceedings of the 41st ACM SIGPLANSIGACT Symposium on Principles of Programming Languages, pp. 633–645. ACM (2014). https://doi.org/10.1145/2535838.2535846
Launchbury, J.: A natural semantics for lazy evaluation. In: Proceedings of the 20th ACM SIGPLANSIGACT Symposium on Principles of Programming Languages, pp. 144–154. ACM (1993). https://doi.org/10.1145/158511.158618
Levy, P.B.: Callbypushvalue: a subsuming paradigm. In: Girard, J.Y. (ed.) TLCA 1999. LNCS, vol. 1581, pp. 228–243. Springer, Heidelberg (1999). https://doi.org/10.1007/3540489592_17
Lindley, S.: Normalisation by evaluation in the compilation of typed functional programming languages. Ph.D. thesis, University of Edinburgh, UK (2005)
Lindley, S., Stark, I.: Reducibility and \(\top \)lifting for computation types. In: Urzyczyn, P. (ed.) TLCA 2005. LNCS, vol. 3461, pp. 262–277. Springer, Heidelberg (2005). https://doi.org/10.1007/11417170_20
Lucassen, J.M., Gifford, D.K.: Polymorphic effect systems. In: Proceedings of the 15th ACM SIGPLANSIGACT Symposium on Principles of Programming Languages, pp. 47–57. ACM (1988). https://doi.org/10.1145/73560.73564
Maraist, J., Odersky, M., Turner, D.N., Wadler, P.: Callbyname, callbyvalue, callbyneed, and the linear lambda calculus. In: Proceedings of the Eleventh Annual Mathematical Foundations of Programming Semantics Conference, pp. 370–392 (1995). https://doi.org/10.1016/S03043975(98)003582
Maraist, J., Odersky, M., Wadler, P.: The callbyneed lambda calculus. J. Funct. Program. 8(3), 275–317 (1998). https://doi.org/10.1017/S0956796898003037
McDermott, D., Mycroft, A.: Callbyneed effects via coeffects. Open Comput. Sci. 8, 93–108 (2018). https://doi.org/10.1515/comp20180009
Melliès, P.A.: Categorical semantics of linear logic. In: Interactive Models of Computation and Program Behaviour, Panoramas et Synthèses 27, Société Mathématique de France (2009)
Moggi, E.: Notions of computation and monads. Inf. Comput. 93(1), 55–92 (1991). https://doi.org/10.1016/08905401(91)900524
MunchMaccagnoni, G.: Models of a nonassociative composition. In: Muscholl, A. (ed.) FoSSaCS 2014. LNCS, vol. 8412, pp. 396–410. Springer, Heidelberg (2014). https://doi.org/10.1007/9783642548307_26
Okasaki, C., Lee, P., Tarditi, D.: Callbyneed and continuationpassing style. LISP Symbolic Comput. 7(1), 57–81 (1994). https://doi.org/10.1007/BF01019945
Petricek, T., Syme, D.: Joinads: a retargetable controlflow construct for reactive, parallel and concurrent programming. In: Rocha, R., Launchbury, J. (eds.) PADL 2011. LNCS, vol. 6539, pp. 205–219. Springer, Heidelberg (2011). https://doi.org/10.1007/9783642183782_17
Tolmach, A.: Optimizing ML using a hierarchy of monadic types. In: Leroy, X., Ohori, A. (eds.) TIC 1998. LNCS, vol. 1473, pp. 97–115. Springer, Heidelberg (1998). https://doi.org/10.1007/BFb0055514
Turner, D.A.: A new implementation technique for applicative languages. Softw. Pract. Experience 9(1), 31–49 (1979). https://doi.org/10.1002/spe.4380090105
Turner, D.N., Wadler, P., Mossin, C.: Once upon a type. In: Proceedings of the Seventh International Conference on Functional Programming Languages and Computer Architecture, pp. 1–11. ACM (1995). https://doi.org/10.1145/224164.224168
Wadsworth, C.: Semantics and Pragmatics of the LambdaCalculus. University of Oxford (1971)
Wansbrough, K., Peyton Jones, S.: Once upon a polymorphic type. In: Proceedings of the 26th ACM SIGPLANSIGACT Symposium on Principles of Programming Languages, pp. 15–28. ACM (1999). https://doi.org/10.1145/292540.292545
Zeilberger, N.: The logical basis of evaluation order and patternmatching. Ph.D. thesis, Carnegie Mellon University, Pittsburgh, PA, USA (2009)
Acknowledgements
We gratefully acknowledge the support of an EPSRC studentship, and thank the anonymous reviewers for helpful comments.
Author information
Authors and Affiliations
Corresponding author
Editor information
Editors and Affiliations
Rights and permissions
Open Access This chapter is licensed under the terms of the Creative Commons Attribution 4.0 International License (http://creativecommons.org/licenses/by/4.0/), which permits use, sharing, adaptation, distribution and reproduction in any medium or format, as long as you give appropriate credit to the original author(s) and the source, provide a link to the Creative Commons license and indicate if changes were made.
The images or other third party material in this chapter are included in the chapter's Creative Commons license, unless indicated otherwise in a credit line to the material. If material is not included in the chapter's Creative Commons license and your intended use is not permitted by statutory regulation or exceeds the permitted use, you will need to obtain permission directly from the copyright holder.
Copyright information
© 2019 The Author(s)
About this paper
Cite this paper
McDermott, D., Mycroft, A. (2019). Extended CallbyPushValue: Reasoning About Effectful Programs and Evaluation Order. In: Caires, L. (eds) Programming Languages and Systems. ESOP 2019. Lecture Notes in Computer Science(), vol 11423. Springer, Cham. https://doi.org/10.1007/9783030171841_9
Download citation
DOI: https://doi.org/10.1007/9783030171841_9
Published:
Publisher Name: Springer, Cham
Print ISBN: 9783030171834
Online ISBN: 9783030171841
eBook Packages: Computer ScienceComputer Science (R0)