Data Layout from a Type-Theoretic Perspective

The specifics of data layout can be important for the efficiency of functional programs and interaction with external libraries. In this paper, we develop a type-theoretic approach to data layout that could be used as a typed intermediate language in a compiler or to give a programmer more control. Our starting point is a computational interpretation of the semi-axiomatic sequent calculus for intuitionistic logic that defines abstract notions of cells and addresses. We refine this semantics so addresses have more structure to reflect possible alternative layouts without fundamentally departing from intuitionistic logic. We then add recursive types and explore example programs and properties of the resulting language.


Introduction
The Curry-Howard isomorphism establishes a firm relationship between the propositions of intuitionistic logic and types for functional programs.Even if both sides of this correspondence are intuitionistic, the precise relation between proofs and functional programs varies significantly with the proof system.Curry [4], for example, related Hilbert-style axiomatic proofs to combinators and combinatory reduction.Howard [12], on the other hand, related natural deductions to terms in the typed λ-calculus.As a further example, Herbelin [11] related an intuitionistic sequent calculus with a "stoup" (LJT) to a λ-calculus with a form of explicit substitution.The computational mechanism in each of these examples is quite different and in each case derives from a proof-theoretic notion of reduction.The logical motivation for these reductions stems from the desire to prove, constructively at the meta-level, the consistency of specific systems of inference rules [8].Moreover, proofs that are fully reduced (called normal or cut-free, depending on the system) exhibit the subformula property, which means they can serve as verifications [7,14].
The basis for this paper is the recently discovered semi-axiomatic sequent calculus [6] and its correspondence to futures [2,10].Briefly, the semi-axiomatic sequent calculus starts from the intuitionistic sequent calculus and replaces the right rules for positive connectives (positive conjunctions A 1 ∧ A 2 , positive unit ⊤, and disjunctions A 1 ∨ A 2 ) and the left rules for negative connectives (implications A 1 ⊃ A 2 and negative conjunctions A 1 A 2 ) by axioms.For example, the six axioms A 1 , A 2 ⊢ A 1 ∧ A 2 ; A k ⊢ A 1 ∨ A 2 for k ∈ {1, 2}; A 1 , A 1 ⊃ A 2 ⊢ A 2 ; and A 1 A 2 ⊢ A k for k ∈ {1, 2} replace the usual ∧r, ∨r k , ⊃l, and l k rules, respectively, while the ∧l, ∨l, ⊃r, and r rules remain unchanged.This restructuring leads to a failure of Gentzen's cut elimination theorem [8]: some cuts (called snips) are essential and cannot be eliminated.Fortunately, all snips arise from the new axioms and can be shown to obey a subformula property [6,Theorem 7] derived from the evident subformula property of the new axioms (A 1 and A 2 are subformulas of A 1 ∧ A 2 , etc.).
Computationally, a process is assigned to each proof in the semi-axiomatic sequent calculus, arriving at a type theory dubbed SAX [6, section 5].Both cuts and snips are treated as the allocation of a future, with the two premises of the cut or snip computing in parallel.The first premise computes and writes the value of the future, while the second may read its value, potentially blocking until it has been written.The type of the future (that is, the cut formula) determines the form of value that it ultimately holds.
The key observation underlying this paper is that we have the freedom to give different computational interpretations to cuts and snips.The subformula property of the new axioms, reflected in the snips, is manifest in projections from the values of larger types to those of smaller types.For example, ordinarily we might think of assigning terms to the axiom Instead, if we ensure that x : A 1 ∧ A 2 has already been allocated, the axiom expresses address projections Taking it further, this axiom can be seen as merely computing the addresses of A 1 and A 2 , given the address for the pair A 1 ∧ A 2 .Under this interpretation, only cuts allocate memory for a future.A snip is then the parallel composition of two processes that respectively write to and read from a shared portion of a future that has already been allocated.
When we go beyond the usual propositions-as-types correspondence and add recursive types and recursive processes to our language, we have to slightly modulate our approach.For example, a type of lists of booleans satisfying the equation boollist = {nil : 1, cons : bool × boollist } would require an unbounded (or unpredictable) amount of space for a value of type boollist .In order to avoid this problem, we introduce a type constructor ↓A, originating in adjoint logic [3,19,17], that is inhabited by addresses for cells of type A, i.e., pointers.Logically, this has no force in the sense that A ⊣ ⊢ ↓A, but it affects the fine structure of proofs.Every recursive type must be guarded by a ↓ shift, as in boollist = {nil : 1, cons : ↓bool × ↓boollist }.This expresses a layout where a binary number is either just the tag nil or a tag cons together with a pair of addresses, cons a 1 a 2 .Through different ways to place ↓ shifts we can control the layout of the data.For example, here we would likely prefer boollist = {nil : 1, cons : bool × ↓boollist }, where the address of a boolean is replaced by the boolean itself.
In summary, the main contributions of this paper are: • a reformulated semi-axiomatic sequent calculus that syntactically distinguishes cuts and snips so they can be assigned a different dynamics (section 3); and simultaneously • a new type theory, derived by Curry-Howard interpretation of the reformulated semi-axiomatic sequent calculus, for specifying data layout for futures-based concurrency (also in section 3); and • proofs of preservation and progress (including equirecursive types and recursive processes, section 3.6).Related work is discussed in section 4.An extended version of this paper can be found at arXiv [5].

SAX: A semi-axiomatic type theory for shared memory concurrency
The semi-axiomatic sequent calculus is a presentation of intuitionistic logic that blends inference rules of the sequent calculus with axioms of the Hilbert calculus [6].Perhaps surprisingly, there is a Curry-Howard correspondence between the semi-axiomatic sequent calculus and a type theory for futures [2,10], a form of write-once shared memory concurrency.Here we give a detailed review of the semi-axiomatic DeYoung and Pfenning 2-3 sequent calculus and its SAX type theory (though slightly altered to use explicit rules of weakening and contraction) because they serve as the cornerstones for our SNAX type theory.

