Abstract 1 Introduction 2 Overview 3 Call-By-Push-Value 𝝀-Calculus 4 Compiling CBPV Terms to Programs 5 Abstract Machines 6 CBPV is Reasonable for Both Time and Space 7 Conclusion and Future Work References

A Verified Cost Model for Call-By-Push-Value

Zhuo Zoey Chen ORCID University of Melbourne, Australia Johannes Åman Pohjola ORCID University of Gothenburg, Sweden Christine Rizkallah ORCID University of Melbourne, Australia
Abstract

The call-by-push-value λ-calculus allows for syntactically specifying the order of evaluation as part of the term language. Hence, it serves as a unifying language for embedding various evaluation strategies including call-by-value and call-by-name. Given the impact of call-by-push-value, it is remarkable that its adequacy as a model for computational complexity theory has not yet been studied. In this paper, we show that the call-by-push-value λ-calculus is reasonable for both time and space complexity. A reasonable cost model can encode other reasonable cost models with polynomial overhead in time and constant factor overhead in space. We achieve this by encoding call-by-push-value λ-calculus into Turing machines, following a simulation strategy by Forster et al.; for the converse direction, we prove that Levy’s encoding of the call-by-value λ-calculus has reasonable complexity bounds. The main results have been formalised in the HOL4 theorem prover.

Keywords and phrases:
lambda calculus, formalizations of computational models, computability theory, HOL, call-by-push-value reduction, time and space complexity, abstract machines
Copyright and License:
[Uncaptioned image] © Zhuo Zoey Chen, Johannes Åman Pohjola, and Christine Rizkallah; licensed under Creative Commons License CC-BY 4.0
2012 ACM Subject Classification:
Theory of computation Lambda calculus
Supplementary Material:
Software  (Mechanised Proof): https://github.com/ZhuoZoeyChen/cbpv-reasonable-HOL/ [5]
  archived at Software Heritage Logo swh:1:dir:df18377e9fa5e35255f2687ad66ddbc2f010b934
Acknowledgements:
We thank Yannick and Fabian for taking the time to meet with us and discuss their work on the weak call-by-value λ-calculus. We are also grateful to the anonymous reviewers for their valuable feedback.
Editors:
Yannick Forster and Chantal Keller

1 Introduction

The λ-calculus [7] is a fundamental model of computation that represents functions as abstractions over variables. It provides a foundation for computability, mathematical logic, and functional programming. Functional programming supports a concise, declarative style of programming that is ideal for reasoning about functional correctness properties.

Besides functional correctness, another important property of a program is its computational complexity. It addresses the vital questions: How fast does my program produce an output? How much space will my program use in order to produce that output?

In complexity analysis, we describe the asymptotic behaviour of cost functions that model the cost of the program mathematically. But where do cost functions come from? In practice they are often constructed in an ad hoc manner with no formal connection to any program semantics. Cost models bridge that gap.

Creating cost models for functional programming languages is thus an essential topic. It is also a significant challenge due to the abstract nature of functional programming. As λ-calculus is the basis of functional programming languages, a vital question is whether we can create cost models for the λ-calculus. There has been a large body of research [18, 8, 2, 1, 11, 12, 3] dedicated to solving this problem. An important parameter in a cost model for the λ-calculus is the choice of evaluation strategy. One strategy is call-by-value, where function calls are applied once the arguments are fully evaluated, as in Standard ML [23]. Another strategy is call-by-name, where the evaluation of arguments is deferred and the function call happens first.

The call-by-push-value λ-calculus (CBPV) [19] is a variant of λ-calculus where the evaluation strategy can be set on a call-by-call basis. In particular, CBPV has syntactic constructs that enable delaying or forcing the evaluation of specific terms. Various evaluation strategies, including call-by-value and call-by-name, can be encoded within this subsuming paradigm.

This high expressive power of CBPV has resulted in a long line of work on the language since its inception [10, 9, 24, 22, 13, 15, 6, 16]. Prior work has studied and extended the calculus [16, 27, 22], related it to other calculi [10, 6, 14], and formalised it [24, 13]. The fine-grained control CBPV provides has proved useful to verify compiler optimisations [24].

There are foundational results that demonstrate that CBPV aids in recurrence extraction, which can in turn be used for analysing the complexity of functional programs, with various evaluation strategies [15].

This demonstrates that CBPV can serve as a basis for further research on analysing the complexity of functional programs with various evaluation strategies. As such, it is vital to establish time and space cost models for CBPV. Naturally, such cost models must satisfy some property that demonstrates that they are fit for purpose.

Reasonable Machines

Turing machines are the standard computational model for complexity theory. They have obvious cost models for time (the number of steps) and space (the number of tape cells used). Cost models are less obvious for λ-terms, but the readability and convenience of using λ-terms are higher. Can cost analysis performed in one carry over to the other?

A reasonable cost model [26, 28] answers this question in the positive. Reasonableness is a standard requirement for assessing the suitability of computational models for reasoning about complexity, by relating them to Turing machines (which are considered reasonable by definition). The invariance thesis [28] states that:

“Reasonable machines simulate each other with polynomially bounded overhead in time and constant factor overhead in space”.

Hence the definition of standard complexity classes like P, PSPACE, and EXP are independent of which (reasonable) substrate they are defined on.

Contribution

This paper contributes, to the best of our knowledge, the first reasonable time and space cost models for CBPV. We further provide machine-checked proofs in HOL4 [25] for the core parts thereof. In doing so we build on prior work on formally verified time and space cost models for the weak call-by-value λ-calculus (WCBV) that was formalised in Coq [17, 11].

Related Work

In 1996, Lawall and Mairson [18] proved that the full λ-calculus is reasonable for both time and space using the measures total ink used and maximum ink used. But the time measure of total ink used is too general and hard to apply. In 2008, Dal Lago and Martini [8] provided a different time measure for WCBV, which counts the number of β-steps while taking account of the size of β-redexes. This was further strengthened by Accattoli and Dal Lago [2] in 2016, showing that counting (leftmost-outermost) β-steps makes the full λ-calculus reasonable for time. Continuing on this line, Forster, Kunze, and Roth [11] proved in 2020 that WCBV is reasonable with respect to natural measures, accompanied with a partial formalisation. They define a natural measure to be the number of β-reductions for time, and the size of the biggest intermediate term for space. They proved that WCBV is reasonable by interleaving two evaluation strategies: a substitution-based strategy and heap-based strategy, which we adapt and implement for CBPV in our paper. Forster, Kunze, Smolka, and Wuttke [12] provided a complete formalisation in 2021, showing that WCBV is reasonable for time. The complete formal verification of the space invariance thesis for the same calculus still remains open. One limitation of this line of work, as well as ours, is that we do not consider sublinear time or space classes. In contrast, Accattoli, Dal Lago, and Vanoni [3] presented a reasonable space cost model for the λ-calculus that works for LOGSPACE by using a variant of the Krivine abstract machine. It remains open whether this approach can be extended to CBPV.

CBPV, developed by Levy in 1999 [19], has been increasingly popular in recent decades. There are also various extensions of CBPV, including with stacks [21], with probability [10] and with call-by-need [22]. On the formalisation side, there is a formal equational theory [24] for CBPV; there is another formalisation [13] that includes proofs for its operational, equational, and denotational theory. On the applied side, there are projects such as extracting recurrences [15] using CBPV. There is a similar λ-calculus called the Bang-calculus [9], which can be regarded as an untyped version of CBPV without any side-effects.

2 Overview

Our goal is to show that CBPV is reasonable. This section is a high-level overview of our proof strategy, which is detailed in Section 6. The main theorems involved are:

Theorem 1 (Turing Machines Simulating CBPV).

Let T, SΩ(n). For a CBPV term s, if s reduces to a normal form t in time n and space m, then one can construct a Turing machine Ps simulating s that halts with output Pt simulating t, in time 𝒪(𝑝𝑜𝑙𝑦(T(n))) and space 𝒪(S(m)).

Theorem 2 (CBPV Simulating Turing Machines).

