Begin removing view related code and docs
This commit is contained in:
43
demos/contractBasics.tri
Normal file
43
demos/contractBasics.tri
Normal file
@@ -0,0 +1,43 @@
|
||||
!import "base" !Local
|
||||
!import "list" !Local
|
||||
!import "contracts" !Local
|
||||
|
||||
-- A custom 'and' combinator written directly against base.matchResult.
|
||||
-- It succeeds only when *both* contracts succeed, threading the checked value
|
||||
-- from the first into the second. This makes the Result pair structure explicit.
|
||||
myAndC = (c1 c2 value rest :
|
||||
matchResult
|
||||
(msg _ : contractErr msg rest)
|
||||
(v _ : c2 v rest)
|
||||
(c1 value rest))
|
||||
|
||||
-- Plain predicates lifted into contracts with a diagnostic message.
|
||||
natural? = guardC "natural" (n : gte? n 0)
|
||||
nonZero? = guardC "non-zero" (n : not? (isZero? n))
|
||||
|
||||
-- Safe wrappers around partial base / list functions.
|
||||
-- The frontend desugars @ and =@ into runtime withContract applications.
|
||||
safeDiv a@natural? b@(myAndC natural? nonZero?) =@natural? div a b
|
||||
|
||||
safeHead xs@(nonEmptyListOf anyC) =@anyC head xs
|
||||
safeTail xs@(nonEmptyListOf anyC) =@(listOf anyC) tail xs
|
||||
|
||||
-- A higher-order wrapper: the supplied function must satisfy a contract,
|
||||
-- the input list must satisfy a contract, and the result list is guaranteed.
|
||||
checkedMap f@(fnContract anyC natural?) xs@(listOf anyC) =@(listOf natural?) map f xs
|
||||
|
||||
-- Advertise the safe wrappers in the module manifest with their own contracts.
|
||||
!export safeDiv : fn2 natural? nonZero? natural?
|
||||
!export safeHead : fnContract (nonEmptyListOf anyC) anyC
|
||||
!export checkedMap : fn2 (fnContract anyC natural?) (listOf anyC) (listOf natural?)
|
||||
|
||||
-- A small interaction-tree pipeline that uses contracts as recoverable effects.
|
||||
pipeline = (input :
|
||||
do bindM
|
||||
scaled <- checkM natural? (mul input 2)
|
||||
half <- handleM "contract"
|
||||
(_ : pureM 1)
|
||||
(checkM nonZero? (sub scaled 4))
|
||||
pureM (div scaled half))
|
||||
|
||||
main = runM (pipeline 5)
|
||||
66
demos/contractEffects.tri
Normal file
66
demos/contractEffects.tri
Normal file
@@ -0,0 +1,66 @@
|
||||
!import "base" !Local
|
||||
!import "list" !Local
|
||||
!import "contracts" !Local
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Contracts + interaction trees with `do` notation
|
||||
--
|
||||
-- The `do` keyword takes a monadic bind operator. Here we use `bindM` from
|
||||
-- `lib/contracts.tri` to sequence pure, contract-checked computations.
|
||||
--
|
||||
-- checkM contract value -- lift a contract failure into the tree
|
||||
-- exceptE tag value k -- a resumable failure carrying a continuation
|
||||
-- handleM tag handler tree -- rewrite matching exceptions
|
||||
-- runM tree -- interpret the tree into a Result
|
||||
--
|
||||
-- A handler receives the exception value and the resumption continuation `k`.
|
||||
-- It may resume by calling `k value`, or it may replace the failing action with
|
||||
-- a new tree of its own.
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
positive? = guardC "expected positive integer" (n : gte? n 1)
|
||||
nonEmpty? = guardC "expected non-empty list" (xs : not? (emptyList? xs))
|
||||
|
||||
-- Average a list. Fails with a contract exception if the list is empty.
|
||||
average = (xs :
|
||||
do bindM
|
||||
_ <- checkM nonEmpty? xs
|
||||
n <- pureM (length xs)
|
||||
_ <- checkM positive? n
|
||||
total <- pureM (sum xs)
|
||||
pureM (div total n))
|
||||
|
||||
-- A resumable config lookup. When the key is missing, callers can supply a
|
||||
-- value by handling the "missing" exception.
|
||||
lookupConfig = (key defaultValue :
|
||||
exceptE "missing" key (resume : pureM defaultValue))
|
||||
|
||||
-- A pipeline that averages a list and divides by a configured divisor.
|
||||
pipeline = (xs :
|
||||
do bindM
|
||||
divisor <- lookupConfig "divisor" 1
|
||||
avg <- average xs
|
||||
scaled <- liftM (x : div x divisor) avg
|
||||
pureM scaled)
|
||||
|
||||
-- Without a handler the missing-key exception reaches runM.
|
||||
unhandled = runM (pipeline [10 20 30])
|
||||
-- < unhandled
|
||||
-- > [t, "divisor"]
|
||||
|
||||
-- With a handler we replace the missing divisor with 2, so 20 / 2 = 10.
|
||||
withHandler = runM (handleM "missing" (key k : pureM 2) (pipeline [10 20 30]))
|
||||
-- < withHandler
|
||||
-- > [t t, 10]
|
||||
|
||||
-- Handler can also use the original default by calling the resumption.
|
||||
withResume = runM (handleM "missing" (key k : k 2) (pipeline [10 20 30]))
|
||||
-- < withResume
|
||||
-- > [t t, 20]
|
||||
|
||||
-- Contract failures still propagate through handlers for other tags.
|
||||
bothFail = runM (handleM "missing" (key k : pureM 2) (pipeline []))
|
||||
-- < bothFail
|
||||
-- > [t, "expected non-empty list"]
|
||||
|
||||
main = withHandler
|
||||
@@ -1,190 +0,0 @@
|
||||
!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
|
||||
@@ -1,137 +0,0 @@
|
||||
# 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
|
||||
```
|
||||
@@ -1,119 +0,0 @@
|
||||
!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)]
|
||||
@@ -1,9 +0,0 @@
|
||||
!import "prelude" !Local
|
||||
!import "view" !Local
|
||||
!import "views.catalog" !Local
|
||||
|
||||
main =
|
||||
matchResult
|
||||
(diag env : renderDiagnostic diag)
|
||||
(env rest : "ok")
|
||||
(checkTypedProgramWith policyStrict listMapWrongListArgContract)
|
||||
@@ -1,116 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,17 +0,0 @@
|
||||
!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)
|
||||
@@ -1,20 +0,0 @@
|
||||
!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)
|
||||
@@ -1,19 +0,0 @@
|
||||
!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)
|
||||
@@ -1,30 +0,0 @@
|
||||
!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)))
|
||||
@@ -1,51 +0,0 @@
|
||||
!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"))
|
||||
@@ -1,17 +0,0 @@
|
||||
# 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`.
|
||||
@@ -1,3 +0,0 @@
|
||||
!import "vc.demo.util" Util
|
||||
|
||||
foo x@Bool =@Bool Util.toString x
|
||||
@@ -1,3 +0,0 @@
|
||||
!import "vc.demo.util" Util
|
||||
|
||||
foo x@Bool =@Bool Util.id x
|
||||
@@ -1 +0,0 @@
|
||||
module vc.demo.util = util.tri
|
||||
@@ -1,2 +0,0 @@
|
||||
id x@Bool =@Bool x
|
||||
toString x@Bool =@String "ok"
|
||||
@@ -1,3 +0,0 @@
|
||||
!import "views.catalog" !Local
|
||||
|
||||
main = viewCatalogSelfTests
|
||||
@@ -1,9 +0,0 @@
|
||||
-- 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"
|
||||
@@ -1,10 +0,0 @@
|
||||
-- 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)
|
||||
@@ -1,10 +0,0 @@
|
||||
!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