Judgmental aspects.
Following the usual Curry-Howard pattern, the propositions of intuitionistic logic become SAX types, sequents become SAX static typing judgments, and their proofs become SAX processes.Sequents and SAX typing judgments correspond as follows: where the typing judgment is read as "Process P may read data of types A 1 , A 2 , . . ., A n from addresses a 1 , a 2 , . . ., a n , respectively, and must write data of type A to address a."This discipline also serves to enforce the invariant that each address is written by exactly one process.For this reason, we will sometimes refer to the address that a process must write to as the process's destination.
In both the semi-axiomatic proof theory and the SAX type theory, we use the metavariable Γ to stand for contexts -of either antecedents or readable addresses, respectively.SAX addresses have no structure, being only variables x that will be mapped to concrete addresses α at runtime.

Weakening and contraction.
For reasons that will become clear in section 3, we diverge slightly from the presentation of the semiaxiomatic sequent calculus and its SAX type theory seen in [6] and use explicit rules for weakening and contraction.With respect to process syntax, both weakening and contraction are silent.(The explicit rules for weakening and contraction mean that our SAX typing rules will not immediately yield a syntax-directed type checking algorithm.But conversion to the implicit weakening and contraction of [6] is standard, and those rules are directly suitable for type checking.)Cut and identity.
The semi-axiomatic sequent calculus's cut rule (inherited from the sequent calculus) corresponds to SAX's static typing rule for a notion of futures for concurrent computation, x P ; Q.
Operationally, x P ; Q runs by first allocating memory for data of type A and then running, in parallel, processes P and Q to write data to addresses x and c, respectively.If Q tries to read from address x before P has written to x, then Q will block until P does write to x. 4

2-4
Data Layout from a Type-theoretic Perspective The semi-axiomatic sequent calculus's identity rule (also inherited from the sequent calculus) corresponds to the SAX typing rule for a primitive operation, copy a b, for copying data from address b to address a.This copy operation is shallow: it does not follow pointers to copy recursively.
As we have done here, we will use pictures throughout this section to provide intuition about the way that data is laid out in SAX; in section 3, these will serve as a point of comparison with the layouts offered by our SNAX type theory.

Pairs, type
In the Curry-Howard isomorphism between natural deduction and the simply typed λ-calculus, conjunctions A 1 ∧ A 2 are interpreted as product types A 1 × A 2 that describe pairs of values of types A 1 and A 2 , respectively, (as well as describing the expressions that evaluate to such values).With the shift in perspective to the semi-axiomatic sequent calculus and shared memory concurrency, conjunction has a slightly different -but very closely related -interpretation: types A 1 × A 2 describe addresses a to which a pair a 1 , a 2 of addresses of types A 1 and A 2 , respectively, must be written (as well as describing the processes that must write to such addresses a).
The ∧a axiom of the semi-axiomatic sequent calculus thus corresponds to a static typing rule for the process write a a 1 , a 2 that writes a pair of addresses a 1 , a 2 to address a.
As a proof-theoretic aside, in the semi-axiomatic sequent calculus, the above ∧a axiom is used in place of the sequent calculus's full-fledged right rule, ∧r, that has premises Γ ⊢ A 1 and Γ ⊢ A 2 .Using the cut and identity rules, the ∧a axiom and the usual right rule are interderivable and therefore characterize the same notion of intuitionistic conjunction.The same pattern will hold for the other logical connectives in the semi-axiomatic sequent calculus: depending on whether the connective's polarity [1,9] is positive or negative, either the sequent calculus right or left rule will be replaced with an equivalently expressive axiom.Moreover, right axioms and right rules will write, whereas left axioms and left rules will read.
Under our shared memory interpretation, the left rule for conjunction becomes a static typing rule for the process read a ( x 1 , x 2 ⇒ P ) that reads the pair of addresses that is stored at address a: Operationally, the pair of addresses a 1 , a 2 stored at address a is read from memory; then variables x 1 and x 2 are bound to addresses a 1 and a 2 , respectively, and execution continues according to process P .
Example.At this point, we can consider our first, very simple example process.The commutativity of conjunction can be captured by a semi-axiomatic proof of A 1 ∧A 2 ⊢ A 2 ∧A 1 , and its computational content is a shared memory process of type p : A 1 × A 2 ⊢ q : A 2 × A 1 that creates a new pair at address q by swapping the components of the existing pair at address p: The process first reads from address p and binds variables x 1 and x 2 to the pair of addresses that are stored there.Then it writes those same addresses in reverse order as a pair at address q.
DeYoung and Pfenning
The unit type 1 is the nullary form of the product type A 1 × A 2 and arises in Curry-Howard correspondence with ⊤.The ⊤a axiom becomes a typing rule for the construct write a , and the ⊤l rule (which, also being an instance of weakening, is uninteresting in terms of provability, but is computationally relevant) becomes a typing rule for the construct read a ( ⇒ P ).
• ⊢ write a :: (a : 1) 1a Tagged unions, type {ℓ : A ℓ } ℓ∈L .Disjunction corresponds to a labeled sum type, {ℓ : A ℓ } ℓ∈L , for tagged unions.Being a positive connective, like conjunction and truth, disjunction's ∨a k axiom in the semi-axiomatic sequent calculus becomes a typing rule for writing a tagged address.Specifically, the process write a k a k writes a tag k and an address a k into memory at address a.
Symmetrically -and adhering to the pattern for positive types -the semi-axiomatic sequent calculus's ∨l rule becomes a typing rule for the reading construct read a (ℓ x ℓ ⇒ P ℓ ) ℓ∈L that branches on the tag that it reads from address a.
The process read a (ℓ x ℓ ⇒ P ℓ ) ℓ∈L reads the tag, say k ∈ L, stored at address a and selects the corresponding branch.The variable x k is bound to the address that was tagged by k, and execution continues according to P k .
Example.At this point, we can consider another simple example.Booleans can be described with the type {tt : 1, ff : 1}, which we abbreviate as bool .The following process reads the boolean stored at address a and then writes its negation at address b.The diagram shows the process's execution when the tag stored at address a is tt; the other case is symmetric.
Being a negative proposition, the implication A 1 ⊃ A 2 follows a story dual to that of the positive conjunction A 1 ∧ A 2 .Unlike the positive types, which write with axioms and read with left rules, the function type A 1 → A 2 that corresponds to implication writes with a right rule and reads with an axiom.
The semi-axiomatic sequent calculus's ⊃r rule therefore becomes a typing rule for the process write a ( x, z ⇒ P ).In practice, this process might write (a pointer to) a closure to address a, but closures exist at a lower level of abstraction than the Curry-Howard correspondence between the semiaxiomatic sequent calculus and SAX supports.For this reason, we think of the process write a ( x, z ⇒ P )