Let T, SΩ(n). For a Turing machine Ps that halts with output Pt in time n and space m, one can construct a CBPV term s simulating Ps which can be reduced to a normal form t simulating Pt in time 𝒪(𝑝𝑜𝑙𝑦(T(n))) and space 𝒪(S(n)).

That is, we must model the cost of CBPV using Turing machines and prove that the resulting simulation is cost-bounded (Theorem 1). Moreover, we must show that CBPV provides sufficient expressivity to reasonably simulate any Turing machine (Theorem 2).

Turing Machines Simulating CBPV

Inspired by the strategy used for proving that WCBV is reasonable [11], we verify that CBPV can be simulated by Turing machines with reasonable overhead by using two intermediate abstract machines: the substitution machine (Section 5.2) and the heap machine (Section 5.3).

It is well-known that the λ-calculus has the size explosion problem, where linear time can lead to exponential growth in space [26]. That is, with 𝒪(n) β-reduction steps, the largest intermediate term can be of size 𝒪(2n). Turing machines, by contrast, need at least one unit of time to consume one unit of space, so space cost cannot exceed time cost. Hence, if one adopts a substitution-based strategy alone, the overhead in time will be exponential. To solve the size explosion problem, a shared memory structure is required to store values. This motivates why the heap-based strategy is incorporated into our simulation.

But the heap-based strategy has a pointer explosion problem [26], which makes space overhead non-constant. Luckily, size explosion and pointer explosion problems don’t overlap [11], so we can use the heap-based strategy when a size explosion happens, and vice versa.

We formalise the simulation of CBPV by each of the two abstract machines, and verify that it respects the desired bounds in terms of time and space overhead. The cost bounds turn out to be similar to those for WCBV, enabling the adoption of an existing algorithm [11] to obtain a Turing machine simulation by interleaving the substitution and heap machines.

CBPV Simulating Turing Machines

For this direction, we use WCBV as an intermediate model. We first formalise the translation from WCBV to CBPV provided by Levy [19]. We then show that CBPV can simulate WCBV with reasonable time and space overheads. Since WCBV can simulate Turing machines with reasonable overheads [11, Theorem 5.1], we obtain our result for this direction as a corollary.

Formalisation

We verify in HOL4 that our time and space cost models for CBPV have the desired overheads. The formalisation covers all material presented in Section 3, Section 4, Section 5 and Section 6.2. An overview is given in Figure 6 in Section 6. The interleaving strategy, and the connection between abstract machines and Turing machines is done using pen-and-paper proofs adapted from the literature, in Section 6.

3 Call-By-Push-Value 𝝀-Calculus

The CBPV λ-calculus [19, 20] allows encoding the order of evaluation as part of the syntax of a program. Hence, it serves as a subsuming paradigm that enables studying evaluation strategies, and combinations thereof, using a single set of reduction rules. Levy provides semantic-preserving translations from call-by-name and call-by-value into CBPV [20].

For simplicity, we use a core fragment of CBPV that is sufficient for demonstrating reasonability. As such we omit, for instance, the general pair types, and instead introduce a simpler double sequencing operation that will be discussed later. Furthermore, while most presentations of CBPV are typed, ours is untyped CBPV. We consider types an orthogonal concern to cost: the well-typed CBPV terms are a strict subset of the untyped CBPV terms, so a cost model for the latter immediately suggests a cost model for the former.

The CBPV terms are defined below as two mutually recursive sets: the values 𝚅 and the computations 𝙼. The mutual recursion adds some technical difficulties in our formalisation as all relevant functions need to be mutually recursive too. For instance, the substitution function for CBPV, and the compilation function for compiling CBPV terms into programs are both defined mutually recursively, which complicates proofs. To simplify the presentation, we will often use a single overloaded name for two such mutually recursive functions.

Values V:=𝗏𝖺𝗋x|𝗍𝗁𝗎𝗇𝗄MComputations M:=λ.M|𝖺𝗉𝗉MV|𝖿𝗈𝗋𝖼𝖾V|𝗋𝖾𝗍V|𝗌𝖾𝗊MM|𝗉𝗌𝖾𝗊𝙼𝙼𝙼|𝗅𝖾𝗍V.𝗂𝗇M

Fine-grained control over evaluation can be achieved using the 𝖿𝗈𝗋𝖼𝖾 and 𝗍𝗁𝗎𝗇𝗄 operators. 𝗍𝗁𝗎𝗇𝗄 suspends a computation, and 𝖿𝗈𝗋𝖼𝖾 resumes a suspended computation.

Note that we have an extra 𝗉𝗌𝖾𝗊 that is absent in the standard presentation of CBPV. An example of 𝗉𝗌𝖾𝗊 computation is 𝗉𝗌𝖾𝗊m2m1n. It allows us to evaluate two computations m1 and m2 and use the results in a third computation n. Note that the notation within 𝗉𝗌𝖾𝗊 follows the convention and binds to the right. This can of course be encoded with nested 𝗌𝖾𝗊, but at the cost of higher binding depth: 𝗌𝖾𝗊m2(𝗌𝖾𝗊m1n). Avoiding this higher binder depth will turn out to be crucial for obtaining constant space overhead in Section 6.2. Including pairs in the language would have solved the problem too, but 𝗉𝗌𝖾𝗊 suffices for our purposes.

We then formalise the big-step cost semantics of closed CBPV provided by Levy [20]; that is, we only consider terms with no free variables at the top level. Similar to the change we made in the syntax, we also add 𝗉𝗌𝖾𝗊 as a special case of the pair type into our semantics.

In order to define the semantics for closed CBPV, we need to first provide a closed substitution function for β-reductions. The following function mvi substitutes all the variables with de Bruijn index i by v in m by recursively visiting all the inner terms of m:

(λ.m)ui=λ.(mui+1)(𝖺𝗉𝗉mv)ui=𝖺𝗉𝗉(mui)(vui)(𝗋𝖾𝗍v)ui=𝗋𝖾𝗍(vui)(𝗌𝖾𝗊mn)ui=𝗌𝖾𝗊(mui)(nui+1)(𝗉𝗌𝖾𝗊m2m1n)ui=𝗉𝗌𝖾𝗊(m2ui)(m1ui)(nui+2)(𝗏𝖺𝗋x)ui=u(if x=i)(𝗏𝖺𝗋x)ui=𝗏𝖺𝗋x(if xi)(𝗍𝗁𝗎𝗇𝗄m)ui=𝗍𝗁𝗎𝗇𝗄(mui)(𝖿𝗈𝗋𝖼𝖾v)ui=𝖿𝗈𝗋𝖼𝖾(vui)(𝗅𝖾𝗍v.𝗂𝗇m)ui=𝗅𝖾𝗍(vui).𝗂𝗇(mui+1)

Note the special cases such as (λ.m)ui, where we need to increment the targeted variable index i accordingly because we are entering extra layers of abstractions. A more special case is (𝗉𝗌𝖾𝗊m2m1n)ui, we increment i by two for this substitution because n needs to leave two free variable names for the two computations m1 and m2.

We then define time cost and space cost semantics for CBPV. For the time cost semantics, we use a judgement mkn to mean that the computation m reduces to n in k steps. The rules are given in Figure 1.

Figure 1: The Rules Defining Big-Step Semantics of CBPV Terms with Time Cost.

For space, the judgement msn says that m reduces to n with space cost s. Note that the time and space cost semantics judgements coincide if the cost annotations are ignored.

We define a size function m for CBPV terms m as follows. Note that we account for the size of a de Bruijn index x in the term size.

𝗏𝖺𝗋x=1+x𝗍𝗁𝗎𝗇𝗄m=1+m𝖿𝗈𝗋𝖼𝖾v=1+v𝗅𝖾𝗍v.𝗂𝗇m=1+v+mλ.m=1+m𝖺𝗉𝗉mv=1+m+v𝗋𝖾𝗍v=1+v𝗌𝖾𝗊mn=1+m+n𝗉𝗌𝖾𝗊m2m1n=1+m2+m1+n

