sigmal-docs

Sigmal Language Specification — Part 02

Core Type System and Universes

Top > Design docs > Core design > Part 02


Sigmal is a pure, total, structurally typed language.

At its logical core, Sigmal is based on a minimal Calculus of Inductive Constructions (CIC).

Terms and types inhabit a unified dependent λ-calculus with:

Sigmal includes only the computational core of CIC. It does not include:

There is:


1. Universes

Universes are indexed by natural numbers.

$ { e }

Where:

Syntactic sugar:

$0  ≡  $ { 0 }
$1  ≡  $ { 1 }
$2  ≡  $ { 2 }

Universe equality is determined by equality of normalized Nat values.

Example:

$ { + 1 1 }  ≡  $ { 2 }

if both expressions normalize to the same Nat.

Universes are stratified:

If A : $ { n }, then:

$ { n } : $ { + n 1 }

There is no Type : Type.

There is no impredicativity.

This stratification enforces logical consistency of the minimal CIC core.


2. Dependent Functions and Abstraction

Sigmal uses a single abstraction form:

\ (x : A) -> T = B

This form represents both:

Types are ordinary terms living in universes.

If:

then:

\ (x : A) -> B : $ { max n m }

Non-dependent arrow sugar:

A -> B

is equivalent to:

\ (_ : A) -> B

2.1 Function Application

Application uses whitespace and is left-associative:

f x y    ≡    (f x) y

Parentheses are only for grouping:

f (g x)

Sigmal defines no infix operators.


3. Record Types

Record types are finite maps from symbol keys to types:

&{
  K1 : T1;
  K2 : T2;
}

Record types are:

Two record types are definitionally equal iff:

Record values:

&{
  K1 = v1;
  K2 = v2;
}

3.1 Dependent Pairs (Σ-Types) via Inductive Encoding

Record types in Sigmal are non-dependent labeled product types. Field types do not depend on other fields.

Dependent product types (Σ-types) are not primitive record types. Instead, they are expressed using inductive families in the minimal CIC core.

A dependent pair type (Σ-type) can be defined as:

Sigma =
  \ (A : $ { u })
    (B : A -> $ { v })
  -> $ { max u v }
  = #{
      Pack :
        \ (a : A)
          (b : B a)
        -> Sigma A B;
    };

Sigma A B represents a pair:

where the type of the second component depends on the first.

Introduction

A dependent pair is constructed using Pack:

Pack a b

where:

Elimination

Dependent pairs are eliminated using pattern matching:

^ p {
  Pack(a, b) => ...
}

The types of a and b are refined in the match branch:

Dependent elimination follows the general rules for inductive families (see Section 4).

Relationship to Records

Non-dependent record types:

&{
  x : A;
  y : B;
}

are equivalent to ordinary (non-dependent) product types.

Dependent pairs (Sigma) serve the role of dependent products (Σ-types) and should be used when later components depend on earlier ones.

Records remain:

Dependent pairs are a logical construct provided by the inductive core and are erased at runtime unless explicitly preserved.

Rationale

Keeping records non-dependent preserves:

All dependent data relationships are expressed via inductive families in the minimal CIC core.


This keeps the calculus:


4. Inductive Families

Inductive types may be indexed by values.

General form:

Ind =
  \ (params...)
    (indices...)
  -> $ { u }
  = #{
      C1 : T1;
      C2 : T2;
    };

Constructors may specify explicit result types.

Example (length-indexed vector):

Vec =
  \ (A : $0)
    (n : Nat)
  -> $0
  = #{
      Nil  : Vec A 0;
      Cons : \ (k : Nat) -> A -> Vec A k -> Vec A (S k);
    };

Inductive definitions must satisfy:

Two inductive families are definitionally equal iff:


4.1 Dependent Elimination

Pattern matching supports dependent elimination.

General form:

^ x : Motive {
  C1(args...) => e1;
  C2(args...) => e2;
}

Where:

When non-dependent, motive may be omitted:

^ x {
  ...
}

Pattern matching must be exhaustive.


4.2 Propositional Equality

Propositional equality is an inductive family:

Eq =
  \ (A : $0)
    (x : A)
    (y : A)
  -> $0
  = #{
      Refl : Eq A x x;
    };

No rewriting is performed automatically.

Transport across equality is defined via dependent elimination.

Equality reasoning is explicit.


5. Symbols (Sym)

Sym : $0

Symbols are structural identity atoms used as:

Symbol equality is structural.

There is no global registry.

Symbol representation is implementation-defined but must be deterministic.


6. Symbol Injection

@{ e }

Where:

Valid only in symbol-key positions.

Bare identifiers in key positions are sugar for:

@{ TextSym "identifier" }

Symbol construction utilities are provided by .std.core.


7. Const-Normalizable Expressions

An expression e is const-normalizable if:

  1. e typechecks in the pure fragment
  2. e is effect-free
  3. e terminates
  4. e reduces to a value

We write:

Γ ⊢const e ⇓ v

Const-required positions include:

Const evaluation is:

Const evaluation does not execute effect interpreters.


8. Definitional Equality

Definitional equality corresponds to conversion in minimal CIC.

Definitional equality includes:

Only const-normalizable expressions participate in definitional equality.

No symbolic rewriting is performed.

Example:

No automatic extensional reasoning is performed.


9. No Runtime Reflection into Types

Runtime values cannot influence type structure unless they appear in const-normalizable positions.

There is:

Type structure depends only on:


10. Explicit Evidence Discipline

Sigmal performs no implicit property resolution.

If a function requires a property, it must receive a witness explicitly.

The only automatic reasoning mechanism is definitional equality.

All non-definitional reasoning must be expressed via values (e.g., Eq).


11. Typeclasses

Typeclasses are ordinary record types.

There is:

Instances are explicit values.


12. Literals

Literal interpretation does not depend on implicit resolution.

Conversions must be explicit.


13. Summary

The Sigmal core type system is:

Type identity is structural and determined by normalized form.

All non-definitional properties must be passed explicitly as values.


Sigmal.org - the calculus we can build on