2-6
Data Layout from a Type-theoretic Perspective as writing the continuation ( x, z ⇒ P ).
Γ ⊢ write a ( x, z ⇒ P ) :: (a : The semi-axiomatic sequent calculus's ⊃a axiom becomes a typing rule for the construct read a a 1 , a 2 . This construct reads the continuation ( x, z ⇒ P ) stored at address a and passes it two addresses: a 1 , the address of the function argument of type A 1 to which the continuation should be applied; and a 2 , the address to which the called function should write its result of type A 2 .The variables x and z are bound to these addresses, respectively, and execution continues according to P .

Other types.
Other SAX types and process constructs also emerge from this Curry-Howard reading of the semiaxiomatic sequent calculus.For example, it is possible to adapt the negative polarity conjunction from intuitionistic logic to a type of lazy records (e.g., like call-by-push-value [13]).Its SAX typing rules are dual to those for tagged unions [6]; moreover, because function types already exemplify the key aspects of negative types in SAX, we do not present the details of negative conjunction and lazy records in this paper.
Another possible SAX type is ↓A, which arises from the downshift of adjoint logic [3,19,17].From a purely logical standpoint, ↓A is not especially interesting because ↓A is logically equivalent to A. Neither is ↓A particularly useful in SAX processes: it merely serves to introduce indirections beyond those already present in abundance in SAX.However, the type ↓A is also present in SNAX and becomes much more useful there, so we postpone further discussion of type ↓A, processes write a b and read a ( x ⇒ P ), and their typing rules and operational semantics to section 3.

Adding recursion to SAX
For most practical examples, recursively defined types and processes are needed.Recursion in SAX goes beyond a strict Curry-Howard correspondence with the semi-axiomatic sequent calculus, but only in the same way that recursive functional programming goes beyond a strict Curry-Howard correspondence with natural deduction.
Instead of adding an explicit µ, fold, and unfold operators, we use recursive type definitions and recursive process definitions.Recursive type definitions have the form t = A; we choose to treat them equirecursively so that t and its unfolding, A, are indistinguishable.Under this interpretation, type definitions like t = t would not be sensible, so SAX requires type definitions to be contractive: each type name t must (eventually) unfold to a logical type constructor like × or →.
Recursive process definitions have the form proc p (z: , where the argument x 1 :A 1 , . . ., x n :A n may be read by process P , and z:C is the destination to which P will write.(If the process P diverges, it escapes the obligation to write by postponing that obligation indefinitely.)Calls to these recursively defined processes are made by the process construct call p c a 1 • • • a n .Its typing rule is the following where Σ is a signature that holds recursive type and process definitions.(See section 2.3 for more details on signatures.) Operationally, call p c a 1 • • • a n will lookup the definition for p and execution will continue according to the definition's body, substituting addresses for the argument and destination variables.Accordingly, recursive process definitions are required to be contractive.

Extended example: mapping a function across a linked list of booleans
As an extended example of the SAX type theory, we can consider the recursive type boollist that describes linked lists of booleans.(A polymorphic type of linked lists is not currently possible in SAX, but adding parametric polymorphism to SAX is a primary goal of future work.)The type boollist is defined as follows.% allocate ys ′ and call map recursively with dest.ys ′ q write q y, ys ′ ; % allocate q and write pair of y and ys ′ write ys cons q )) % write the tagged pair to the original destination ys

Details of the SAX type theory
The types in SAX are as described above; recursive type definitions t = A and recursive process definitions proc p z x 1 • • • x n = P are collected in signatures Σ.A signature indexes the SAX typing judgment: Γ ⊢ Σ P :: (a : A).However, because none of the typing rules affect the signature, it is frequently elided.
SAX processes P and Q have one of five forms: allocations, copies, writes, reads, and calls.
Processes P, Q :: Writes rely on a syntactic category of storables S, which are the data that may be written into a memory cell.There is one storable for each type constructor: pairs of addresses, a 1 , a 2 ; unit value, ; tagged address, k a ; pointers, a ; and function continuations, ( x, z ⇒ P ).Reads rely on a syntactic category of co-storables T that are dual to storables.Once again, there is one form of co-storable for each type constructor: continuations for pairs, unit values, tagged unions, and pointers; and pairs of addresses to be passed to function continuations.We will not repeat the process typing rules here.The operational semantics of the SAX type theory is based on multiset rewriting, using three semantic objects: thread(a, P ) denotes a running process P that must write to address a; cell(a, ✷) denotes an empty memory cell at address a, i.e., one that has been allocated but not yet written; and !cell(a, S) denotes a filled memory cell at address a, i.e., one that has been allocated and now stores S. The '!' is notation borrowed from linear logic and denotes that filled cells implicitly persist across rewriting steps.

