Theories¶
A panproto Theory is a generalised algebraic theory: a finite
description of a data shape in terms of sorts, operations, and
equations. didactic produces one Theory per Model class.
Sorts¶
Every Model class gets a primary sort named after the class, plus one constraint sort per field:
becomes (in spec form):
sorts = [
{"name": "User", "kind": "Structural"},
{"name": "User_id", "kind": {"Val": "Str"}},
{"name": "User_email", "kind": {"Val": "Str"}},
]
The primary sort is Structural (a vertex kind); the constraint
sorts are Val[ValueKind] (a value carrier with a typed payload).
Operations¶
Each field becomes an accessor operation from the primary sort to its constraint sort:
ops = [
{"name": "id", "inputs": [["self", "User", "No"]], "output": "User_id"},
{"name": "email", "inputs": [["self", "User", "No"]], "output": "User_email"},
]
Ref[T] and Embed[T] produce operations whose output is T's
primary sort, which gives the Theory an explicit edge to the target
class.
Equations¶
Class-level axioms and annotated-types
constraints become equations on the Theory. didactic's spec-builder
collects them, panproto validates that the set is consistent, and
the resulting Theory carries the equations as first-class data.
Why use a Theory¶
A Theory is a content-addressed, language-agnostic description of a data shape. Three things follow:
- Two Models with the same Theory are interchangeable. The structural fingerprint (see Fingerprints) is computed from the Theory, so two structurally identical Models share a migration entry, share a schema URI, and produce byte-identical schema artefacts when emitted.
- A Theory can be exported to many target formats. panproto's
IoRegistryandAstParserRegistryconsume the Theory and emit Avro, OpenAPI, FHIR, Protobuf, Rust, TypeScript, etc. - Theory operations compose categorically.
colimit_theoriescomputes the pushout of two Theories over a shared sub-theory, which is whatclass B(A)does internally and what migration synthesis builds on.
When to use it directly¶
Most code never touches panproto.Theory directly. Reach for it when:
- You need to know the canonical key of a field (
spec.translation.sort). - You are writing a custom emitter and want to walk the Theory's ops and equations.
- You want to call
panproto.colimit_theoriesdirectly for a Models combination outside the inheritance graph.
Foo.__theory__ is the entry; didactic.theory.build_theory_spec(Foo)
returns the panproto-shape dict if you only need that.