Figure 2 gives inference rules of the space cost semantics. It tracks the maximum intermediate term size of an evaluation. For instance, for the 𝗉𝗌𝖾𝗊 case, there are three different evaluation stages: (1). Evaluating m1; (2). Evaluating m2 (3). Substituting results v1 and v2 into n. The space cost is the maximum size among these stages.

Figure 2: The Rules Defining Big-Step Semantics of CBPV Terms with Space Cost.

4 Compiling CBPV Terms to Programs

As a first step in bridging the gap between CBPV and Turing machines, we define a flat data structure to represent programs that correspond to CBPV terms. A program P is formed of a list of tokens, 𝖳𝗈𝗄 that are defined as follows:

𝗍𝖳𝗈𝗄:=𝗏𝖺𝗋𝖳x|𝗍𝗁𝗎𝗇𝗄𝖳|𝖾𝗇𝖽𝖳𝗁𝗎𝗇𝗄𝖳|𝗅𝖺𝗆𝖳|𝖾𝗇𝖽𝖫𝖺𝗆𝖳|𝖺𝗉𝗉𝖳|𝖿𝗈𝗋𝖼𝖾𝖳|𝗋𝖾𝗍𝖳|𝖾𝗇𝖽𝖱𝖾𝗍𝖳|𝗌𝖾𝗊𝖳|𝖾𝗇𝖽𝖲𝖾𝗊𝖳|𝗉𝗌𝖾𝗊𝖳|𝖾𝗇𝖽𝖯𝗌𝖾𝗊𝖳|𝗅𝖾𝗍𝖳|𝖾𝗇𝖽𝖫𝖾𝗍𝖳
Definition 3 (Size of Tokens and Programs).
|𝗏𝖺𝗋𝖳x|=1+x|t|=1otherwiseP=1+tiP|ti|

The de Bruijn index x counts towards the token size because larger indices require more tape cells to store on Turing machines. The size of a program is simply the sum of the size of its tokens plus 1 (which is the size of the empty program on a Turing machine).

Definitions 4 and 5 define compilation to the substitution and heap machines, respectively.

Definition 4 (Compilation Function for Substitution Machine).
γ(𝗏𝖺𝗋x)=𝗏𝖺𝗋𝖳xγ(𝗍𝗁𝗎𝗇𝗄m)=𝗍𝗁𝗎𝗇𝗄𝖳::γ(m)++[𝖾𝗇𝖽𝖳𝗁𝗎𝗇𝗄𝖳]γ(𝖿𝗈𝗋𝖼𝖾v)=γ(v)++[𝖿𝗈𝗋𝖼𝖾𝖳]γ(𝗋𝖾𝗍v)=𝗋𝖾𝗍𝖳::γ(v)++[𝖾𝗇𝖽𝖱𝖾𝗍𝖳]γ(λ.m)=𝗅𝖺𝗆𝖳::γ(m)++[𝖾𝗇𝖽𝖫𝖺𝗆𝖳]γ(𝖺𝗉𝗉mv)=γ(m)++γ(v)++[𝖺𝗉𝗉𝖳]γ(𝗌𝖾𝗊mn)=γ(m)++[𝗌𝖾𝗊𝖳]++γ(n)++[𝖾𝗇𝖽𝖲𝖾𝗊𝖳]γ(𝗉𝗌𝖾𝗊m2m1n)=γ(m1)++γ(m2)++[𝗉𝗌𝖾𝗊𝖳]++γ(n)++[𝖾𝗇𝖽𝖯𝗌𝖾𝗊𝖳]γ(𝗅𝖾𝗍v.𝗂𝗇m)=γ(v)++[𝗅𝖾𝗍𝖳]++γ(m)++[𝖾𝗇𝖽𝖫𝖾𝗍𝖳]
Definition 5 (Compilation Function for Heap Machine).

We define γ exactly as γ, except:

γ(𝗋𝖾𝗍v)=γ(v)++[𝗋𝖾𝗍𝖳]

We use pairs of delimiter tokens (like 𝗌𝖾𝗊𝖳 and 𝖾𝗇𝖽𝖲𝖾𝗊𝖳) when necessary, to preserve the tree structure of the original term. The development of these compilers was fiddly, since the right balance needs to be struck between including enough structure to prevent different subterms from being conflated or evaluated prematurely, yet not too much structure, because extra structure takes space, and must be accounted for in the space cost bound proofs. γ and γ make slightly different tradeoffs in this respect. We could change the substitution machine to use γ, but the overall proof does not require the machines to use the same syntax.

The following lemma is useful for our space cost analysis. It states that the size of a compiled program is linear wrt. term size. (Note that the same lemma also works for γ.)

Lemma 6 (Program Size Bounds).

1mγ(m)+12m

We write Pm to state that P is the corresponding program for m.

Definition 7 (Program-Term Correspondence).

Pm holds if γ(m)=P.

5 Abstract Machines

Recall from Section 2 that our proof strategy relies on interleaving two simulation strategies to achieve reasonability in time and space. The substitution-based strategy has reasonable overhead for space, but not for time due to the size explosion problem. The heap-based strategy has reasonable overhead for time, but not for space due to the pointer explosion problem. These two explosion problems do not occur at the same time. Thus, by interleaving the respective Turing machines for each of these two strategies, we can obtain a reasonable simulation. In order to achieve this, we first implement two abstract machines that represent these two strategies respectively in this section. We then construct the corresponding Turing machines and finish the rest of the proofs in Section 6. Note that the size of intermediate terms and the complexity differs between the abstract machines and their corresponding Turing machines.

In this section, we first introduce an auxiliary extraction function that is used by both abstract machines (Section 5.1). We then introduce the substitution machine (Section 5.2) and the heap machine (Section 5.3), and investigate their cost in relation to CBPV.

5.1 Extraction Function

For each pair of delimiter tokens, we define a φ function to scan a program until the corresponding end delimiter. To simplify the presentation, we overload φ to account for all operands. The idea is that φP=(M,Q) strips the argument body out of P and returns it as M, where Q is the rest of the program. We show the extraction function for 𝗅𝖺𝗆𝖳- 𝖾𝗇𝖽𝖫𝖺𝗆𝖳 below. The intuition is similar to finding matching parentheses pairs. When φ is applied to a well-formed P, we have φP=φ(M::[𝖾𝗇𝖽𝖫𝖺𝗆𝖳]++Q)=(M,Q), where M has balanced 𝗅𝖺𝗆𝖳- 𝖾𝗇𝖽𝖫𝖺𝗆𝖳 pairs.

Definition 8 (Extraction Function for 𝗅𝖺𝗆𝖳- 𝖾𝗇𝖽𝖫𝖺𝗆𝖳).

φP=φ[] 0P where:

φM 0(𝖾𝗇𝖽𝖫𝖺𝗆𝖳::Q)=(M,Q)φMk(t::Q)=φM++[t]kQφMk(𝗅𝖺𝗆𝖳::Q)=φM++[𝗅𝖺𝗆𝖳]k+1QφMk[]=𝑢𝑛𝑑𝑒𝑓𝑖𝑛𝑒𝑑φMk+1(𝖾𝗇𝖽𝖫𝖺𝗆𝖳::Q)=φM++[𝖾𝗇𝖽𝖫𝖺𝗆𝖳]kQ

5.2 Substitution Machine

In this section, we develop a machine that implements a substitution-based evaluation strategy. Before diving into the transition rules, we need a helper function ::tc that is used to prevent empty lists from accumulating on the stack. It is defined recursively as follows:

[]::tcC=Cc::tcC=c::tcC(c[])

The substitution machine performs substitutions immediately as they appear at the top of the current stacks. The machine state consists of two stacks: the task stack and the value stack. In the initial state, the value stack is empty and the task stack contains the γ(m) for a CBPV computation m. On successful termination, a final value is produced on the value stack, and the task stack is empty. Note that the value stack (despite its name) will sometimes contain computations in non-final states. An alternative presentation would be to add an extra stack for suspended computations, but we found no need for this.