2-8
Data Layout from a Type-theoretic Perspective A configuration C is a collection of filled cells and threads with corresponding empty cells: We say that a configuration C is final if it consists only of filled cells !cell(a, S).Configurations are typed with a judgment Φ C :: Φ ′ .Configuration contexts Φ have the same syntactic structure as contexts Γ, but configuration contexts Φ are not subject to contraction; in the judgment Φ C :: Φ ′ , the addresses in Φ are therefore presumed to be distinct.Also, in C and Φ, we write a, b, and c for readability, but they are all fresh runtime addresses α (not variables x).The configuration typing judgment has the rules: Notice that both the thread and cell rules check that the address a is not already present in the domain of Γ, to ensure that each address has a unique type.Both rules also rely on the static typing judgment for SAX processes.
The concurrent operational semantics is then described by the following multiset rewriting clauses.
where S ⊲ T is given by Preservation and progress hold for the SAX type theory [6].

SNAX type theory for data layout
The SAX type theory does not take layout considerations into account in the sense that addresses remain entirely abstract.As a concrete example, a single cons node in a linked list of booleans can be thought of as laid out in SAX with three indirections, while a more compact flat layout would be more memory-efficient:

tt
, the flat layout cons tt . . . is likely preferable.
SAX's rather extreme level of indirection arises from its heavy reliance on the cut rule.This suggests that if we want to account for data layout in a SAX-like type theory, an understanding of cut elimination and the structure of cut-free proofs in the semi-axiomatic sequent calculus may provide some insight.

Cut elimination in the semi-axiomatic sequent calculus
Unfortunately, the semi-axiomatic sequent calculus does not immediately satisfy Gentzen-style cut elimination.As a counterexample, there is a semi-axiomatic proof of but there is no cut-free proof: the cut that appears here is essential and cannot be eliminated.However, notice that the above cut has a subformula property: the cut formula (here A 1 ) is a proper subformula of one of the conclusion sequent's formulas (here A 1 ∧ A 2 ).Moreover, this subformula property derives from the use of the cut formula within the occurrence of the ∧a axiom.Such formulas that are used by axioms are said to be eligible to act as the cut formula in one of these well-behaved cuts, which are called snips.Proof-theoretically, both eligibility and snips are thought of as properties of proofs: we can implicitly ignore that a formula is eligible and that a cut is a snip because eligibility is not part of the structure of the proof rules themselves.
Although semi-axiomatic proofs cannot be transformed to be fully cut-free, they can be transformed so that the only remaining cuts are these well-behaved snips.For example, the above proof can be reformulated using a snip as follows; the eligible formulas are indicated by underlining.
For more on the proof-theoretic view of eligibility as a property of proofs, we refer the reader to [6].

Making eligibility first-class
As we saw in section 2, the SAX type theory is a Curry-Howard interpretation of the semi-axiomatic sequent calculus that ignores eligibility and snips, viewing them as mere technical refinements used in recovering (a modified form of) cut elimination.However, in this section, we elevate eligibility and snips to be first-class concepts in the proof theory and thereby obtain, by Curry-Howard correspondence, a type theory that gives a clean, logically grounded account of data layout in shared memory concurrency.We will call the resulting type theory SNAX, short for "SAX with snips".
To make eligibility a structural component of the semi-axiomatic sequent calculus, contexts Γ now contain ordinary antecedents A and eligible antecedents A -eligibility is no longer a refinement property, but instead intrinsic to an antecedent.Owing to the subformula structure that underlies eligibility, an eligible antecedent A in a proof will correspond to an eligible address a•p : A, where p is a projection and a • p is a new form of address.For example, we will see shortly that just as A 1 is an eligible antecedent within the axiom for A 1 ∧ A 2 , so will a • π 1 be the address of the first component of a pair that itself begins at address a. (We will sometimes elide the • operator in a • p, especially when π 1 and π 2 are involved.) We say that a strictly extends c and write a ≻ c whenever a = c • p for some projection p; we also say that a (weakly) extends c and write a c whenever either a = c or a ≻ c.Note that every address has a variable (either a static x or a runtime α) at its head.This reflects the idea that memory will be allocated

2-10
Data Layout from a Type-theoretic Perspective in blocks and, at the level of abstraction that SNAX provides, each address exists relative to the base address of the block to which it belongs.Projections provide a clean, logical description of the abstract layout of data.On the other hand, machine code relies on concrete address arithmetic.To bridge this gap, we envision that, at a lower level of abstraction, projections would be concretized.One simple concretization (a) ⋆ underlying our diagrams would be the following: where However, this is not the only possible concretization.Practical compilers employ layout optimizations, such as bit-packing to reduce the space needed for the tags of consecutive tagged unions.By using projections, SNAX is agnostic about the particular concretization chosen and remains flexible.
Aside from the changes to addresses and contexts, sequents and typing judgments look the same as in SAX: Γ ⊢ A and Γ ⊢ P :: (a : A), respectively.As a general convention, for each typing judgment Γ ⊢ P :: (a : A), we presuppose that a b for all b:B ∈ Γ; the typing rules will maintain this invariant.(This property is also provable for all b:B ∈ Γ [see Lemma B.2].)If we did not have this well-formedness condition, there would incorrectly be two writers to address a: one implicitly as part of the writer to b, and the other being P .
To achieve (its modified form of) cut elimination, the semi-axiomatic sequent calculus also uses eligible succedents.However, because the SNAX type theory does not model the internal layout of function closures, eligible succedents do not appear in SNAX.As a consequence, cut elimination (even in modified form) will not hold for SNAX.Since we are primarily interested in operational aspects, we avoid here the technical complications required to restore it, since type preservation and progress do hold.

