Structure
Structure
Theory
Dependent Pair
When we want to group 2 types together, a natural way is to use the cartesian product:
In a dependent type system, a \(\Sigma\)-Type is a generalization of the cartesian product type, written as:
This denotes a pair \(\langle x, y \rangle\) where:
- \(x : A\)
- \(y : B(x)\) — the second component depends on the first
Structure
A structure is essentially a syntactic and semantic wrapper around nested \(\Sigma\)-types (dependent pair types). Just like a continuous Cartesian product combines multiple independent types as:
the \(\Sigma\)-type generalizes this idea by allowing each type to depend on the values introduced before it. A structure captures a sequence of fields, each of which may or may not depend on the previous ones.
Suppose we have a sequence of types:
Then the structure corresponds mathematically to a nested dependent pair:
Here, the final
𝟙
(unit type) serves as a base case to terminate the nested structure, representing the “end” of the data.
Syntax
**Declare a structure **
In Arch
, struct-like dependent records are straightforward to express. To define such a structure simply list all fields in order, enclosed within curly braces {}
. Each field’s type annotation can reference any of the preceding fields:
For each field:
- Explicit typing is required — each field must specify its type, either as a concrete type or as a type variable (i.e., as a type itself). While it is technically possible to omit variable names and use anonymous types, we strongly recommend naming every field for clarity and ease of reference. If any subsequent field needs to depend on a value, naming that value becomes essential.
- Dependencies are permitted — any field may depend on any of the preceding fields in the structure. This allows you to express rich dependency relationships directly and naturally.
This approach closely mirrors dependent record types in type theory, where each field’s type can reference all previous fields, enabling strong type safety and highly expressive modeling.
Example
This define a factory that takes a type as input and outputs a VectorType.
Declare a record
After declaring a structure, we can assign values to a strcure wchich satisfies the dependent relationship, and we get a record:
Projecting Variables from a Structure
Suppose we have a structure \(S = {x_1, x_2, \cdots, x_n}\). To access (or project) a field from this structure, use the structure name followed by a dot and the field identifier:
-
Projecting a Single Field
This syntax retrieves the value of the field
x1
from structureS
. -
Projecting Multiple Fields at Once
To simultaneously extract multiple fields from a record, use the following syntax, which aligns the returned values with the specified variables:
Here, each variable on the left (
r1
,r2
,r3
, ...) will be bound to the corresponding field (x1
,x2
,x3
, ...) fromS
. This provides a convenient way to unpack several values from a record in a single statement. -
Pattern Matching
You can pattern-match arbitrary records to extract fields in the structure:
def toString: (v: SafeVector) match {
{ len, data, index, getVal } ⇒ toString len ++ toString data ++ toString index ++ toString getVal;
}
Extends
A structure can be extended from other structures using the <
operator:
This expression constructs a new anonymous structure by merging fields from structA, structB, etc. The result is:
In practice, however, we more commonly write named structure inheritance as:
This syntax is actually just syntactic sugar. It desugars into:
In other words, we treat A as a structure defined by extending B with the fields in structA. The < operator is a compositional constructor, not a special form of def.