Typed Functional Array Languages: Shapes, Uniqueness, and Parallel Compilation
Prerequisites. Direct starred prerequisites: Chapter 19 and chapter 133; chapter 31 supplies the indexed families. No later core chapter depends on this route.
A dot product takes two vectors and multiplies them componentwise before summing. In an ordinary functional language its type is
Change one feature. A
Change one more. A nested
Three obstacles, one object: a type language in which sizes are expressions. This chapter freezes the language
The frozen language
Definition 139.1 — Syntax¶
Referenced from 7 locations
Definition 139.2 — Witnessed sizes¶
Referenced from 6 locations
The witness condition is the chapter’s first non-obvious clause and it is worth saying at once what it excludes. If a value had type
Definition 139.3 — Typing¶
Subtyping
Referenced from 5 locations
Two clauses of definition 139.3 carry the design. t-app substitutes the argument into the result type, as in any dependent system. t-map does not: its side condition
Definition 139.4 — Dynamic semantics¶
Evaluation is big-step,
Dynamic size matching
Referenced from 7 locations
Remark 139.5 — What the semantics does not model¶
Definition 139.4 defines successful executions only. A failed size coercion, an out-of-bounds index, and an attempt to build an array of fewer than one element all have no rule, so they have no derivation — not a derivation producing an error. Everything proved below is therefore conditioned on the existence of a successful evaluation derivation.
Referenced from 3 locations
Value equivalence and substitution
Definition 139.6 — Value equivalence¶
Referenced from 4 locations
Two closures are equivalent when they return equivalent values on the same argument and fail on the same arguments. The second half is what makes the relation usable in a semantics that models only successful executions.
Proposition 139.7 — Substitution preserves semantics¶
If
and then with .If
and then .Conversely for both, and correspondingly for the logical relation of definition 139.11.
Referenced from 5 locations
Proof of Proposition 139.7 — Substitution preserves semantics
Proof. Clauses 1 and 2 are proved by mutual induction on the evaluation and size-checking derivations; the mutual induction is forced because d-coerce appeals to size checking and size checking appeals to evaluation in c-arr. The converses are proved by mutual induction on the structure of
Exercise 139.1¶
Give two closures that are equivalent by definition 139.6 but not syntactically identical, and show that clause 1 of proposition 139.7 would be false with equality in place of
Referenced from 2 locations
Calculating with sizes
The type language is now fixed; the following calculations expose one clause of it at a time.
Example 139.8 — Dot product¶
Take
Referenced from 4 locations
Example 139.9 — Concatenation and reshape¶
Referenced from 3 locations
Example 139.10 — Filter and the escaping size¶
Referenced from 3 locations
Exercise 139.2¶
Write a program that filters an array and then takes the length of the result, and check that it type-checks. Then write one that filters and returns the result itself from a function whose declared result type names the length, and identify the side condition of t-let that fails.
Referenced from 2 locations
Exercise 139.3¶
Delete
Referenced from 2 locations
Soundness
Definition 139.11 — The logical relation¶
Referenced from 7 locations
The array clause is where the relation stops being a syntactic predicate: it evaluates the size expression in
Proposition 139.12 — Extensibility¶
Write
Referenced from 5 locations
Proposition 139.13 — Dynamic size matching and checking¶
If
and then for some ; and conversely, if some is extracted then .If
and then .If
then .
Referenced from 7 locations
Proof of Proposition 139.13 — Dynamic size matching and checking
Proof. Clause 1 is by induction on
Proof of Theorem 139.15 — Soundness
Proof. By induction on the typing derivation, with proposition 139.14 for t-relax.
t-int, t-var. Immediate from definition 139.11 and
t-app. Inverting d-app, the function evaluates to a closure
t-map. Inverting d-map, the array evaluates to
t-let. Inverting d-let,
t-coerce. Inverting d-coerce gives
The remaining rules are componentwise. ◻
Remark 139.16 — The exact strength of thm:arr-soundness¶
The theorem quantifies over a successful evaluation: its third hypothesis is a derivation of
no progress statement — it does not say that a well-typed expression has an evaluation derivation;
no termination statement — an expression with no derivation may be diverging or failing, and the theorem does not distinguish them;
nothing about failure — a failed coercion, an out-of-bounds index and an empty-array construction all simply have no derivation, and remark 139.5 is the reason.
Adding rules that propagate dynamic errors, and then proving termination by a logical relation in the style of Tait’s normalization argument, is a separate development. Empty arrays are excluded, and admitting them requires shape information to be available dynamically wherever an array can be empty.
Referenced from 4 locations
Exercise 139.4¶
Exhibit a well-typed closed expression of
Referenced from 2 locations
System card: a production array compiler
Only now, with the proved core in hand, is it useful to look at an implementation. The following observations are about a particular compiler and are not theorems about
- Second-order array combinators.
-
The source language offers
, , and as primitives with fixed sequential meanings. Their sequential semantics is what the compiler is entitled to preserve; their parallel implementation is a choice made later. - Uniqueness and aliasing.
-
A parameter marked unique may be consumed, so its buffer can be updated in place. The analysis tracks which values may alias which, and rejects a program that uses a consumed value. This is a static discipline for in-place update in a pure language, and it is absent from
: definition 139.1 has no update and no uniqueness annotation. - Fusion and flattening.
-
Adjacent combinators are fused into one, and nested parallelism is flattened into flat parallelism. Each pass has an invariant that the compiler’s own type checker enforces. That a pass preserves that invariant is evidence of the kind discussed in chapter 133, and is not a semantic-preservation theorem.
- Generated code.
-
The back end emits code for a parallel target. The boundary between the functional meaning of the source and the behaviour of the generated program is where floating-point associativity, scheduling and hardware behaviour enter, and none of them is modelled by
. - Bounded property analysis.
-
A restricted property language can express equivalence, range, injectivity, bijectivity, monotonicity, filtering and partitioning of array-producing expressions, and a bounded automatic analysis decides properties in that grammar. It is an analysis with a stated grammar, not a verifier.
Remark 139.17 — What is not claimed¶
Nothing above asserts end-to-end compiler correctness, floating-point equivalence between source and target, race freedom in the presence of foreign code, asymptotic optimality, or correctness of the hardware. The cited language definitions and implementation studies establish none of those five statements.
Referenced from 3 locations
Comparison card: eager memoized functions over index sets
Change one design decision at a time from the proved spine.
Replace “array indexed by a size” with “eagerly memoized function over a typed finite index set”. A table has type
where is a type whose inhabitants are the legal indices. Where writes , this design writes , and the index type may be a sum or a product rather than a prefix of the integers.Replace bulk combinators with pointful nested indexing. A
becomes a comprehension over the index set, and the programmer writes the element expression rather than a function to be mapped.Add fine-grained effect rows for the operations that behave like mutation. A table built by writing its entries needs an effect; the row records which region is written.
Isolate associative accumulation as its own effect. An accumulator whose combining operation is associative may be split and recombined.
Calculate one reduction or histogram with that accumulator, showing the reordering argument for that example.
Remark 139.18 — The boundary of the comparison¶
This card uses the typed-index, effect and accumulation material of its source and nothing else. It claims no general race-freedom theorem: item 5 is a calculation about one example, licensed by associativity of that particular operation. It claims no progress or preservation theorem for the compared language, and no correctness of any of its compiler passes. The automatic differentiation of that line of work, and the separate linearization, unzipping and transposition results, are reserved for the differentiation route and are not used here. Upstream describes the implementation as an early-stage research project.
Referenced from 2 locations
Exercise 139.5¶
Express the type of
Referenced from 2 locations
Limits and seminar
The frozen source for the formal core is Bailly, Henriksen and Elsman (2023): definition 139.1, definition 139.2, definition 139.3, definition 139.4, definition 139.6, definition 139.11 are its Figures 1–7, and proposition 139.7, proposition 139.12, proposition 139.13, proposition 139.14 and theorem 139.15 are its Propositions 3.4, 3.5, 3.6–3.8, 3.9 and 3.10, at their exact statements. The 2021 precursor is used only where signatures coincide. Section 139.5 reports the implementation observations of the compiler papers, the thesis and the bounded property analysis; section 139.6 reports the typed-index, effect and accumulation design of its own source. No theorem is transferred from an implementation to
Five boundaries. Theorem 139.15 is conditioned on a successful evaluation, by remark 139.16, and is neither progress nor termination. Arrays are nonempty, and proposition 139.13 uses that. Size equality is syntactic, so example 139.9 needs a coercion with a run-time check where a solver would not. Uniqueness, in-place update, fusion, flattening and code generation are outside
[4]
Suggested first pass.
None of these problems is a prerequisite for a later chapter. Begin with exercise 139.6, then complete exercise 139.9.
Exercise 139.6¶
Derive the type of
Referenced from 3 locations
Exercise 139.7¶
t-relax may be applied at any point, so a program has many typing derivations. Show that any two derivations of the same program give types that differ only in size information, and give two derivations of one program whose types are not syntactically equal.
Referenced from 2 locations
Exercise 139.8¶
Admit empty arrays into definition 139.1. Show that clause 1 of proposition 139.13 becomes false, by exhibiting a value, a type and a witnessed variable for which no size can be extracted. Then propose the smallest change to definition 139.4 that restores it, and say what it costs at run time.
Referenced from 2 locations
Exercise 139.9 — Practical: size-dependent checker and evaluator¶
Practical project.arr-size-checker Complete project arr-size-checker. Implement, for the frozen core of definition 139.1, (i) the typing rules of definition 139.3 including t-map’s side condition, t-let’s witness condition and t-coerce, (ii) the big-step evaluator of definition 139.4 with dynamic size matching and dynamic size checking, and (iii) the witness function of definition 139.2. The invariant the implementation must maintain is theorem 139.15 on every accepted input: whenever the checker accepts
dot-product: 32
mismatched-zip: rejected
unpacked-length: 3
unwitnessed-size: rejected
map-ragged: rejected
The checker is independent evidence for the frozen core; it does not prove theorem 139.15, implements none of section 139.5 or section 139.6, and — by remark 139.16 — says nothing about programs whose evaluation fails.