Weakening and contraction.
To correctly maintain the connection between an eligible antecedent and the axiom from which it derives its eligibility, some care must be taken with weakening and contraction.Ordinary antecedents and their corresponding addresses are still subject to weakening, but eligible ones may not be weakened away (or otherwise, their eligibility would fail to be derived from an axiom).Contraction for two ordinary antecedents and their corresponding addresses occurs as in SAX.Furthermore, contracting an eligible antecedent A and an ordinary antecedent A together into A is permitted: the eligibility of the resulting A will still be traceable to an axiom.But contracting two copies of a:A into one is not permitted in SNAX.Such a contraction rule would not be harmful, but neither would it be useful since no two eligible antecedents can be assigned the same address in a derivable judgment (see Lemma B.3).In this way, eligible antecedents A and their corresponding addresses a:A follow an almost The essential idea of the SNAX type theory is that, once eligibility and snips are first-class, we have the freedom to give different computational interpretations to cuts and snips.SNAX retains the cut rule from SAX but also has a distinct snip + rule.The cut rule and x P ; Q construct continue to act as in SAX, allocating memory for data of type A and then running P and Q in parallel.(The type A should be inferred or given, if SNAX is used as a source language, so that allocation can depend on the type.) But the snip + rule is different.Its P ; Q construct does not (re-)allocate memory at address a because it is an eligible address and, as such, refers to a location within a block already allocated by an earlier cut rule.Instead, it simply runs processes P and Q in parallel, with reads at address a that occur in Q blocking until that address has been written to by P .5 In the pure proof theory, there would also be a symmetric snip − rule for eligible succedents.However, as previously mentioned, SNAX ignores eligibility in succedents and therefore does not include snip − .Eligibility does not enter into the identity rule; it remains as in SAX.(Note that the id typing rule is one place where it is essential to have the presupposition on typing judgments Γ ⊢ P :: (a : A) that a b for all b:B ∈ Γ.Without it, the id rule would not be operationally sensible.) Recall from section 2 that SAX uses the construct write a a 1 , a 2 to write a pair of addresses a 1 , a 2 to address a.Because these addresses point to the data that are conceptually the components of a pair of values, the layout is very indirect.
In contrast, for SNAX, we first observe that the purely logical axiom ∧a has both antecedents A 1 and A 2 eligible (as denoted by the underlining), because both are proper subformulas that are used in an axiom.This subformula structure is then reflected in the ×a typing rule by assigning addresses aπ 1 and aπ 2 to A 1 and A 2 , respectively.Because these addresses are locally calculable from a, they are not needed in the process syntax write a , .

2-12
Data Layout from a Type-theoretic Perspective The above picture depicts a particular flat layout for SNAX pairs in which aπ 1 precedes aπ 2 .At a formal level, SNAX abstracts away from these particulars: SNAX requires only that aπ 1 and aπ 2 are calculable from a : A 1 × A 2 and that aπ 1 • p 1 = aπ 2 • p 2 for all projections p 1 and p 2 .For example, as far as SNAX is concerned, an equally correct picture could have aπ 2 preceding aπ 1 .
SNAX also tweaks the construct for reading an address a of type A 1 × A 2 .Instead of binding variables with read a ( x 1 , x 2 ⇒ P ), we now use read a ( , ⇒ P ).Bound variables are no longer needed because we know that a SNAX pair at address a will always have its components located at the relative addresses aπ 1 and aπ 2 .Logically, though, the static typing rule for reading at type A 1 × A 2 is still derived from the semi-axiomatic sequent calculus's ∧l rule.
The ×l rule demonstrates that, while eligible antecedents always correspond to addresses that are projections a•p, the converse is not true: not all address projections correspond to eligible antecedents.Here, although aπ 1 :A 1 and aπ 2 :A 2 appear in the premise of the ×l rule, the antecedents A 1 and A 2 are not eligible in the premise of the ∧l rule.
(In common layouts we considered, such as the one depicted in the above diagram, the processes write a , and read a ( , ⇒ P ) do not actually write nor read runtime information, their names notwithstanding.It would be possible to consider erasing write a , from the syntax and reducing read a ( , ⇒ P ) to P .We do not do so because it diverges from the logical foundations and complicates type checking.) Example.Because SNAX tracks eligibility explicitly, the structure of the proof of commutativity of conjunction changes: snip + and id rules are needed to mediate the ordinary A 1 and A 2 of the ∧l rule's premise and the eligible A 1 and A 2 of the ∧a axiom.The corresponding SNAX process involves address projections and explicit copying of data so that the flat layout of pairs is respected.
The rules for ⊤ in the semi-axiomatic sequent calculus do not involve eligibility -after all, ⊤ has no proper subformula -and so the SNAX process constructs and typing rules involving 1 are as in SAX.They are repeated here for convenience.
• ⊢ write a :: (a : 1) 1a Γ ⊢ P :: (c : C) Γ, a:1 ⊢ read a ( ⇒ P ) :: (c : C) 1l However, there is one operational difference: Now that SNAX provides an abstraction that supports conceptually flat layouts of pairs, we can think of data of type 1 as taking no space at runtime.This proves useful in some of the examples that will follow.
Tagged unions, type {ℓ : A ℓ } ℓ∈L .Disjunction still corresponds to a labeled sum type, {ℓ : A ℓ } ℓ∈L , for tagged unions, as in SAX.However, instead of the indirect layout of SAX, the presence of an eligible antecedent in the ∨a k rule suggests a DeYoung and Pfenning 2-13 flat layout for tagged unions in which the tag and the underlying data are laid out side-by-side.In SNAX, this is abstracted using a new form of address projection, a • k, where k is the tag.
Instead of SAX's write a k a k for writing a tagged address, SNAX uses the construct write a k .This can be seen as fixing address a k to be a•k and then eliding it because it is calculable from the address a and tag k.This process is typed by the a k rule, which corresponds to the ∨a k axiom for disjunction.Following the pattern seen for pairs, the eligible antecedent A k in the ∨a k axiom corresponds to the eligible a•k:A k in the a k typing rule.
(k ∈ {1, 2}) The SNAX construct for reading an address a of type {ℓ : A ℓ } ℓ∈L also differs slightly from its SAX counterpart.Once again, instead of binding variables x ℓ in the branches of read a (ℓ x ℓ ⇒ P ℓ ) ℓ∈L , we take advantage of knowing that a tag ℓ at address a will always have its underlying data located at a•ℓ and use the construct read a (ℓ ⇒ P ℓ ) ℓ∈L .Logically, the typing rule is still derived from the semi-axiomatic sequent calculus's ∨l rule.All of this follows the pattern seen for the type Example.We can now revisit booleans of type bool = {tt : 1, ff : 1} in the context of SNAX.Each address a:bool stores only a tag, tt or ff, and no space needs to be reserved for a•tt : 1 or a•ff : 1.A process for reading a boolean at address a and writing its negation to address b is as follows; its execution in the case that a holds tag tt is shown.The semi-axiomatic sequent calculus can include the shift proposition ↓A from adjoint logic [3,19,17].Because the semi-axiomatic sequent calculus consists of a single adjoint layer, A and ↓A are logically equivalent.From a provability perspective, this makes ↓A uninteresting, but the corresponding type, which we also write as ↓A, nevertheless has computational significance. 6s a proposition of positive polarity, ↓A follows the pattern of having its axiom correspond to a typing rule for writes at that type.From a computational standpoint, we can interpret the structure of the ↓a axiom as writing an address of type A into an address of type ↓A.In other words, ↓A is the type of pointers to data of type A.
In the proof theory, the ↓a axiom must use an eligible antecedent A in order for cut elimination to hold.However, requiring the ↓a typing rule to use an eligible address would be far too restrictive computationally -it would force a pointer at address a to point to only a specific projection of a, say a•↓.We certainly