Substitution on programs, written, PQi is similar to that for CBPV terms (Section 3); its definition is elided. Figure 3 shows the transition rules for the substitution machine. The three columns represent the task stack, the value stack, and the assumptions. Each represents one transition step, where the row above represents the current state of the machine, and the row on the same level as represents the next state of the machine after the transition. For example, the transition rule for 𝗍𝗁𝗎𝗇𝗄𝖳 strips one layer of 𝗍𝗁𝗎𝗇𝗄𝖳-𝖾𝗇𝖽𝖳𝗁𝗎𝗇𝗄𝖳 off the task stack and places it on the value stack (thus suspending it). Note that the transition rules for 𝗌𝖾𝗊𝖳 and 𝗉𝗌𝖾𝗊𝖳 can strip 𝗋𝖾𝗍𝖳 components from the value stack directly without the extraction function φ. For instance, in the 𝗌𝖾𝗊𝖳 rule, 𝗋𝖾𝗍𝖳::U++[𝖾𝗇𝖽𝖱𝖾𝗍𝖳] is just the first element on the value stack. We can strip it with a simple list operation. Furthermore, since there is no extra subsequent programs after 𝖾𝗇𝖽𝖱𝖾𝗍𝖳 in 𝗋𝖾𝗍𝖳::U++[𝖾𝗇𝖽𝖱𝖾𝗍𝖳], we can obtain U by removing 𝗋𝖾𝗍𝖳 and 𝖾𝗇𝖽𝖱𝖾𝗍𝖳 using simple list operations.

The transition rule for 𝗏𝖺𝗋𝖳 is not strictly necessary: we only consider closed terms, so the rule will never be exercised when running the compilation output. Nonetheless, including it appears to make the proofs more ergonomic, by making it unnecessary to carry around a closedness side condition. For example, consider the useful technical lemma

((γ(v)::P)::T,V)(P::tcT,γ(v)::V)

which holds unconditionally when the 𝗏𝖺𝗋𝖳 rule is present in the substitution machine semantics. If we remove the rule, it only holds when v is a thunk.

Multiple transitions are written (T,V)kσ(T,V), where T is the current task stack and V is the current value stack. We obtain a new state (T,V) after applying the transition rules k times on the current state (T,V), with the size of the biggest intermediate state being ½σ. We elide σ or k when irrelevant. We write to represent 0 or more transition steps.

Task StackValue StackAssumption(𝗏𝖺𝗋𝖳n::P)::TVP::tcT𝗏𝖺𝗋𝖳n::V(𝗍𝗁𝗎𝗇𝗄𝖳::P)::TVφP=(M,Q)Q::tcT𝗍𝗁𝗎𝗇𝗄𝖳::M++[𝖾𝗇𝖽𝖳𝗁𝗎𝗇𝗄𝖳]::V(𝖿𝗈𝗋𝖼𝖾𝖳::P)::T(𝗍𝗁𝗎𝗇𝗄𝖳::K)::VφK=(M,[])(M++P)::tcTV(𝗅𝖺𝗆𝖳::P)::TVφP=(M,Q)Q::tcT(𝗅𝖺𝗆𝖳::M++[𝖾𝗇𝖽𝖫𝖺𝗆𝖳])::V(𝖺𝗉𝗉𝖳::P)::TQ::(𝗅𝖺𝗆𝖳::M++[𝖾𝗇𝖽𝖫𝖺𝗆𝖳])::VMQ0::(P::tcT)V(𝗋𝖾𝗍𝖳::P)::TVφP=(U,Q)Q::tcT(𝗋𝖾𝗍𝖳::U++[𝖾𝗇𝖽𝖱𝖾𝗍𝖳])::V(𝗌𝖾𝗊𝖳::P)::T(𝗋𝖾𝗍𝖳::U++[𝖾𝗇𝖽𝖱𝖾𝗍𝖳])::VφP=(N,Q)NU0::(Q::tcT)V(𝗉𝗌𝖾𝗊𝖳::P)::T(𝗋𝖾𝗍𝖳::U2++[𝖾𝗇𝖽𝖱𝖾𝗍𝖳])::(𝗋𝖾𝗍𝖳::U1++[𝖾𝗇𝖽𝖱𝖾𝗍𝖳])::VφP=(N,Q)(NU10)U21::(Q::tcT)V(𝗅𝖾𝗍𝖳::P)::TK::VφP=(M,Q)MK0::(Q::tcT)V

Figure 3: Transition Rules for the Substitution Machine.

The substitution machine simulates CBPV with constant time and space overhead:

Lemma 9 (Substitution Machine Time Simulation).

If mkn, then there exists k such that (Pm,[])k([],Pn) where k3k+1 and Pmm and Pnn.

Proof.

By rule induction on the big-step semantics of CBPV.

Lemma 10 (Substitution Machine Space Simulation).

If msn then there exists σ such that (Pm,[])σ([],Pn) , where sσ9s and Pmm and Pnn.

Proof.

Similar to the time simulation proof, we induct on the structure of the big-step semantics of CBPV and show that this theorem is true for all the transition rules.

5.3 Heap Machine

In this section, we introduce an environment-based abstract machine. Free variables are interpreted as pointers into a heap that store their values. But first, some auxiliary definitions.

Definition 11 (Closure).

A closure P,a is a pair consisting of a program P and pointer a. The pointer a binds the free variables in the program P to the values in the heap.

Definition 12 (Heap).

A heap is defined as a list of heap cells where each cell {C,a} consists of a closure C and an additional pointer a. The pointer a points to the previous cell in the heap, providing a linked list representation of the heap.

Let ++ be list concatenation, and len be the standard length function for lists.

Definition 13 (Put and Lookup).

In lookup, let H[a]={C,a}.

putHe=(H++[e],len(H))lookupHa 0=ClookupHax=lookupHa(x1)(if x 0)

The states of the heap machine are triplets consisting of a task stack, a value stack and a heap. We store values in the heap, and replace variables with pointers instead of directly substituting values in-place.

The transition rules for the heap machine are shown in Figure 4. Compared to Section 5.2, there are some minor differences that are not directly related to substitution, but are convenient in the proofs. For example, we spell out the 𝗍𝗁𝗎𝗇𝗄𝖳 structure for the 𝖿𝗈𝗋𝖼𝖾𝖳 case, so this rule does not have to use the φ function.

In our proofs, we write heap machine transitions as (T,V,H)kσ(T,V,H), where (T,V,H) is a triple representing the current task stack, value stack, and heap. We obtain a new state (T,V,H) after applying the transition rules k times on the current state, with the size of the biggest intermediate state being σ. We elide σ or k when irrelevant.

Task StackValue StackHeapAssumption𝗏𝖺𝗋𝖳x::P,a::TVH𝗅𝗈𝗈𝗄𝗎𝗉Hax=gP,a::Tg::VH𝗍𝗁𝗎𝗇𝗄𝖳::P,a::TVHφP=(M,Q)Q,a::T𝗍𝗁𝗎𝗇𝗄𝖳::M++[𝖾𝗇𝖽𝖳𝗁𝗎𝗇𝗄𝖳],a::VH𝖿𝗈𝗋𝖼𝖾𝖳::P,a::T𝗍𝗁𝗎𝗇𝗄𝖳::M++[𝖾𝗇𝖽𝖳𝗁𝗎𝗇𝗄𝖳],b::VHM,b::P,a::TVH𝗅𝖺𝗆𝖳::P,a::TVHφP=(M,Q)Q,a::T𝗅𝖺𝗆𝖳::M++[𝖾𝗇𝖽𝖫𝖺𝗆𝖳],a::VH𝖺𝗉𝗉𝖳::P,a::TQ::𝗅𝖺𝗆𝖳::M++[𝖾𝗇𝖽𝖫𝖺𝗆𝖳],b::VH𝗉𝗎𝗍H{Q,b}=(H,c)M,c::P,a::TVH𝗋𝖾𝗍𝖳::P,a::TM,b::VHP,a::TM,b::VHφP=(N,Q)𝗌𝖾𝗊𝖳::P,a::TM,b::VH𝗉𝗎𝗍H{M,b,a}=(H,c)N,c::Q,a::TVHφP=(N,Q)𝗉𝗎𝗍H{M2,b2,a}=(H1,c1)𝗉𝗌𝖾𝗊𝖳::P,a::TM2,b2::M1,b1::VH𝗉𝗎𝗍H1{M1,b1,a}=(H2,c2)N,c2::Q,a::TVH2φP=(M,Q)𝗅𝖾𝗍𝖳::P,a::TK::VH𝗉𝗎𝗍H{K,a}=(H,b)M,b::Q,a::TVH[],a::TVHTVH

