Tricu 2.0.0
Sorry for squashing all of this but 🤷
This commit is contained in:
337
docs/view-contracts.md
Normal file
337
docs/view-contracts.md
Normal file
@@ -0,0 +1,337 @@
|
||||
# View Contracts and View Trees
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
View Contracts are the portable checking layer for Tree Calculus programs.
|
||||
|
||||
The checker does not consume detached metadata about a separate executable. Its
|
||||
canonical input is a typed, checkable tree artifact: ordinary tree data that
|
||||
contains both the executable program payloads and the view/contract structure
|
||||
needed to validate and transform them.
|
||||
|
||||
The checker consumes this artifact and returns either:
|
||||
|
||||
```text
|
||||
checked-execution artifact
|
||||
```
|
||||
|
||||
or:
|
||||
|
||||
```text
|
||||
structured diagnostic
|
||||
```
|
||||
|
||||
A checked-execution artifact is interpreted by `runChecked`. Unguarded programs
|
||||
are represented as `checkedPure rootPayload`; guarded programs contain explicit
|
||||
checked guard/bind nodes.
|
||||
|
||||
This keeps checking independent of any particular host implementation. A typed
|
||||
artifact may be produced by any frontend, compiler, hand-written generator, or
|
||||
future self-hosted `tricu` toolchain.
|
||||
|
||||
## 2. Design Principle
|
||||
|
||||
The model follows the same discipline as interaction trees.
|
||||
|
||||
Interaction trees use tagged structural envelopes with explicit executable
|
||||
payloads:
|
||||
|
||||
```tri
|
||||
io action = pair "tricuIO" (pair version action)
|
||||
pure x = pair 0 x
|
||||
bind action k = pair 1 (pair action k)
|
||||
```
|
||||
|
||||
The interpreter understands the outer structure, but it does not recursively
|
||||
mistake every subtree for interpreter metadata. A continuation `k` is an opaque
|
||||
executable tree until the interpreter reaches the `bind` step that applies it.
|
||||
|
||||
View trees use the same rule:
|
||||
|
||||
```text
|
||||
structure says how to check;
|
||||
opaque executable fields are only executed/applied by the checker at the
|
||||
appropriate step.
|
||||
```
|
||||
|
||||
This is the key distinction that allows Views to carry guards without confusing
|
||||
ordinary program trees with View metadata.
|
||||
|
||||
## 3. Views
|
||||
|
||||
A View is an extrinsic contract over an ordinary Tree Calculus value. Tree
|
||||
Calculus values do not carry native runtime types; a View describes how a value
|
||||
may be treated by the checker or by a checked boundary.
|
||||
|
||||
Core View forms:
|
||||
|
||||
```text
|
||||
Any
|
||||
Ref ref
|
||||
Fn [argView...] resultView
|
||||
List elemView
|
||||
Maybe elemView
|
||||
Pair leftView rightView
|
||||
Result errView okView
|
||||
Guarded baseView guard
|
||||
```
|
||||
|
||||
`Ref` supports both generated/numeric and symbolic references. Symbolic refs are
|
||||
preferred for user-authored views:
|
||||
|
||||
```tri
|
||||
UserId = viewRef "UserId"
|
||||
```
|
||||
|
||||
A guarded view refines a base view with an executable guard:
|
||||
|
||||
```tri
|
||||
UserId = viewGuarded (viewRef "UserId") userIdGuard
|
||||
```
|
||||
|
||||
The guard is ordinary program code. The View validator checks that the guarded
|
||||
view envelope is well-formed, and recursively validates the `baseView`, but it
|
||||
must treat the guard payload/reference as opaque executable data, not as another
|
||||
View.
|
||||
|
||||
## 4. Guards
|
||||
|
||||
Guards are ordinary `tricu` values/functions grouped with the Views they refine.
|
||||
|
||||
Example:
|
||||
|
||||
```tri
|
||||
userIdGuard = value :
|
||||
-- ordinary program that validates value
|
||||
|
||||
UserId = viewGuarded (viewRef "UserId") userIdGuard
|
||||
|
||||
loadUser id@UserId = ...
|
||||
```
|
||||
|
||||
Guards return the standard checked-runtime protocol:
|
||||
|
||||
```tri
|
||||
guardOk value
|
||||
guardFail
|
||||
```
|
||||
|
||||
Guards do not author diagnostics. The checked-exec runner owns guard failure and
|
||||
malformed-guard diagnostics using boundary context from the checked artifact.
|
||||
|
||||
Guards are injected by the checker. They are not discovered by the runtime as a
|
||||
separate metadata layer. The checking process transforms a view tree into an
|
||||
executable tree with the necessary guard applications inserted.
|
||||
|
||||
## 5. View Tree Artifact
|
||||
|
||||
The primary checker-facing artifact is a view executable term graph.
|
||||
|
||||
Conceptually:
|
||||
|
||||
```text
|
||||
ViewTree
|
||||
version
|
||||
root node id
|
||||
nodes
|
||||
```
|
||||
|
||||
Each node is tagged tree data. Nodes combine executable payloads, view claims,
|
||||
and structural relationships in one graph.
|
||||
|
||||
Representative node forms:
|
||||
|
||||
```text
|
||||
Value node view executableTree
|
||||
Apply node calleeNode argNode expectedOrInferredView
|
||||
Require node requiredView sourceNode
|
||||
External node name view
|
||||
```
|
||||
|
||||
This is not a mandatory final encoding; it is the semantic target. The important
|
||||
property is that executable trees and checking structure are carried together in
|
||||
a single portable artifact.
|
||||
|
||||
A node may contain opaque executable fields. Those fields are tree terms, but
|
||||
they are not recursively decoded as view-tree nodes or Views unless the node's
|
||||
semantics explicitly says so.
|
||||
|
||||
## 6. Checker Semantics
|
||||
|
||||
The checker is an interpreter over the view tree.
|
||||
|
||||
For each node it may:
|
||||
|
||||
1. validate the node envelope;
|
||||
2. validate Views referenced by the node;
|
||||
3. check compatibility between expected and actual Views;
|
||||
4. recursively check child nodes;
|
||||
5. inject guards required by guarded Views;
|
||||
6. produce the executable tree for that node;
|
||||
7. memoize node results by node id.
|
||||
|
||||
The root node result is a checked-execution program.
|
||||
|
||||
In abstract form:
|
||||
|
||||
```text
|
||||
checkViewTree : ViewTree -> Result CheckedExec Diagnostic
|
||||
```
|
||||
|
||||
or, in self-hosted terms:
|
||||
|
||||
```tri
|
||||
checkViewTree viewTree = ... -- ok checkedExec / err diagnostic
|
||||
```
|
||||
|
||||
## 7. Compatibility and Guard Injection
|
||||
|
||||
Structural compatibility is about Views. Guard injection is about producing the
|
||||
checked-execution tree.
|
||||
|
||||
For example, if a node is required to satisfy:
|
||||
|
||||
```tri
|
||||
viewGuarded (viewRef "UserId") userIdGuard
|
||||
```
|
||||
|
||||
then the checker verifies the underlying View relationship and emits executable
|
||||
code that applies `userIdGuard` at the appropriate checked boundary.
|
||||
|
||||
The checker, not the runtime metadata system, owns this transformation.
|
||||
|
||||
## 8. Source Annotations
|
||||
|
||||
Source annotations are one frontend syntax for producing view-tree nodes.
|
||||
|
||||
Examples:
|
||||
|
||||
```tri
|
||||
Nat = viewRef "Nat"
|
||||
Box a = viewPair (viewRef "Box") a
|
||||
|
||||
idNat x@Nat =@Nat x
|
||||
idBox x@(Box String) =@(Box String) x
|
||||
```
|
||||
|
||||
Annotations are value-level View expressions. Names such as `Nat` and `Box` are
|
||||
ordinary program values/functions that evaluate to Views.
|
||||
|
||||
A frontend that supports this syntax should lower the source into a view tree
|
||||
that contains the relevant executable terms, views, and checking structure. The
|
||||
artifact must not depend on source names or on the frontend implementation that
|
||||
produced it.
|
||||
|
||||
## 9. Contract Expressions
|
||||
|
||||
Contract-expression helpers remain useful as authoring/building tools, but they
|
||||
are not the fundamental artifact model.
|
||||
|
||||
Preferred style for expression-oriented authoring is pipeline-first:
|
||||
|
||||
```tri
|
||||
mapBoolStringUse = cFn <|
|
||||
[(viewFn [(viewBool)] viewString) (viewList viewBool)] (viewList viewString)
|
||||
|> cApply (cFn [(viewBool)] viewString)
|
||||
|> cApply (cValue (viewList viewBool))
|
||||
|> cRequire (viewList viewString)
|
||||
```
|
||||
|
||||
These helpers should be understood as convenient ways to build typed/checkable
|
||||
structure, not as a permanent replacement for view-tree artifacts.
|
||||
|
||||
## 10. Artifact Direction
|
||||
|
||||
The target direction is to make the view tree the canonical checked-program
|
||||
artifact.
|
||||
|
||||
Older split concepts remain useful internally or during development:
|
||||
|
||||
```text
|
||||
tree term
|
||||
view value
|
||||
typed-program node
|
||||
module/export manifest
|
||||
```
|
||||
|
||||
But the durable design should avoid treating contracts as detached facts about a
|
||||
separate program. The portable checker input is the checkable program itself.
|
||||
|
||||
In short:
|
||||
|
||||
```text
|
||||
Do not store code over here and contracts over there.
|
||||
Store a view tree: executable code plus the structure needed to check and guard it.
|
||||
```
|
||||
|
||||
## 11. IO Interaction Trees
|
||||
|
||||
`tricu` IO is represented as ordinary interaction-tree data:
|
||||
|
||||
```tri
|
||||
io action = pair "tricuIO" (pair version action)
|
||||
pure value = pair 0 value
|
||||
bind action k = pair 1 (pair action k)
|
||||
```
|
||||
|
||||
View Contracts do not change that representation. A checked program may produce
|
||||
an ordinary IO interaction tree, and the existing IO driver can execute it
|
||||
unchanged.
|
||||
|
||||
For source evaluation with contracts enabled, `tricu eval --io` performs an
|
||||
additional frontend instrumentation pass over visible IO continuations. When a
|
||||
continuation returns a `pure (...)` value that mentions source-annotated
|
||||
functions, the frontend lowers that pure expression into the existing portable
|
||||
checked-exec protocol before returning the next IO action.
|
||||
|
||||
This means source sugar works for practical checked IO paths such as:
|
||||
|
||||
```tri
|
||||
acceptNames xs@(NonEmptyList String) =@String "accepted"
|
||||
|
||||
main = io (bind (pure []) (xs : pure (acceptNames xs)))
|
||||
```
|
||||
|
||||
and for explicit higher-order boundaries:
|
||||
|
||||
```tri
|
||||
useHandler handler@(Fn [(NonEmptyList String)] String) xs@(List String) =@String
|
||||
handler xs
|
||||
|
||||
main = io (bind (pure []) (xs : pure (useHandler acceptNames xs)))
|
||||
```
|
||||
|
||||
The IO runtime does not perform View inference or guard injection at every step.
|
||||
The source/frontend pass constructs checked-exec boundaries once; the runtime
|
||||
only evaluates the resulting interaction tree.
|
||||
|
||||
Current limitations:
|
||||
|
||||
- This is source-visible instrumentation, not whole-program function-flow
|
||||
tracking.
|
||||
- Higher-order guarantees require explicit annotated boundaries.
|
||||
- Raw prebuilt interaction trees, imported executable artifacts, and content-store
|
||||
terms are not automatically re-instrumented unless they pass through this
|
||||
source-lowering path.
|
||||
- The IO action shape itself is only shallowly checkable unless users provide
|
||||
guarded Views for the relevant boundaries.
|
||||
- Continuation result Views are not inferred from external effects; dynamic IO
|
||||
values should cross annotated/guarded boundaries when runtime enforcement is
|
||||
required.
|
||||
|
||||
Making IO checking more complete is future work. In particular, a future design
|
||||
may validate every continuation-produced action structurally, carry checked
|
||||
wrappers with higher-order function values, or define a portable checked-IO
|
||||
artifact instead of relying on Haskell/frontend source instrumentation.
|
||||
|
||||
## 12. Host Independence
|
||||
|
||||
No part of the core View Tree design is specific to Haskell or to the current implementation.
|
||||
|
||||
Any producer may emit a view-tree artifact if it follows the portable tree-data
|
||||
encoding. Any checker implementation may consume it if it implements the typed
|
||||
node semantics.
|
||||
|
||||
The current implementation can produce and consume these artifacts, but it is
|
||||
not the semantic authority. The artifact format and the self-hosted checker
|
||||
semantics are the authority.
|
||||
Reference in New Issue
Block a user