2-14
Data Layout from a Type-theoretic Perspective want pointers to arbitrary addresses, so we allow the ↓a typing rule to use an ordinary b:A.(The ↓a typing rule is another place the well-formedness condition on typing judgments is essential.) Again following the pattern for positive propositions, the ↓l rule corresponds to the typing rule for a construct for reading at type ↓A, namely read a ( x ⇒ P ).Unlike the constructs for reading pairs and tagged values, read a ( x ⇒ P ) has a bound variable and no projection.At runtime, the address stored at address a is read; then the variable x is bound to that address, and execution continues according to process P .Using a variable, not a projection, in this rule is necessary because the pointer may refer to an arbitrary location, not just to one calculable from a.
Example.By judiciously inserting or removing ↓ shifts within a type, different layouts can be effected.As an example, we can revisit the types bool and boollist .Having only a ↓ shift in front of the recursive to boollist yields a flat layout, with pointer indirection only between list elements:

Functions, type
Unlike the data of positive types such as A 1 × A 2 , we will not model the internal layout of function closures.As previously mentioned, we therefore ignore the eligibility that appears in the semi-axiomatic sequent calculus's ⊃a axiom.For this reason, SNAX directly inherits the process constructs and static typing rules for A 1 → A 2 from SAX. Operationally, they behave as before.(Although we do not present the details in this paper, it is also possible to adapt negative conjunction from intuitionistic logic to the SNAX type theory as a lazy record type.)

Adding recursion to SNAX
Recursion is added to SNAX in the same way as for SAX: We use recursive type and process definitions, t = A and proc p (z:C) (x 1 :A 1 ) • • • (x n :A n ) = P , respectively.As in SAX, the SNAX type theory requires that these definitions are contractive.In addition, SNAX requires that all recursion in type definitions be guarded by a ↓ shift or a negative type constructor (only → in this paper), as in boollist = {nil : 1, cons : bool × ↓boollist }, for example.The unguarded type boollist = {nil : 1, cons : bool × boollist } is forbidden because storing a value of type boollist according to this unguarded definition would require an unbounded amount of space.

Extended example: Mapping a function across a linked list of booleans
We can revisit the example of mapping a function across a list of booleans in SNAX.Here we choose to use the flattest of the layouts for lists of booleans, which corresponds to a type definition for boollist that uses only the ↓ shift necessary to guard the recursion.A common idiom is for both arguments and destinations of processes to be addresses (that is, pointers), a small departure from similar code in SAX.
% "write" pair to ys • cons write ys cons ) ; % write tag cons to ys write ysp ys ))) % write pointer to ys at destination ysp After reading the pointer xsp to access xs:boollist , the SNAX version of map generally follows the pattern of the SAX map, with a few essential deviations.First, here there is only a single point at which memory is allocated: the cut indicated by the ys (• • •); syntax.Second, the projections such as xs • cons • π 1 are used to refer to memory cells within the allocated block as laid out by the type boollist .Third, because the projections are locally calculable, they can be elided from some parts of the syntax.Last, because the type now uses ysp : ↓boollist , a final write ysp ys is needed.