Figure 4: Transition Rules for the Heap Machine.

Correspondence between programs and CBPV terms is here relative to an environment. We therefore use the unfolding judgement, written (H,a|m1)km2, which takes as inputs a heap H, a pointer a, a variable bound number k, and two CBPV terms m1 and m2. It returns true when m2 is identical to m1 with all of its free variables replaced by their values in H. A representative subset of the unfolding rules are shown in Figure 5. The two variable rules are the interesting ones. The first variable rule unfolds a bound variable to itself. The second variable rule (at the bottom) unfolds free variables to their value on the heap.

Figure 5: A Selection of Unfolding Rules.

We define a heap-aware correspondence using the unfolding function as follows:

Definition 14 (Closure-Term Correspondence with Heap).

: For any closure P,a with heap H and CBPV term n, P,a is the corresponding closure for n (written as P,aHn) if and only if there exists a CBPV term m such that (H,a|m)0n and γ(m)=P.

We prove in HOL4 that the heap machine can simulate CBPV with constant overhead in time:

Lemma 15 (Heap Machine Time Simulation).

If mkn then there exists k such that (Pm, 0,[],[])k([],Pn,a,H), where k10k+3 and Pm, 0m and Pn,aHn.

Proof.

By rule induction on the big-step semantics of CBPV. The space cost is unrelated to that of the CBPV reduction. Instead, the size of the kth state is bounded by the size of the original CBPV term, and the number of steps:

Lemma 16 (Heap Machine Space Simulation).

If (Pm,[],[])k(T,N,H) and Pmm then T++N++H(3k+1)(4k+2m).

Proof.

The proof proceeds by showing each stack’s length and that all elements in each stack are bounded by the size of the original term m and the number of transitions taken k.

6 CBPV is Reasonable for Both Time and Space

In this section, we use the results from Section 5 to prove that CBPV is reasonable. We achieve this by providing two simulations between CBPV and Turing machines, as elaborated in Figure 6.

Section 6.1 describes how Turing machines can simulate CBPV with polynomial time overhead and constant factor space overhead, fulfilling Theorem 1 in Section 2. Note that this simulation goes through the abstract machines we implemented and formalised in Section 5.

Section 6.2 describes how CBPV can reasonably simulate WCBV. We adapt the result that WCBV can reasonably simulate Turing machines from existing literature [11]. Together, we have that CBPV can simulate Turing machines with polynomial time overhead and constant factor space overhead, fulfilling Theorem 2 in Section 2.

Figure 6: Simulation between Turing Machines and CBPV with Intermediate Models.

6.1 Turing Machines Simulating CBPV

In this section we show that it is always possible to construct a Turing machine M𝐶𝐵𝑃𝑉 that simulates CBPV with polynomially bounded time overhead and constant factor space overhead. The results from Section 5, specifically, Lemmas 9, 10, 15, and 16, will be used here.

Our proof is very similar to a proof from the literature [11], where similar heap and substitution machines are interleaved to obtain a simulation of WCBV rather than CBPV. Their proof relies on formalised results similar to our formalised results, and proves that the interleaving strategy always obeys the required time and space bounds. We demonstrate that their argument extends to the more general case of CBPV. While our abstract machines are much more involved, they have similar time and space bounds, which simplifies adaptation.

We need to construct Turing machines M𝑠𝑢𝑏𝑠𝑡 and Mℎ𝑒𝑎𝑝 that simulate the respective abstract machines. We must then prove that one can always construct a Turing machine M𝐶𝐵𝑃𝑉 that interleaves M𝑠𝑢𝑏𝑠𝑡 and Mℎ𝑒𝑎𝑝 such that they always obey the required bounds.

The substitution-based Turing machine M𝑠𝑢𝑏𝑠𝑡 is constructed by iterating over smaller Turing machines each simulating an individual transition rule from Figure 3. Similarly, the heap-based Turing machine Mℎ𝑒𝑎𝑝 is constructed by iterating over Turing machines simulating the rules of Figure 4. In addition to the original CBPV term s, each of these machines takes as input a number of steps k that they are meant to simulate. The M𝑠𝑢𝑏𝑠𝑡 takes an additional input σ and aborts if the amount of space used is larger than σ. The encoding of the machine transition rules in Turing machines is straightforward, where we use 13 symbols to represent the 13 constructors(tokens) in the substitution machine. Similarly, we use 12 symbols to represent the 12 constructors(tokens) in the heap machine.

The algorithm then constructs M𝐶𝐵𝑃𝑉 by interleaving the above two machines, M𝑠𝑢𝑏𝑠𝑡 and Mℎ𝑒𝑎𝑝. Provided an input s which has a normal form t, the algorithm starts by applying M𝑠𝑢𝑏𝑠𝑡 over (the program equivalent of) s to reduce it. If a size explosion occurs during this reduction, execution then switches to use Mℎ𝑒𝑎𝑝 before the explosion happens. In this case, the heap-based strategy is guaranteed not to encounter the pointer explosion problem [11]. That is because the terms that cause size explosions result in a space cost of 𝒪(n2), which easily accommodates the logn space cost for pointer storage in the heap machine. This algorithm guarantees termination and reasonable time and space overhead.

Now let’s construct the Turing machines. In the following theorems, we write sT for the number of transition steps and sS for size of the biggest intermediate term.

We first consider the substitution machine. Msubst takes as inputs a term s, two numbers k and σ. s is the term to be reduced, k represents the number of transition steps to perform, and σ represents the space threshold over which the machine should abort. We show that this machine must satisfy one of the following three conditions: (1) it returns a desired value t within k steps; (2) it reaches the space bound and halts; (3) it finishes k reductions and halts (within both space and time bounds). This is formally stated below as Theorem 17.

Theorem 17.

There exists a Turing machine Msubst that takes as inputs k,σ and a term s. It halts in time 𝒪(k poly(min (σ,sS))) and space 𝒪(min (σ,sS) + log σ + log k) while one of the following statements holds:

  • The machine outputs a term t, then s has normal form t and σsS and k3sT+1.

  • The machine halts in a state named space bound not reached and k3sT+1 holds.

  • The machine halts in a state named space bound reached and σ9sS holds.

Proof.

We can construct a Turing machine Msubst by looping Turing machines that implement the individual steps of the abstract substitution machine. We add an extra rule where this machine has to halt if it were to reach a state with size larger than σ. Note that the extra rule requires Msubst to halt even if it is in the middle of execution, in order to avoid the size explosion problem. With an initialisation function τ that converts s from a λ-term into a program τ(s), we now have the desired Turing machine Msubst.

The time and space cost from the substitution machine mostly carry over directly, but the extraction functions φ cannot be implemented in constant time. For instance, φQkP takes time and space 𝒪(Q+P+k).

From Lemma 10, we know that if ssSt then there exists σ such that (Ps,[])σ([],Pt), where sSσ9sS and Pss and Ptt. Thus the size of all intermediate states and the overall space consumption lie within 9sS.

From Lemma 9, we know that if ssTt, then there exists k such that (Ps,[])k([],Pt) where k3sT+1 and Pss and Ptt. Thus there must exist a k that is large enough to simulate the reduction while still lying within the bound 3sT+1.

The next step is to construct the heap-based Turing machine Mheap:

Theorem 18.

There exists a Turing machine Mheap that, given a number k and a closed term s, halts in time 𝒪(poly(s,k)) and space 𝒪(s poly(k)). If s has a normal form t and k10sT+3, it computes a heap H and a closure g such that gHt. Otherwise, it halts in a distinguished final state (denoting “failure”).

