Tricu 2.0.0
Sorry for squashing all of this but 🤷
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
!import "../lib/prelude.tri" !Local
|
||||
!import "prelude" !Local
|
||||
|
||||
main = lambdaEqualsTC
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
!import "../lib/prelude.tri" !Local
|
||||
!import "../lib/io.tri" !Local
|
||||
!import "prelude" !Local
|
||||
!import "io" !Local
|
||||
|
||||
-- Interaction Tree Effect Runtime
|
||||
--
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
!import "../../lib/io.tri" !Local
|
||||
!import "../../lib/arboricx/server.tri" !Local
|
||||
!import "base" !Local
|
||||
!import "io" !Local
|
||||
!import "arboricx.server" !Local
|
||||
|
||||
-- Arboricx HTTP registry server demo.
|
||||
-- Run with --allow-write ./store --allow-read ./store
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
!import "../../lib/base.tri" !Local
|
||||
!import "../../lib/io.tri" !Local
|
||||
!import "../../lib/socket.tri" !Local
|
||||
!import "prelude" !Local
|
||||
!import "io" !Local
|
||||
!import "socket" !Local
|
||||
|
||||
-- Main accept+echo loop. Recursion via y.
|
||||
echoLoop = y (self : server :
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
!import "../../lib/base.tri" !Local
|
||||
!import "../../lib/list.tri" !Local
|
||||
!import "../../lib/io.tri" !Local
|
||||
!import "base" !Local
|
||||
!import "list" !Local
|
||||
!import "io" !Local
|
||||
|
||||
-- Environment effects: ask and local.
|
||||
-- ask reads the current environment value.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
!import "../../lib/base.tri" !Local
|
||||
!import "../../lib/list.tri" !Local
|
||||
!import "../../lib/io.tri" !Local
|
||||
!import "base" !Local
|
||||
!import "list" !Local
|
||||
!import "io" !Local
|
||||
|
||||
-- Basic fork and await.
|
||||
-- fork spawns a concurrent task and returns a handle.
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
-- 3. You see:
|
||||
-- Hello, <name>!
|
||||
|
||||
!import "../lib/io.tri" !Local
|
||||
!import "prelude" !Local
|
||||
!import "io" !Local
|
||||
|
||||
main = io <|
|
||||
bind (fork getLine) (h :
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
!import "../../lib/base.tri" !Local
|
||||
!import "../../lib/list.tri" !Local
|
||||
!import "../../lib/io.tri" !Local
|
||||
!import "base" !Local
|
||||
!import "list" !Local
|
||||
!import "io" !Local
|
||||
|
||||
-- Greet and return a pure value.
|
||||
-- putStrLn writes to stdout; pure lifts "done" into IO.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
!import "../lib/prelude.tri" !Local
|
||||
!import "../lib/io.tri" !Local
|
||||
!import "../lib/socket.tri" !Local
|
||||
!import "../lib/http.tri" !Local
|
||||
!import "prelude" !Local
|
||||
!import "io" !Local
|
||||
!import "socket" !Local
|
||||
!import "http" !Local
|
||||
|
||||
myRouter = (method path headers body :
|
||||
matchBool
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
!import "../../lib/base.tri" !Local
|
||||
!import "../../lib/list.tri" !Local
|
||||
!import "../../lib/io.tri" !Local
|
||||
!import "base" !Local
|
||||
!import "list" !Local
|
||||
!import "io" !Local
|
||||
|
||||
-- readFile returns a Result. matchResult branches on ok / err.
|
||||
-- Run with --allow-read PATH or --unsafe-io.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
!import "../../lib/base.tri" !Local
|
||||
!import "../../lib/list.tri" !Local
|
||||
!import "../../lib/io.tri" !Local
|
||||
!import "base" !Local
|
||||
!import "list" !Local
|
||||
!import "io" !Local
|
||||
|
||||
-- Transform an IO result.
|
||||
-- mapIO applies a pure function to the value produced by an action.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
!import "../../lib/base.tri" !Local
|
||||
!import "../../lib/list.tri" !Local
|
||||
!import "../../lib/io.tri" !Local
|
||||
!import "base" !Local
|
||||
!import "list" !Local
|
||||
!import "io" !Local
|
||||
|
||||
-- Mutable state via get and put.
|
||||
-- get reads the current state.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
!import "../../lib/base.tri" !Local
|
||||
!import "../../lib/list.tri" !Local
|
||||
!import "../../lib/io.tri" !Local
|
||||
!import "base" !Local
|
||||
!import "list" !Local
|
||||
!import "io" !Local
|
||||
|
||||
-- Write a file, then read it back.
|
||||
-- thenIO discards the writeFile Result and continues.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
!import "../../lib/base.tri" !Local
|
||||
!import "../../lib/list.tri" !Local
|
||||
!import "../../lib/io.tri" !Local
|
||||
!import "base" !Local
|
||||
!import "list" !Local
|
||||
!import "io" !Local
|
||||
|
||||
-- Cooperative scheduling with yield.
|
||||
-- yield returns control to the scheduler so other tasks can run.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
!import "../lib/prelude.tri" !Local
|
||||
!import "prelude" !Local
|
||||
|
||||
main = exampleTwo
|
||||
-- Level Order Traversal of a labelled binary tree
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
!import "../lib/patterns.tri" !Local
|
||||
!import "patterns" !Local
|
||||
|
||||
-- We can do conditional pattern matching by providing a list of lists, where
|
||||
-- each sublist contains a boolean expression and a function to return if said
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
!import "../lib/prelude.tri" !Local
|
||||
!import "../lib/io.tri" !Local
|
||||
!import "../lib/arboricx/arboricx.tri" !Local
|
||||
!import "prelude" !Local
|
||||
!import "io" !Local
|
||||
!import "arboricx" !Local
|
||||
|
||||
-- Read an Arboricx bundle from disk and execute it.
|
||||
-- This demo loads test/fixtures/id.arboricx and applies the
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
!import "../lib/prelude.tri" !Local
|
||||
!import "prelude" !Local
|
||||
|
||||
main = size size
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
!import "../lib/prelude.tri" !Local
|
||||
!import "prelude" !Local
|
||||
|
||||
main = toSource not?
|
||||
-- Thanks to intensionality, we can inspect the structure of a given value
|
||||
|
||||
190
demos/viewContracts.tri
Normal file
190
demos/viewContracts.tri
Normal file
@@ -0,0 +1,190 @@
|
||||
!import "prelude" !Local
|
||||
!import "view" !Local
|
||||
|
||||
-- ============================================================================
|
||||
-- View Contracts in tricu
|
||||
-- ============================================================================
|
||||
--
|
||||
-- Verify this guide passes checking with:
|
||||
--
|
||||
-- tricu check demos/viewContracts.tri
|
||||
--
|
||||
-- Expected output:
|
||||
--
|
||||
-- ok
|
||||
--
|
||||
-- This file uses tricu syntax sugar. The lower-level portable View Tree
|
||||
-- form is shown in demos/viewContracts/complete.tri.
|
||||
|
||||
-- ============================================================================
|
||||
-- 1. What's the problem?
|
||||
-- ============================================================================
|
||||
--
|
||||
-- Programs grow by connecting definitions. A common mistake is connecting a
|
||||
-- value with one shape to code that expects another shape:
|
||||
--
|
||||
-- a function expects Bool, but receives String
|
||||
-- a function returns String, but its caller expects Bool
|
||||
-- a list is expected to contain bytes, but contains strings
|
||||
--
|
||||
-- In a large program, those mistakes are often far away from where the bad value
|
||||
-- was first introduced. View Contracts give tricu a portable way to check those
|
||||
-- boundaries.
|
||||
|
||||
-- ============================================================================
|
||||
-- 2. Views: useful built-in shapes
|
||||
-- ============================================================================
|
||||
--
|
||||
-- A View is a description of the shape we expect at a boundary. tricu includes
|
||||
-- built-in Views for common shapes such as:
|
||||
--
|
||||
-- Bool
|
||||
-- String
|
||||
-- Byte
|
||||
-- Unit
|
||||
-- List View
|
||||
-- Maybe View
|
||||
-- Pair View1 View2
|
||||
-- Fn [View1] View2
|
||||
--
|
||||
-- tricu has unconventional but intuitive sugar for annotations:
|
||||
--
|
||||
-- name =@View value
|
||||
-- function argument@View =@ResultView body
|
||||
--
|
||||
-- These examples are ordinary checked source definitions.
|
||||
|
||||
message =@String "hello"
|
||||
|
||||
names =@(List String) [("Ada") ("Grace")]
|
||||
|
||||
chooseFirst left@String right@String =@String left
|
||||
|
||||
stringIdentity =@(Fn [String] String) (x : x)
|
||||
|
||||
-- Uncommenting the below definition demonstrates a plain View mismatch:
|
||||
--
|
||||
-- bad =@Bool "not a Bool"
|
||||
--
|
||||
-- `tricu check` reports that the value is known as String where Bool was
|
||||
-- required.
|
||||
|
||||
-- ============================================================================
|
||||
-- 3. Why don't you just have Types?
|
||||
-- ============================================================================
|
||||
--
|
||||
-- tricu is built on Tree Calculus. A defining feature of Tree Calculus is
|
||||
-- intensionality: programs can inspect and construct program-shaped trees directly.
|
||||
-- That intensional power is useful, but it makes ordinary sound static typing a
|
||||
-- hard fit. A value can be both data and executable structure, and code can make
|
||||
-- decisions based on tree shape in ways a conventional type checker may not be
|
||||
-- able to predict soundly. This is an area of active research, not a settled
|
||||
-- claim that Tree Calculus languages cannot ever have useful typed variants.
|
||||
--
|
||||
-- View Contracts are not advertised as "the type system for tricu". They are
|
||||
-- a practical contract layer: portable metadata plus checker/runtime boundaries
|
||||
-- that catch many real mistakes while leaving the underlying language intact.
|
||||
|
||||
-- For more information about sound typing for Tree Calculus:
|
||||
-- https://github.com/barry-jay-personal/typed_tree_calculus
|
||||
|
||||
-- ============================================================================
|
||||
-- 4. What are the Contracts about, then?
|
||||
-- ============================================================================
|
||||
--
|
||||
-- `List String` tells us that every element is a String. It does not tell us the
|
||||
-- list has at least one element.
|
||||
--
|
||||
-- That matters for functions like `head`. Calling `head` on an empty list is a
|
||||
-- bug. We want to express the stronger requirement:
|
||||
--
|
||||
-- this is a List String, and it is non-empty
|
||||
--
|
||||
-- That is what a guarded View is for.
|
||||
|
||||
-- A guard is ordinary tricu code. It receives the runtime value and returns:
|
||||
--
|
||||
-- guardOk value -- accept the value
|
||||
-- guardFail -- reject the boundary
|
||||
--
|
||||
-- The guard does not write diagnostics. The checked runner reports where the
|
||||
-- failing boundary came from.
|
||||
|
||||
requireNonEmpty = (xs :
|
||||
lazyBool
|
||||
(_ : guardFail)
|
||||
(_ : guardOk xs)
|
||||
(emptyList? xs))
|
||||
|
||||
-- A user-defined View can be parameterized just like an ordinary function.
|
||||
--
|
||||
-- NonEmptyList String
|
||||
--
|
||||
-- means "a List String guarded by requireNonEmpty".
|
||||
|
||||
NonEmptyList elem = viewGuarded (viewList elem) requireNonEmpty
|
||||
|
||||
-- ============================================================================
|
||||
-- 5. Using a custom View in normal annotations
|
||||
-- ============================================================================
|
||||
--
|
||||
-- This value satisfies the custom contract.
|
||||
|
||||
contributors =@(NonEmptyList String) [("Ada") ("Grace")]
|
||||
|
||||
-- This function requires NonEmptyList String before its body can run. In a
|
||||
-- library, this is the kind of contract you would put on an operation like
|
||||
-- `head`: callers must prove the list is non-empty first.
|
||||
|
||||
acceptNames xs@(NonEmptyList String) =@String "accepted non-empty names"
|
||||
|
||||
primaryContributor =@String acceptNames contributors
|
||||
|
||||
-- Uncommenting this definition demonstrates a guarded View failure:
|
||||
--
|
||||
-- nobody =@(NonEmptyList String) []
|
||||
--
|
||||
-- The structure is fine (`[]` is a List String), but the runtime guard rejects
|
||||
-- it because the list is empty.
|
||||
|
||||
-- ============================================================================
|
||||
-- 6. Contracts protect callers too
|
||||
-- ============================================================================
|
||||
--
|
||||
-- Contracts can describe function results as well as arguments. If a function
|
||||
-- promises to return `NonEmptyList String`, checked execution guards that result
|
||||
-- before callers depend on it.
|
||||
|
||||
mkContributors name@String =@(NonEmptyList String) [(name)]
|
||||
|
||||
fromSingleName =@String acceptNames (mkContributors "Evelyn")
|
||||
|
||||
-- Uncommenting this version would fail because the result contract is too
|
||||
-- strong for the implementation:
|
||||
--
|
||||
-- badContributors name@String =@(NonEmptyList String) []
|
||||
|
||||
-- ============================================================================
|
||||
-- 7. Writing your own Views and Contracts
|
||||
-- ============================================================================
|
||||
--
|
||||
-- The pattern is:
|
||||
--
|
||||
-- 1. Start with the closest structural View.
|
||||
-- 2. Write a guard for the runtime fact the structure cannot express.
|
||||
-- 3. Package them with viewGuarded.
|
||||
-- 4. Use the new View in normal annotations.
|
||||
--
|
||||
-- Examples of useful guarded Views:
|
||||
--
|
||||
-- NonEmptyList String
|
||||
-- SortedList Byte
|
||||
-- FixedLengthBytes 32
|
||||
-- ValidUserId
|
||||
-- NonEmptyString
|
||||
--
|
||||
-- Guards are intentionally runtime checks. Use plain Views for ordinary shape
|
||||
-- checking, and guarded Views when a boundary really must enforce a stronger
|
||||
-- invariant.
|
||||
|
||||
main =@String primaryContributor
|
||||
137
demos/viewContracts/README.md
Normal file
137
demos/viewContracts/README.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# View Contract Demos
|
||||
|
||||
These demos exercise the finalized View Contract stack in `lib/view.tri`:
|
||||
portable View Trees/checkable typed-program nodes, structural View flow checks,
|
||||
runtime guarded Views, checked-exec, source annotations, and module-boundary
|
||||
View metadata.
|
||||
|
||||
## End-user guide
|
||||
|
||||
Start here. `demos/viewContracts.tri` is written with normal source annotation
|
||||
sugar and reads as a short guide to View Contracts: motivating structural
|
||||
mismatches, explaining plain Views, noting why this is not a full static type
|
||||
system, and building a custom `NonEmptyList` guarded View.
|
||||
|
||||
```bash
|
||||
tricu check demos/viewContracts.tri
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```text
|
||||
ok
|
||||
```
|
||||
|
||||
## Complete explicit demo
|
||||
|
||||
`demos/viewContracts/complete.tri` shows the same layer from the portable
|
||||
View Tree/checkable-program side. It uses explicit builders such as
|
||||
`typedValue`, `typedRequire`, and `typedApply`, and demonstrates contextual guard
|
||||
diagnostics, observation composition, reachability, and malformed guard output.
|
||||
|
||||
```bash
|
||||
tricu eval demos/viewContracts/complete.tri -f decode
|
||||
```
|
||||
|
||||
## Portable checker self-tests
|
||||
|
||||
Runs the checker self-test suite carried as ordinary `tricu` code.
|
||||
|
||||
```bash
|
||||
tricu eval demos/viewContracts/selfTests.tri -f decode
|
||||
```
|
||||
|
||||
Expected output is a list of `"ok"` strings.
|
||||
|
||||
## Diagnostic rendering
|
||||
|
||||
Shows a strict-mode structural View failure rendered for humans.
|
||||
|
||||
```bash
|
||||
tricu eval demos/viewContracts/diagnostic.tri -f decode
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```text
|
||||
"symbol 162 expected List Bool but got List String"
|
||||
```
|
||||
|
||||
## Stdlib-shaped contracts
|
||||
|
||||
Checks successful higher-order contracts shaped like common stdlib APIs.
|
||||
|
||||
```bash
|
||||
tricu eval demos/viewContracts/stdlibContracts.tri -f decode
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```text
|
||||
["ok", "ok", "ok", "ok", "ok"]
|
||||
```
|
||||
|
||||
These examples are structural View checks, not runtime guarded checks.
|
||||
|
||||
## Frontend emission layer
|
||||
|
||||
`frontendEmission/` documents the portable artifact shape a frontend can emit
|
||||
after parsing/elaboration. The `*.source.txt` files are pseudo-source; the
|
||||
matching `*.emitted.tri` files are explicit typed-program builder output.
|
||||
|
||||
This layer is still instructive because it shows the exact bridge between source
|
||||
syntax and portable View Tree/checkable metadata.
|
||||
|
||||
## Source syntax sugar
|
||||
|
||||
The `sourceSyntax/` demos use ergonomic annotations and the `tricu check`
|
||||
frontend. The frontend lowers annotations to the same typed-program nodes used by
|
||||
the explicit demos above, then executes checked-exec so guarded annotations fail
|
||||
through the portable runner.
|
||||
|
||||
Successful check:
|
||||
|
||||
```bash
|
||||
tricu check demos/viewContracts/sourceSyntax/success.tri
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```text
|
||||
ok
|
||||
```
|
||||
|
||||
Labeled diagnostic check:
|
||||
|
||||
```bash
|
||||
tricu check demos/viewContracts/sourceSyntax/failure.tri
|
||||
```
|
||||
|
||||
Expected first failing diagnostic:
|
||||
|
||||
```text
|
||||
symbol 4 (x) expected Bool but got String
|
||||
```
|
||||
|
||||
If the first definition is fixed or removed, the later application-result
|
||||
failure demonstrates callee-aware labels:
|
||||
|
||||
```text
|
||||
symbol 3 (g application result) expected String but got Bool
|
||||
```
|
||||
|
||||
## Module boundary layer
|
||||
|
||||
`modules/` shows producer-checked module export Views flowing into a consumer
|
||||
check as module-boundary evidence. During auto-build, annotated exports are
|
||||
checked before the module manifest alias is published. Consumers then use the
|
||||
manifest's View Contract metadata as assumptions, while compatibility is still
|
||||
judged by `lib/view.tri`.
|
||||
|
||||
```bash
|
||||
tricu check demos/viewContracts/modules/success.tri
|
||||
# ok
|
||||
|
||||
tricu check demos/viewContracts/modules/failure.tri
|
||||
# symbol 3 (Util.toString application result) expected Bool but got String
|
||||
```
|
||||
119
demos/viewContracts/complete.tri
Normal file
119
demos/viewContracts/complete.tri
Normal file
@@ -0,0 +1,119 @@
|
||||
!import "prelude" !Local
|
||||
!import "view" !Local
|
||||
|
||||
-- Complete explicit View Contract demo.
|
||||
-- Run with: tricu eval demos/viewContracts/complete.tri -f decode
|
||||
--
|
||||
-- This file uses the low-level portable typed-program builders directly. It is
|
||||
-- useful for understanding what source annotations lower to. For the end-user
|
||||
-- guide, see demos/viewContracts.tri.
|
||||
|
||||
requireNonEmpty = (xs :
|
||||
lazyBool
|
||||
(_ : guardFail)
|
||||
(_ : guardOk xs)
|
||||
(emptyList? xs))
|
||||
|
||||
NonEmptyList = (elemView :
|
||||
viewGuarded (viewList elemView) requireNonEmpty)
|
||||
|
||||
checkedResult = (result :
|
||||
matchResult
|
||||
(diag env : renderDiagnostic diag)
|
||||
(exec env :
|
||||
matchResult
|
||||
(runtimeDiag runtimeEnv : renderDiagnostic runtimeDiag)
|
||||
(value runtimeEnv : value)
|
||||
(runChecked exec))
|
||||
result)
|
||||
|
||||
checkedContract = (program :
|
||||
checkedResult (checkTypedProgramWith policyStrict program))
|
||||
|
||||
plainViewFailure =
|
||||
matchResult
|
||||
(diag env : renderDiagnostic diag)
|
||||
(exec env : "unexpected-ok")
|
||||
(checkTypedProgramWith
|
||||
policyStrict
|
||||
(typedProgram
|
||||
0
|
||||
[(typedValue 0 (viewList viewString) [("Ada")])
|
||||
(typedRequire 0 (viewList viewBool) t)]))
|
||||
|
||||
nonEmptyRootSuccess =
|
||||
matchBool
|
||||
"ok"
|
||||
"unexpected-value"
|
||||
(equal?
|
||||
(checkedContract
|
||||
(typedProgram
|
||||
0
|
||||
[(typedValue 0 (NonEmptyList viewString) [("Ada") ("Grace")])]))
|
||||
[("Ada") ("Grace")])
|
||||
|
||||
nonEmptyRootFailure =
|
||||
checkedContract
|
||||
(typedProgram
|
||||
0
|
||||
[(typedValue 0 (viewList viewString) [])
|
||||
(typedRequire 0 (NonEmptyList viewString) [])])
|
||||
|
||||
firstNameSuccess =
|
||||
checkedContract
|
||||
(typedProgram
|
||||
2
|
||||
[(typedValue 0 (viewFn [(NonEmptyList viewString)] viewString) (xs : head xs))
|
||||
(typedValue 1 (viewList viewString) [("Ada") ("Grace")])
|
||||
(typedApply 2 0 1 "Ada")
|
||||
(typedRequire 2 viewString "Ada")])
|
||||
|
||||
firstNameFailure =
|
||||
checkedContract
|
||||
(typedProgram
|
||||
2
|
||||
[(typedValue 0 (viewFn [(NonEmptyList viewString)] viewString) (xs : head xs))
|
||||
(typedValue 1 (viewList viewString) [])
|
||||
(typedApply 2 0 1 t)
|
||||
(typedRequire 2 viewString t)])
|
||||
|
||||
resultGuardFailure =
|
||||
checkedContract
|
||||
(typedProgram
|
||||
2
|
||||
[(typedValue 0 (viewFn [(viewString)] (NonEmptyList viewString)) (name : []))
|
||||
(typedValue 1 viewString "Ada")
|
||||
(typedApply 2 0 1 [])])
|
||||
|
||||
observationComposition =
|
||||
checkedContract
|
||||
(typedProgram
|
||||
0
|
||||
[(typedValue 0 viewString "Ada")
|
||||
(typedRequire 0 (viewGuarded viewString (x : guardOk (append x " Lovelace"))) "Ada")
|
||||
(typedRequire 0 (viewGuarded viewString (x : guardOk (append x "!"))) "Ada")])
|
||||
|
||||
unreachableGuard =
|
||||
checkedContract
|
||||
(typedProgram
|
||||
0
|
||||
[(typedValue 0 viewString "only the root is checked")
|
||||
(typedValue 1 (viewList viewString) [])
|
||||
(typedRequire 1 (NonEmptyList viewString) [])])
|
||||
|
||||
malformedGuard =
|
||||
checkedContract
|
||||
(typedProgram
|
||||
0
|
||||
[(typedValue 0 (viewGuarded viewString (x : record 99 t)) "bad guard")])
|
||||
|
||||
main = [
|
||||
(append "plain View structural failure: " plainViewFailure)
|
||||
(append "NonEmptyList root success: " nonEmptyRootSuccess)
|
||||
(append "NonEmptyList root failure: " nonEmptyRootFailure)
|
||||
(append "NonEmptyList function argument success: " firstNameSuccess)
|
||||
(append "NonEmptyList function argument failure: " firstNameFailure)
|
||||
(append "NonEmptyList function result failure: " resultGuardFailure)
|
||||
(append "guard observations compose: " observationComposition)
|
||||
(append "unreachable guard does not run: " unreachableGuard)
|
||||
(append "malformed guard result: " malformedGuard)]
|
||||
9
demos/viewContracts/diagnostic.tri
Normal file
9
demos/viewContracts/diagnostic.tri
Normal file
@@ -0,0 +1,9 @@
|
||||
!import "prelude" !Local
|
||||
!import "view" !Local
|
||||
!import "views.catalog" !Local
|
||||
|
||||
main =
|
||||
matchResult
|
||||
(diag env : renderDiagnostic diag)
|
||||
(env rest : "ok")
|
||||
(checkTypedProgramWith policyStrict listMapWrongListArgContract)
|
||||
116
demos/viewContracts/frontendEmission/README.md
Normal file
116
demos/viewContracts/frontendEmission/README.md
Normal file
@@ -0,0 +1,116 @@
|
||||
# Frontend Emission Demos
|
||||
|
||||
These examples show the layer between source-level View annotations and the
|
||||
portable View Contract checker.
|
||||
|
||||
Each `*.source.txt` file is pseudo-source: it is not parsed by `tricu`. It shows
|
||||
the information a frontend has after parsing/elaboration.
|
||||
|
||||
Each matching `*.emitted.tri` file shows the lowered typed-program metadata that
|
||||
a frontend can emit today. A successful check returns checked-exec; these demos
|
||||
focus on structural Views, so they report `"ok"` as soon as metadata checking
|
||||
succeeds. Guarded programs should run the returned checked-exec with
|
||||
`runChecked`, as shown in `demos/viewContracts.tri` and by `tricu check`.
|
||||
|
||||
## Successful map use
|
||||
|
||||
Pseudo-source:
|
||||
|
||||
```text
|
||||
map : Fn [Fn [Bool] String, List Bool] (List String)
|
||||
f : Fn [Bool] String
|
||||
xs : List Bool
|
||||
|
||||
partial = map f
|
||||
out = partial xs
|
||||
|
||||
require out : List String
|
||||
```
|
||||
|
||||
Run the emitted artifact:
|
||||
|
||||
```bash
|
||||
tricu eval demos/viewContracts/frontendEmission/map-success.emitted.tri -f decode
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```text
|
||||
"ok"
|
||||
```
|
||||
|
||||
## Wrong list argument
|
||||
|
||||
Pseudo-source:
|
||||
|
||||
```text
|
||||
map : Fn [Fn [Bool] String, List Bool] (List String)
|
||||
f : Fn [Bool] String
|
||||
xs : List String
|
||||
|
||||
partial = map f
|
||||
out = partial xs
|
||||
```
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
tricu eval demos/viewContracts/frontendEmission/map-wrong-list.emitted.tri -f decode
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```text
|
||||
"symbol 162 expected List Bool but got List String"
|
||||
```
|
||||
|
||||
## Wrong filter predicate
|
||||
|
||||
Pseudo-source:
|
||||
|
||||
```text
|
||||
filter : Fn [Fn [Bool] Bool, List Bool] (List Bool)
|
||||
pred : Fn [Bool] String
|
||||
xs : List Bool
|
||||
|
||||
partial = filter pred
|
||||
out = partial xs
|
||||
```
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
tricu eval demos/viewContracts/frontendEmission/filter-wrong-predicate.emitted.tri -f decode
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```text
|
||||
"symbol 181 expected Fn [Bool] Bool but got Fn [Bool] String"
|
||||
```
|
||||
|
||||
## Lowering shape
|
||||
|
||||
A frontend does not need to expose `tricu` syntax internally. It only needs to
|
||||
emit portable typed-program nodes:
|
||||
|
||||
```text
|
||||
typedValue symbol view term
|
||||
typedApply out callee arg term
|
||||
typedRequire symbol view term
|
||||
```
|
||||
|
||||
The source-level flow:
|
||||
|
||||
```text
|
||||
out = map f xs
|
||||
```
|
||||
|
||||
lowers to curried Tree Calculus application nodes:
|
||||
|
||||
```text
|
||||
typedApply partial map f partialTerm
|
||||
typedApply out partial xs outTerm
|
||||
```
|
||||
|
||||
Function Views drive argument checking and result inference.
|
||||
@@ -0,0 +1,17 @@
|
||||
!import "prelude" !Local
|
||||
!import "view" !Local
|
||||
!import "views.catalog" !Local
|
||||
|
||||
-- Lowering of filter-wrong-predicate.source.txt to portable typed-program metadata.
|
||||
-- Symbols:
|
||||
-- 180 filter
|
||||
-- 181 pred
|
||||
-- 182 partial
|
||||
|
||||
program = listFilterWrongPredicateContract
|
||||
|
||||
main =
|
||||
matchResult
|
||||
(diag env : renderDiagnostic diag)
|
||||
(env rest : "unexpected-ok")
|
||||
(checkTypedProgramWith policyStrict program)
|
||||
20
demos/viewContracts/frontendEmission/map-success.emitted.tri
Normal file
20
demos/viewContracts/frontendEmission/map-success.emitted.tri
Normal file
@@ -0,0 +1,20 @@
|
||||
!import "prelude" !Local
|
||||
!import "view" !Local
|
||||
!import "views.catalog" !Local
|
||||
|
||||
-- Lowering of map-success.source.txt to portable typed-program metadata.
|
||||
-- Symbols:
|
||||
-- 100 map
|
||||
-- 101 f
|
||||
-- 102 xs
|
||||
-- 103 partial
|
||||
-- 104 out
|
||||
|
||||
program =
|
||||
listMapUseContract viewBool viewString 100 101 102 103 104
|
||||
|
||||
main =
|
||||
matchResult
|
||||
(diag env : renderDiagnostic diag)
|
||||
(env rest : "ok")
|
||||
(checkTypedProgramWith policyStrict program)
|
||||
@@ -0,0 +1,19 @@
|
||||
!import "prelude" !Local
|
||||
!import "view" !Local
|
||||
!import "views.catalog" !Local
|
||||
|
||||
-- Lowering of map-wrong-list.source.txt to portable typed-program metadata.
|
||||
-- Symbols:
|
||||
-- 160 map
|
||||
-- 161 f
|
||||
-- 162 xs
|
||||
-- 163 partial
|
||||
-- 164 out
|
||||
|
||||
program = listMapWrongListArgContract
|
||||
|
||||
main =
|
||||
matchResult
|
||||
(diag env : renderDiagnostic diag)
|
||||
(env rest : "unexpected-ok")
|
||||
(checkTypedProgramWith policyStrict program)
|
||||
30
demos/viewContracts/io-continuation.tri
Normal file
30
demos/viewContracts/io-continuation.tri
Normal file
@@ -0,0 +1,30 @@
|
||||
!import "prelude" !Local
|
||||
!import "io" !Local
|
||||
!import "view" !Local
|
||||
|
||||
-- View Contracts inside IO continuations
|
||||
-- Run with:
|
||||
--
|
||||
-- tricu eval demos/viewContracts/io-continuation.tri --io -f decode
|
||||
--
|
||||
-- Checked IO evaluation instruments continuation bodies once from source
|
||||
-- annotations. The IO runtime still executes ordinary interaction-tree actions;
|
||||
-- the returned continuations already contain the checked-exec guard boundaries.
|
||||
|
||||
requireNonEmpty = (xs :
|
||||
lazyBool
|
||||
(_ : guardFail)
|
||||
(_ : guardOk xs)
|
||||
(emptyList? xs))
|
||||
|
||||
NonEmptyList elem = viewGuarded (viewList elem) requireNonEmpty
|
||||
|
||||
acceptNames xs@(NonEmptyList String) =@String "accepted"
|
||||
|
||||
useHandler handler@(Fn [(NonEmptyList String)] String) xs@(List String) =@String
|
||||
handler xs
|
||||
|
||||
-- The IO action yields an empty list. The higher-order boundary requires a
|
||||
-- handler that accepts NonEmptyList String, so the continuation-internal pure
|
||||
-- call fails before returning the next IO value.
|
||||
main = io (bind (pure []) (xs : pure (useHandler acceptNames xs)))
|
||||
51
demos/viewContracts/io.tri
Normal file
51
demos/viewContracts/io.tri
Normal file
@@ -0,0 +1,51 @@
|
||||
!import "prelude" !Local
|
||||
!import "io" !Local
|
||||
!import "view" !Local
|
||||
|
||||
-- View Contracts + IO interaction trees
|
||||
-- Run with:
|
||||
--
|
||||
-- tricu eval demos/viewContracts/io.tri --io -f decode
|
||||
--
|
||||
-- The IO runtime expects the top-level value to be an interaction tree wrapped
|
||||
-- by the `io` sentinel:
|
||||
--
|
||||
-- pair "tricuIO" (pair version action)
|
||||
--
|
||||
-- View Contracts can validate that boundary before the IO driver starts. The IO
|
||||
-- value is still just an interaction tree; this demo only checks how it was
|
||||
-- exposed.
|
||||
|
||||
ioSentinel? = (value :
|
||||
and?
|
||||
(equal? (fst value) "tricuIO")
|
||||
(equal? (fst (snd value)) 1))
|
||||
|
||||
requireIO = (value :
|
||||
lazyBool
|
||||
(_ : guardOk value)
|
||||
(_ : guardFail)
|
||||
(ioSentinel? value))
|
||||
|
||||
-- A first useful IO View is intentionally shallow:
|
||||
--
|
||||
-- viewAny -- accept any payload structurally
|
||||
-- requireIO sentinel -- require the top-level IO wrapper at runtime
|
||||
--
|
||||
-- This does not prove every future continuation step is well-formed. It proves
|
||||
-- the checked program exposes an IO interaction tree to the host driver.
|
||||
viewIO = viewGuarded viewAny requireIO
|
||||
|
||||
checkedIO = (action :
|
||||
matchResult
|
||||
(diag env : io (pure (renderDiagnostic diag)))
|
||||
(exec env :
|
||||
matchResult
|
||||
(runtimeDiag runtimeEnv : io (pure (renderDiagnostic runtimeDiag)))
|
||||
(value runtimeEnv : value)
|
||||
(runChecked exec))
|
||||
(checkTypedProgramWith
|
||||
policyStrict
|
||||
(typedProgram 0 [(typedValue 0 viewIO action)])))
|
||||
|
||||
main = checkedIO (io (pure "checked interaction tree"))
|
||||
17
demos/viewContracts/modules/README.md
Normal file
17
demos/viewContracts/modules/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Module View Contract demo
|
||||
|
||||
This demo shows producer-checked module export Views flowing into a consumer
|
||||
check as trusted View Contract evidence.
|
||||
|
||||
```sh
|
||||
tricu check demos/viewContracts/modules/success.tri
|
||||
# ok
|
||||
|
||||
tricu check demos/viewContracts/modules/failure.tri
|
||||
# symbol 3 (Util.toString application result) expected Bool but got String
|
||||
```
|
||||
|
||||
`util.tri` is a local workspace module. During auto-build, its annotated exports
|
||||
are checked before the module manifest alias is published. The consumer then
|
||||
uses the manifest's View Contract metadata and View Tree export artifacts as
|
||||
module-boundary assumptions; compatibility is still judged by `lib/view.tri`.
|
||||
3
demos/viewContracts/modules/failure.tri
Normal file
3
demos/viewContracts/modules/failure.tri
Normal file
@@ -0,0 +1,3 @@
|
||||
!import "vc.demo.util" Util
|
||||
|
||||
foo x@Bool =@Bool Util.toString x
|
||||
3
demos/viewContracts/modules/success.tri
Normal file
3
demos/viewContracts/modules/success.tri
Normal file
@@ -0,0 +1,3 @@
|
||||
!import "vc.demo.util" Util
|
||||
|
||||
foo x@Bool =@Bool Util.id x
|
||||
1
demos/viewContracts/modules/tricu.workspace
Normal file
1
demos/viewContracts/modules/tricu.workspace
Normal file
@@ -0,0 +1 @@
|
||||
module vc.demo.util = util.tri
|
||||
2
demos/viewContracts/modules/util.tri
Normal file
2
demos/viewContracts/modules/util.tri
Normal file
@@ -0,0 +1,2 @@
|
||||
id x@Bool =@Bool x
|
||||
toString x@Bool =@String "ok"
|
||||
3
demos/viewContracts/selfTests.tri
Normal file
3
demos/viewContracts/selfTests.tri
Normal file
@@ -0,0 +1,3 @@
|
||||
!import "views.catalog" !Local
|
||||
|
||||
main = viewCatalogSelfTests
|
||||
9
demos/viewContracts/sourceSyntax/failure.tri
Normal file
9
demos/viewContracts/sourceSyntax/failure.tri
Normal file
@@ -0,0 +1,9 @@
|
||||
-- Source-level View Contract diagnostic demo.
|
||||
-- Run with: tricu check demos/viewContracts/sourceSyntax/failure.tri
|
||||
|
||||
makeBool x@String =@Bool x
|
||||
|
||||
xs =@(List String) [(g "hi")]
|
||||
g y@String =@Bool y
|
||||
|
||||
main = "if you're seeing this instead of an error, you ran the file unchecked"
|
||||
10
demos/viewContracts/sourceSyntax/success.tri
Normal file
10
demos/viewContracts/sourceSyntax/success.tri
Normal file
@@ -0,0 +1,10 @@
|
||||
-- Source-level View Contract syntax sugar demo.
|
||||
-- Run with: tricu check demos/viewContracts/sourceSyntax/success.tri
|
||||
|
||||
message =@String "hello"
|
||||
|
||||
boxedMessages =@(Maybe (List String)) just [(message) ("world")]
|
||||
|
||||
chooseFirst x@String y@Byte =@String x
|
||||
|
||||
fromLambda =@(Fn [String] String) (x : x)
|
||||
10
demos/viewContracts/stdlibContracts.tri
Normal file
10
demos/viewContracts/stdlibContracts.tri
Normal file
@@ -0,0 +1,10 @@
|
||||
!import "prelude" !Local
|
||||
!import "view" !Local
|
||||
!import "views.catalog" !Local
|
||||
|
||||
main = [
|
||||
(typedContractCheck listMapBoolStringContract)
|
||||
(typedContractCheck headMaybeBoolContract)
|
||||
(typedContractCheck listFilterBoolContract)
|
||||
(typedContractCheck listFoldStringBoolContract)
|
||||
(typedContractCheck listMapMaybeBoolStringContract)]
|
||||
Reference in New Issue
Block a user