Details of the SNAX type theory
Types and signatures are exactly as they were in SAX, so we do not repeat the details here.
As compared to SAX, SNAX processes have one additional form: P ; Q for concurrent composition of processes P and Q that does not allocate memory.Storables S and co-storables T have slightly different forms than in SAX, owing to SNAX's elision of eligible addresses from process syntax.
Once again, we use an operational semantics based on multiset rewriting with semantic objects of the forms thread(a, P ), cell(a, ✷), and !cell(a, S) that represent running processes, empty cells, and filled cells, respectively.
Configurations C and configuration contexts Φ are the same as in SAX; once again, configuration contexts are not subject to contraction and their addresses are presumed to be distinct, an invariant that will be preserved by the configuration typing rules.Also, we will continue to write a, b, and c in configurations and configuration contexts, but these runtime addresses may not contain static variables x.
The configuration typing rules are quite similar to those of SAX, but include one twist.Unlike SNAX process contexts Γ, configuration contexts Φ do not track eligibility.To mediate the two in rules thread and cell, we therefore define a judgment Φ c Γ that holds exactly when three conditions are met: The rewriting rules for futures, writes, reads, and calls are essentially the same as in SAX, but the definition of S ⊲ T changes slightly.Because some addresses are locally calculable and elided from the syntax, substitution is no longer needed in some cases; however, substitution is still needed for the cases for pointers and functions. thread(c, where S ⊲ T is given by , ⊲ ( , Snips are the essential difference between SAX and SNAX.The rewriting rule for a snip is broadly similar to that for futures, with the key difference that an address a is used instead of choosing a fresh α.

thread(c, (P
Because the address a written by P is not made locally explicit in the snip construct P ; Q, the function dest(P ) (short for "destination") traverses the process P to extract that address.This function returns a set of addresses, but for a well-typed process P , the set will always be a singleton.The definition of dest(P ) can be found in appendix A.
Copying data must be handled differently in SNAX than in SAX.In SAX, we could simply copy a storable from one address to another; the implicit sharing would take care of a type's subformulas.In SNAX, all sharing is made explicit through the ↓ shifts, and those may or may not appear in a given type's subformulas.However, at types ↓A and A 1 → A 2 , simply copying the storable suffices.thread(a, copy a b) !cell(b, S) −→ !cell(a, S) Before a process may be executed, we require that copys at other types are expanded, using reads and writes, so that only copys at types ↓A and A 1 → A 2 remain; this is reminiscent of η-expansion.The expansion of copys is shown in appendix A.

Type safety for SNAX
SNAX satisfies type safety, in the form of type preservation and progress results.Preservation is a bit subtle, but ultimately not difficult, to prove; it relies on various lemmas surrounding eligibility, as well as the definition of Φ c Γ.

Related work
Besides the aforementioned work on the semi-axiomatic sequent calculus and SAX [6], another item of related work is Smullyan's classical sequent calculus in which cuts must be analytic and all other inference rules are replaced by axioms [20].Because all cuts are analytic, there is no direct cut elimination procedure and, consequently, the calculus does not seem to lend itself to computational interpretation.From a computational standpoint, most closely related is perhaps the work on data layout using ordered types [16].Ordered types were suitable to capture the original allocation and layout of data, but not the whole state of memory during computation since ordered logic has only a single ordered context thus cannot directly model many blocks of memory connected by pointers.The current design overcomes both of these limitations with a very different approach: our logic (and therefore the type theory) is not substructural at all.
Another point of comparison is Typed Assembly Language (TAL) [15].We view TAL as a low-level type system that can reflect high level abstractions, but it does not seem to correspond to any particular proof system for intuitionistic logic.Furthermore, while TAL by necessity works with concrete data layouts, the compilation from the λ-calculus to TAL chooses a particular one among them rather than providing a choice to the programmer.Another point of difference is that in SNAX, functions receive destinations (that is, memory locations) for their results, while in TAL they receive continuations to be called with the result.TAL also resolves some issues that we leave to future work.Among them are parametric polymorphism and representation of closures.

A Auxiliary definitions for SNAX operational semantics
The definition of dest(P ), which is used in the operational semantics of snips, is as follows.

dest(x P
Expansion of copys down to types ↓A and A 1 → A 2 is accomplished by the following function.Proof.By induction on the structure of the given derivation.The two interesting cases are as follows.

2-20
Data Layout from a Type-theoretic Perspective Proof.By induction on the structure of the given derivation, appealing to the preceding lemmas about eligibility.The most interesting case is as follows.
Case: Second, we must show that Φ a Γ 1 .
• We are given that c / ∈ dom Φ.From Lemma B.2 and the snip's second premise, we know that a ≻ c.This also implies that c = a, so we may indeed conclude that c / ∈ dom (Φ, a:A).
Fourth, we must show that Φ, a:A c Γ 2 , a:A.∈ dom Φ 0 because α is chosen to be fresh.
Proof.By induction on the structure of the given derivation.The most interesting case is as follows.

Theorem 3 . 1 (
Preservation) If Φ 0 C :: Φ and C −→ C ′ , then Φ 0 C ′ :: Φ ′ for some Φ ′ ⊇ Φ. Proof.By induction on the given derivation, using a few lemmas about eligibility; see appendix B. ✷ Theorem 3.2 (Progress) If C :: Φ, then either C is final or C −→ C ′ for some C ′ .By right-to-left induction on the structure of the given derivation; see appendix B. ✷ η(copy a b : A 1 × A 2 ) = read b ( , ⇒ η(copy (aπ 1 ) (bπ 1 ) : A 1 ); η(copy (aπ 2 ) (bπ 2 ) : A 2 ); write a , ) η(copy a b :1) = read b ( ⇒ write a ) η(copy a b : {ℓ : A ℓ } ℓ∈L ) = read b (ℓ ⇒ η(copy (a•ℓ) (b•ℓ) : A ℓ ); write a ℓ ) ℓ∈L η(copy a b : ↓A) = copy a b η(copy a b : A → B) = copy a b B SNAX Metatheorems Lemma B.1 If a ≻ b and a ≻ c, then either b c or c b. Proof.By proving by simultaneous induction on p 1 and p 2 that b • p 1 = c • p 2 implies b c or c b. ✷ Lemma B.2 If Γ, a:A ⊢ P :: (c : C), then a ≻ c.Proof.By induction on the structure of the given derivation.The two interesting cases are as follows.Case: Γ 1 , a:A ⊢ P :: (b : B) Γ 2 , b:B ⊢ Q :: (c : C) Γ 1 , Γ 2 , a:A ⊢ P ; Q :: (c : C) snip + Appealing to the inductive hypothesis on the first premise, we know that a ≻ b.Similarly, appealing to the inductive hypothesis on the second premise, we know that b ≻ c.So a ≻ c follows from transitivity.Case: Γ 1 , a:A ⊢ P :: (x : B) Γ 2 , x:B ⊢ Q :: (c : C) (x fresh) Γ 1 , Γ 2 , a:A ⊢ x P ; Q :: (c : C) cut By the inductive hypothesis on the first premise, we know that a ≻ x.However, then having a:A in the rule's conclusion contradicts the freshness of x.(The case for the →r rule is similar.)✷ Lemma B.3 If Γ, a:A, b:B ⊢ P :: (c : C), then a b and b a.

Case: Γ 1 Γ 1 ,
, a:A ⊢ P :: (c ′ : C ′ ) Γ 2 , b:B, c ′ :C ′ ⊢ Q :: (c : C) Γ 2 , a:A, b:B ⊢ P ; Q :: (c : C) snip + We must show that a = b and a ⊁ b and b ⊁ a. • Suppose that a = b.We know from the first premise above and Lemma B.2 that a ≻ c ′ .So b ≻ c ′ as well.By the inductive hypothesis on the second premise above, b c ′ , yielding a contradiction.Therefore a = b.• Suppose that a ≻ b.Once again, we know from the first premise above and Lemma B.2 that a ≻ c ′ .By Lemma B.1, either b c ′ or c ′ b.Appealing to the inductive hypothesis on the second premise above, b c ′ and c ′ b.This is a contradiction, so a ⊁ b. • Suppose that b ≻ a. Once again, we know from the first premise above and Lemma B.2 that a ≻ c ′ .So b ≻ c ′ follows by transitivity of ≻.Appealing to the inductive hypothesis on the second premise above, b c ′ and c ′ b.This is a contradiction, so b ⊁ a. Case: Γ 1 , a:A ⊢ P :: (x : C ′ ) Γ 2 , b:B, x:C ′ ⊢ Q :: (c : C) (x fresh) Γ 1 , Γ 2 , a:A, b:B ⊢ x P ; Q :: (c : C) cut By Lemma B.2 on the first premise, we know that a ≻ x.However, then having a:A in the rule's conclusion contradicts the freshness of x.(The case for the →r rule is similar.)✷ Lemma B.4 If Φ c Γ, a:A, then Φ c Γ. Proof.Assume Φ c Γ, a:A.To establish Φ c Γ, there are three parts.• Assume b:B ∈ Γ.Then b:B ∈ Γ, a:A as well.It follows from Φ c Γ, a:A that b:B ∈ Φ. • Assume that b:B ∈ Γ.Then b:B ∈ Γ, a:A as well.It follows from Φ c Γ, a:A that b:B ∈ Φ and b ≻ c. • Assume that b:B ∈ Φ and b ≻ c.It follows from Φ c Γ, a:A that either b:B ∈ Γ, a:A or b ≻ b ′ for some b ′ :B ′ ∈ Γ, a:A.Because a:A is ordinary, either b:B ∈ Γ or b ≻ b ′ for some b ′ :B ′ ∈ Γ. ✷ Theorem B.5 (Preservation) If Φ 0 C :: Φ and C −→ C ′ , then Φ 0 C ′ :: Φ ′ for some Φ ′ ⊇ Φ.

•
Assume that b:B ∈ Γ 1 .From Φ c Γ 1 , Γ 2 , we therefore know that b:B ∈ Φ (and b ≻ c).Because b:B ∈ Γ 1 , Lemma B.2 on the first premise yields b ≻ a, as required.• Assume that b:B ∈ Φ and b ≻ a. From Φ c Γ 1 , Γ 2 , we therefore know that either b:B ∈ Γ 1 , Γ 2 or b ≻ b ′ for some b ′ :B ′ ∈ Γ 1 , Γ 2 .• Suppose that b:B ∈ Γ 2 .By Lemma B.3 on the second premise, b a, which contradicts b ≻ a. • Suppose that b ≻ b ′ for some b ′ :B ′ ∈ Γ 2 .Because both b ≻ a and b ≻ b ′ , Lemma B.1 yields either a b ′ or b ′ a.However, by Lemma B.3 and the second premise, neither of these can be true.The only remaining possibility is that either b:B ∈ Γ 1 or b ≻ b ′ for some b ′ :B ′ ∈ Γ 1 , as required.
boollist = {nil : 1, cons : bool × boollist } ′ :boollist Specifically, an address xs of type boollist stores either: (a) the tag nil and an address u of type 1; or (b) proc map (ys : boollist ) (f : bool → bool ) (xs : boollist ) = read xs ( % read and branch on tag at xs nil u ⇒ copy ys xs % copy (empty) input list xs to destination ys | cons p ⇒ read p ( x, xs ′ ⇒ % read pair at p y read f x, y ; % allocate y and call f with destination y ys ′ call map ys ′ f xs ′ ;