Proof.

We can implement the abstract substitution machine from Section 5.3 by looping Turing machines that implement the individual steps of the abstract machine.

Time and space cost of the φ functions is as in Theorem 17. We also have to consider the 𝗅𝗈𝗈𝗄𝗎𝗉 function. 𝗅𝗈𝗈𝗄𝗎𝗉 iterates through the heap for n indices using the heap headers (a in this case) as pointers, resulting in at most 𝒪(n) time cost.

Thus each abstract step (T,V,H)(T,V,H) can be implemented in 𝒪(poly((T,V,H))) time and 𝒪(𝑚𝑎𝑥((T,V,H),(T,V,H))) space. The space consumption of all involved operations in Figure 4 is bounded by their input or output. Using Lemma 16, the size of all intermediate (T,V,H) can be bound by k and s to derive the claimed resource bounds. The successful computation of g and H for large enough k follows with Lemma 15.

Before constructing MCBPV, we need a lemma to say that unfolding only changes de Bruijn indices starting at k. In particular, closed terms are invariant under unfolding.

Lemma 19.

If s is bounded by k, then (s,a|H)ks.

Proof.

Induction on sk.

We now combine everything together to form our final theorem.

Theorem 20.

There is a Turing machine MCBPV that, given a closed term s that has a normal form t, computes a heap H and a closure g such that g H t in time 𝒪(poly(s, sT)) and space 𝒪(sS).

Proof.

By using the interleaving algorithm (Algorithm 1) adapted from WCBV [11].

Algorithm 1 Interleaving Strategy Algorithm.

Let p be the polynomial such that the machine from Theorem 18 runs in space 𝒪(sp(k)).

  1. 1.

    Initialise k:=0 (in binary)

  2. 2.

    Compute σ:=sp(k) (in binary)

  3. 3.

    Run Msubst on s, k and σ.

    1. (a)

      If Msubst computes the normal form t, output (γ(t),0) and an empty heap [ ] and halt.

    2. (b)

      If Msubst halts with space bound not reached, set k:=k+1 and go to 2

    3. (c)

      If Msubst halts with space bound reached, continue at 4.

  4. 4.

    Run Mheap on s and k.

    1. (a)

      If this computed a closure g and a heap H representing t, output H and g and halt.

    2. (b)

      Otherwise, set k:=k+1 and go to 2.

There are four things to prove about the algorithm. We will go through them one by one.

Halting states.

MCBPV has only two halting states: when Msubst returns (state 3(a) in Algorithm 1), and when Mheap returns (state 4(a)). In both cases, MCBPV returns a closure-heap pair representing the normal form t of s. In the first case, Theorem 17 shows that Msubst will return a normal form t of s and Lemma 19 shows that the closure-heap pair we constructed in state 3(a) indeed represents t. The second case is immediate Theorem 18.

Termination.

The machine will terminate for terminating terms s and diverge on non-terminating CBPV terms. For the terminating case, we need to show two things: (1). for all k, each iteration eventually finishes and goes to the next iteration; (2). there exists a k such that the machine halts and returns a closure-heap pair. We consider (1) first, and fix k. Time cost in step 1 is constant. Binary computation in Turing machines have polynomial cost, thus the time cost in step 2 is 𝒪(poly(s,(k))). Using Theorem 17, step 3 takes time

𝒪(kpoly(min(σ,sS)))𝒪(kpoly(σ))=𝒪(kpoly(sp(k)))from step 2𝒪(kpoly(s,k))p is a polynomial𝒪(poly(s,k))

If Step 4 is executed, this takes time 𝒪(poly(s,k)) by Theorem 18. Since each of the four steps has at most time complexity 𝒪(poly(s,k)), one iteration has time cost 𝒪(poly(s,k)), which suffices for (1). For (2), consider k=10sT+3, which is larger than the two values required in Theorem 17 and Theorem 18. By Theorem 17, the machine does halt during Step 3, unless σsS. In the latter case, 4 is tried. Then, by Theorem 18, as k is large enough, we have that Mheap indeed halts with a closure-heap pair.

Time Complexity.

We have proved the time cost for each iteration, so we just need to sum up all the iterations for the overall time complexity for MCBPV:

𝒪(k=010sT+3(poly(s,k)))𝒪(sTpoly(s,sT))𝒪(poly(s,sT))
Space Complexity.

We first analyse the space cost for one iteration with an arbitrary k. Step 1 is constant. Step 2 takes 𝒪(log(σ)) space since the computation is in binary. By Theorem 17, Step 3 takes space 𝒪(min(σ,sS)+logσ+logk)𝒪(sS+logσ+logk). If step 3(c) reaches the space bound (σ3sS), step 4 is tried. Together with Theorem 18 and definition of m, the space cost for step 4 is 𝒪(sp(k))𝒪(σ)𝒪(sS).

Thus we have the space cost of one iteration:

𝒪(sS+logσ+logk)=𝒪(sS+log(sp(k))+logk)(definition of σ)𝒪(sS+logs+log(p(k))+logk)=𝒪(sS+log(p(k))+logk)(as ssS)=𝒪(sS+log(kc)+logk)(c const., p poly.)=𝒪(sS+clog(k)+logk)𝒪(sS+logk)

The space cost for all iterations is as follows, where the last equation is by Lemma 21:

𝒪(max0k10sT+3(sS+logk))𝒪(sS+logsT)=𝒪(sS)

By combining our formalisation with results above, we obtain Theorem 2.

For terms with sT𝒪(sS) it is crucial that the machine tracks the step number k in binary, because it would need Ω(sT) space otherwise. This suffices because of Lemma 21:

Lemma 21.

logsT𝒪(sS).

Proof.

As the vocabulary is finite, there are at most exponentially many terms for a given size. A reduction from s cannot visit the same term twice since reduction is deterministic. sS is the biggest intermediate term, which means that all the terms in the reduction for s will be smaller than sS. This implies that sT will be at most equal to the total number of terms smaller than sS. Formally: sTcsS for a constant c.

To see that the number of terms smaller than a given size σ is at most exponential, note that #{t|tσ}=#{t|γ(t)2σ} by Lemma 6. Because γ is injective we have #{t|γ(t)2σ}=#{P|P2σ}, which is #{P|P2σ}. Finally, #{P|P2σ}5n1 follows by induction on n. The 5 is because there are four different symbols a program can start with, and variables indices use a fifth symbol.

6.2 CBPV Simulating WCBV

In this section, we prove that CBPV can simulate Turing machines with reasonable time and space overhead. We achieve this by using WCBV as an intermediate model. There is existing work showing WCBV can simulate Turing machines with reasonable time and space overhead [11]. Thus what remains to be shown in this section is a reasonable simulation of WCBV using CBPV. With prior work, this suffices to prove Theorem 2.

Let T denote the set of WCBV λ-terms constructed from the following grammar:

t,uT:=𝗏𝖺𝗋x|𝖺𝗉𝗉TT|λ.T

WCBV does not allow reduction under λ. Time and space cost semantics are as in [11]:

The compilation function c(t) is then defined as follows:

c(𝗏𝖺𝗋x)=𝗏𝖺𝗋xc(λ.t)=𝗋𝖾𝗍𝗍𝗁𝗎𝗇𝗄λ.c(t)c(𝖺𝗉𝗉tu)=𝗉𝗌𝖾𝗊(c(u))(c(t))(𝖺𝗉𝗉(𝖿𝗈𝗋𝖼𝖾𝗏𝖺𝗋 0)(𝗏𝖺𝗋 1))

We prove that CBPV can simulate WCBV with constant overheads, by a routine induction:

Theorem 22.

For each closed WCBV term t, we have:

  1. 1.

    If t˙ku, then there exists k such that c(t)kc(u) and k5k; and

  2. 2.

    If t˙su, then there exists s such that c(t)sc(u) and s6s.

Note that the standard translation uses 𝗌𝖾𝗊 twice instead of 𝗉𝗌𝖾𝗊 once, like this:

cη(𝗏𝖺𝗋x)=𝗏𝖺𝗋η(x)cη(λ.t)=𝗋𝖾𝗍𝗍𝗁𝗎𝗇𝗄λ.cη[00](t)cη(𝖺𝗉𝗉tu)=𝗌𝖾𝗊(cη(u))(𝗌𝖾𝗊cη(t)(𝖺𝗉𝗉(𝖿𝗈𝗋𝖼𝖾𝗏𝖺𝗋 0)(𝗏𝖺𝗋 1)))

Some de Bruijn arithmetic is needed to account for the extra binder in the 𝖺𝗉𝗉 case. Environments η are (partial) functions from to . We define lifting operators as follows:

ηxη(x)+1ηxη(x+1)+1η[xy](z){yif x=zη(z)otherwise

However, it turns out that c has linear space overhead, because there exists terms t such that c(t)=Ω(t2), as shown by the following example. Consider a term tn consisting of n right-associated applications, followed by n occurrences of the variable 0. For example, we’d have the following, where 𝖨 denotes the identity function λ.𝗏𝖺𝗋 0:

t1𝖺𝗉𝗉𝖨(𝗏𝖺𝗋 0)t2𝖺𝗉𝗉𝖨(𝖺𝗉𝗉𝖨(𝖺𝗉𝗉(𝗏𝖺𝗋 0)(𝗏𝖺𝗋 0)))t3𝖺𝗉𝗉𝖨(𝖺𝗉𝗉𝖨(𝖺𝗉𝗉𝖨(𝖺𝗉𝗉(𝖺𝗉𝗉(𝗏𝖺𝗋 0)(𝗏𝖺𝗋 0))(𝗏𝖺𝗋 0))))

We have size(tn)=𝒪(n). But if we consider c(tn), the n occurrences of 𝗏𝖺𝗋 0 in tn become n occurrences of 𝗏𝖺𝗋n, and hence size(tn)=Ω(n2).

This technicality arises because de Bruijn indices count towards term size. We must count like so because numbers are not representable in constant space on Turing machines.

Fortunately, the problematic additional bindings introduced by applications are vacuous over the operand. Translating CBPV to WCBV requires introducing intermediary bindings, and we cannot solve the issue by shuffling arguments: it is necessary for either the operator or operand of an application to be in the scope of a vacuous binding. Based on this observation, we conjecture that without 𝗉𝗌𝖾𝗊 (or products), CBPV is not reasonable for space.

6.2.1 Do we need to go to Turing machines?

Since WCBV is known to be reasonable, the reader may wonder if we must go all the way to Turing machines to prove Theorem 2. Wouldn’t going to WCBV be simpler? This turns out to be straightforward for time cost, but unfortunately the natural encoding of CBPV in WCBV has linear space overhead (cf. Section 6.2). Consider this compilation function:

d(𝗏𝖺𝗋x)=𝗏𝖺𝗋xd(𝗍𝗁𝗎𝗇𝗄m)=λ.d(m)d(𝖿𝗈𝗋𝖼𝖾v)=𝖺𝗉𝗉(d(v))λ.𝗏𝖺𝗋 0d(𝗋𝖾𝗍v)=d(v)d(λ.m)=λ.d(m)d(𝖺𝗉𝗉mv)=𝖺𝗉𝗉(d(m))(d(v))d(𝗌𝖾𝗊mn)=𝖺𝗉𝗉(λ.d(m))(d(n))d(𝗅𝖾𝗍v.𝗂𝗇m)=𝖺𝗉𝗉(λ.d(m))(d(v))d(𝗉𝗌𝖾𝗊m2m1n)=𝖺𝗉𝗉(𝖺𝗉𝗉(λ.λ.d(n))(d(m2)))(d(m1))

We flatten the distinction between values and computations, and to suspend computations we use the one mechanism on offer: λ-abstraction. We have proved that this compilation strategy is reasonable for time cost. Unfortunately, it does not yield a reasonable space cost model. To see why, consider the following variation on the example from the previous section.

t1𝖺𝗉𝗉(𝖿𝗈𝗋𝖼𝖾𝗏𝖺𝗋 0)(𝗏𝖺𝗋 0)t2𝖿𝗈𝗋𝖼𝖾𝗍𝗁𝗎𝗇𝗄𝖺𝗉𝗉(𝖺𝗉𝗉(𝖿𝗈𝗋𝖼𝖾𝗏𝖺𝗋 0)(𝗏𝖺𝗋 0))(𝗏𝖺𝗋 0)t3𝖿𝗈𝗋𝖼𝖾𝗍𝗁𝗎𝗇𝗄𝖿𝗈𝗋𝖼𝖾𝗍𝗁𝗎𝗇𝗄𝖺𝗉𝗉(𝖺𝗉𝗉(𝖺𝗉𝗉(𝖿𝗈𝗋𝖼𝖾𝗏𝖺𝗋 0)(𝗏𝖺𝗋 0))(𝗏𝖺𝗋 0))(𝗏𝖺𝗋 0)

That is, term tn contains 𝒪(n) mentions of 𝗏𝖺𝗋 0 under 𝒪(n) layers of thunks. We have size(tn)=𝒪(n). But when we consider d(tn), the n occurrences of 𝗏𝖺𝗋 0 in tn become n occurrences of 𝗏𝖺𝗋n, and hence size(d(tn))=Ω(n2).

Clearly a reasonable encoding in this direction is impossible: the detour via Turing machines would yield one. But the choice of encoding function would not be obvious.

7 Conclusion and Future Work

In this paper, we establish the first time and space cost models for the CBPV λ-calculus and formally verify that CBPV relates to intermediate abstract machines. These intermediate machines are interleaved to maintain the desired time and space bounds in relation to Turing machines by extending known results about weak call-by-value [11, 12]. Together, this gives the first proof that CBPV is a reasonable model of computation. Hence, CBPV can serve as a basis for reasoning about the computational complexity of functional programs.

In future work we plan to investigate cost models for extensions to CBPV that support call-by-need evaluation. Moreover, it is unclear how the Bang calculus [9] relates to CBPV in terms of time and space cost, and whether the Bang calculus is reasonable. It would also be interesting to consider sublinear complexity classes. Finally, it would be interesting to extend our work into cost models for λ-calculus variants with different evaluation strategies, thus laying the foundation for a unifying approach of complexity analysis for the λ-calculus.

References

  • [1] Beniamino Accattoli. (in)efficiency and reasonable cost models. In Sandra Alves and Renata Wasserman, editors, 12th Workshop on Logical and Semantic Frameworks, with Applications, LSFA 2017, Brasília, Brazil, September 23-24, 2017, volume 338 of Electronic Notes in Theoretical Computer Science, pages 23–43. Elsevier, 2017. doi:10.1016/j.entcs.2018.10.003.
  • [2] Beniamino Accattoli and Ugo dal Lago. (leftmost-outermost) beta reduction is invariant, indeed. Log. Methods Comput. Sci., 12(1), 2016. doi:10.2168/LMCS-12(1:4)2016.
  • [3] Beniamino Accattoli, Ugo Dal Lago, and Gabriele Vanoni. Reasonable space for the λ-calculus, logarithmically. In Christel Baier and Dana Fisman, editors, LICS ’22: 37th Annual ACM/IEEE Symposium on Logic in Computer Science, Haifa, Israel, August 2 - 5, 2022, pages 47:1–47:13. ACM, 2022. doi:10.1145/3531130.3533362.
  • [4] Zhuo Chen. cbpv-reasonable-hol, June 2025. URL: https://github.com/ZhuoZoeyChen/cbpv-reasonable-HOL.
  • [5] Zhuo Zoey Chen, Johannes Åman Pohjola, and Christine Rizkallah. cbpv-reasonable-HOL. Software, swhId: swh:1:dir:df18377e9fa5e35255f2687ad66ddbc2f010b934 (visited on 2025-09-11). URL: https://github.com/ZhuoZoeyChen/cbpv-reasonable-HOL/, doi:10.4230/artifacts.24718.
  • [6] Jules Chouquet and Christine Tasson. Taylor expansion for call-by-push-value. In Maribel Fernández and Anca Muscholl, editors, 28th EACSL Annual Conference on Computer Science Logic, CSL 2020, January 13-16, 2020, Barcelona, Spain, volume 152 of LIPIcs, pages 16:1–16:16. Schloss Dagstuhl – Leibniz-Zentrum für Informatik, 2020. doi:10.4230/LIPICS.CSL.2020.16.
  • [7] Alonzo Church. A set of postulates for the foundation of logic. Annals of Mathematics, 33(2):346–366, 1932. URL: http://www.jstor.org/stable/1968337.
  • [8] Ugo dal Lago and Simone Martini. The weak lambda calculus as a reasonable machine. Theor. Comput. Sci., 398(1-3):32–50, 2008. doi:10.1016/j.tcs.2008.01.044.
  • [9] Thomas Ehrhard and Giulio Guerrieri. The bang calculus: an untyped lambda-calculus generalizing call-by-name and call-by-value. In James Cheney and Germán Vidal, editors, Proceedings of the 18th International Symposium on Principles and Practice of Declarative Programming, Edinburgh, United Kingdom, September 5-7, 2016, pages 174–187. ACM, 2016. doi:10.1145/2967973.2968608.
  • [10] Thomas Ehrhard and Christine Tasson. Probabilistic call by push value. CoRR, abs/1607.04690, 2016. arXiv:1607.04690.
  • [11] Yannick Forster, Fabian Kunze, and Marc Roth. The weak call-by-value λ-calculus is reasonable for both time and space. Proc. ACM Program. Lang., 4(POPL):27:1–27:23, 2020. doi:10.1145/3371095.
  • [12] Yannick Forster, Fabian Kunze, Gert Smolka, and Maximilian Wuttke. A mechanised proof of the time invariance thesis for the weak call-by-value λ-calculus. In Liron Cohen and Cezary Kaliszyk, editors, 12th International Conference on Interactive Theorem Proving, ITP 2021, June 29 to July 1, 2021, Rome, Italy (Virtual Conference), volume 193 of LIPIcs, pages 19:1–19:20. Schloss Dagstuhl – Leibniz-Zentrum für Informatik, 2021. doi:10.4230/LIPIcs.ITP.2021.19.
  • [13] Yannick Forster, Steven Schäfer, Simon Spies, and Kathrin Stark. Call-by-push-value in coq: Operational, equational, and denotational theory. In Assia Mahboubi and Magnus O. Myreen, editors, Proceedings of the 8th ACM SIGPLAN International Conference on Certified Programs and Proofs, CPP 2019, Cascais, Portugal, January 14-15, 2019, pages 118–131. ACM, 2019. doi:10.1145/3293880.3294097.
  • [14] Dmitri Garbuzov, William Mansky, Christine Rizkallah, and Steve Zdancewic. Structural operational semantics for control flow graph machines. CoRR, abs/1805.05400, 2018. arXiv:1805.05400.
  • [15] G. A. Kavvos, Edward Morehouse, Daniel R. Licata, and Norman Danner. Recurrence extraction for functional programs through call-by-push-value. Proc. ACM Program. Lang., 4(POPL):15:1–15:31, 2020. doi:10.1145/3371083.
  • [16] Delia Kesner and Andrés Viso. The power of tightness for call-by-push-value. CoRR, abs/2105.00564, 2021. arXiv:2105.00564.
  • [17] Fabian Kunze, Gert Smolka, and Yannick Forster. Formal small-step verification of a call-by-value lambda calculus machine. In Sukyoung Ryu, editor, Programming Languages and Systems - 16th Asian Symposium, APLAS 2018, Wellington, New Zealand, December 2-6, 2018, Proceedings, volume 11275 of Lecture Notes in Computer Science, pages 264–283. Springer, 2018. doi:10.1007/978-3-030-02768-1_15.
  • [18] Julia L. Lawall and Harry G. Mairson. Optimality and inefficiency: What isn’t a cost model of the lambda calculus? In Robert Harper and Richard L. Wexelblat, editors, Proceedings of the 1996 ACM SIGPLAN International Conference on Functional Programming, ICFP 1996, Philadelphia, Pennsylvania, USA, May 24-26, 1996, pages 92–101. ACM, 1996. doi:10.1145/232627.232639.
  • [19] Paul Blain Levy. Call-by-push-value: A subsuming paradigm. In Jean-Yves Girard, editor, Typed Lambda Calculi and Applications, 4th International Conference, TLCA’99, L’Aquila, Italy, April 7-9, 1999, Proceedings, volume 1581 of Lecture Notes in Computer Science, pages 228–242. Springer, 1999. doi:10.1007/3-540-48959-2_17.
  • [20] Paul Blain Levy. Call-by-Push-Value. PhD thesis, Queen Mary University of London, UK, 2001. URL: https://ethos.bl.uk/OrderDetails.do?uin=uk.bl.ethos.369233.
  • [21] Paul Blain Levy. Adjunction models for call-by-push-value with stacks. In Richard Blute and Peter Selinger, editors, Category Theory and Computer Science, CTCS 2002, Ottawa, Canada, August 15-17, 2002, volume 69 of Electronic Notes in Theoretical Computer Science, pages 248–271. Elsevier, 2002. doi:10.1016/S1571-0661(04)80568-1.
  • [22] Dylan McDermott and Alan Mycroft. Extended call-by-push-value: Reasoning about effectful programs and evaluation order. In Luís Caires, editor, Programming Languages and Systems - 28th European Symposium on Programming, ESOP 2019, Held as Part of the European Joint Conferences on Theory and Practice of Software, ETAPS 2019, Prague, Czech Republic, April 6-11, 2019, Proceedings, volume 11423 of Lecture Notes in Computer Science, pages 235–262. Springer, 2019. doi:10.1007/978-3-030-17184-1_9.
  • [23] Robin Milner, Mads Tofte, and Robert Harper. Definition of standard ML. MIT Press, 1990.
  • [24] Christine Rizkallah, Dmitri Garbuzov, and Steve Zdancewic. A formal equational theory for call-by-push-value. In Jeremy Avigad and Assia Mahboubi, editors, Interactive Theorem Proving - 9th International Conference, ITP 2018, Held as Part of the Federated Logic Conference, FloC 2018, Oxford, UK, July 9-12, 2018, Proceedings, volume 10895 of Lecture Notes in Computer Science, pages 523–541. Springer, 2018. doi:10.1007/978-3-319-94821-8_31.
  • [25] Konrad Slind and Michael Norrish. A brief overview of HOL4. In Otmane Aït Mohamed, César A. Muñoz, and Sofiène Tahar, editors, Theorem Proving in Higher Order Logics, 21st International Conference, TPHOLs 2008, Montreal, Canada, August 18-21, 2008. Proceedings, volume 5170 of Lecture Notes in Computer Science, pages 28–32. Springer, 2008. doi:10.1007/978-3-540-71067-7_6.
  • [26] Cees F. Slot and Peter van Emde Boas. On tape versus core; an application of space efficient perfect hash functions to the invariance of space. In Richard A. DeMillo, editor, Proceedings of the 16th Annual ACM Symposium on Theory of Computing, April 30 - May 2, 1984, Washington, DC, USA, pages 391–400. ACM, 1984. doi:10.1145/800057.808705.
  • [27] Cassia Torczon, Emmanuel Suárez Acevedo, Shubh Agrawal, Joey Velez-Ginorio, and Stephanie Weirich. Effects and coeffects in call-by-push-value (extended version). CoRR, abs/2311.11795, 2023. doi:10.48550/arXiv.2311.11795.
  • [28] Peter van Emde Boas. Chapter 1 - machine models and simulations. In Jan Van Leeuwen, editor, Algorithms and Complexity, Handbook of Theoretical Computer Science, pages 1–66. Elsevier, Amsterdam, 1990. doi:10.1016/B978-0-444-88071-0.50006-0.