The accompanying files include twelve .cinch files in provisional language notation. There is no executable compiler, and the files have not been typechecked. They specify intended behavior and rejection criteria. Some files contain complete small algorithms under the proposed prelude; others are explicitly labeled API or proof-package sketches.
Files and assumptions
| File | Scope | Required environment |
|---|---|---|
01-bounded-index.cinch |
Runtime bounds decision and safe element access | Nat, Fin, Vec, Option, comparison decision procedure, borrowed access |
02-vector-filter.cinch |
Recursive finite filter with dependent output length | Vector constructors, copying elements, total pure predicate |
03-map-fusion.cinch |
Inductive proof and associated rewrite | Immutable finite List, total map, equality, congr |
04-productive-stream.cinch |
Guarded infinite producer and mapping | A sound Later discipline and coinductive observations |
05-schema-generator.cinch |
Compile-time database generator API | Stage I/O, snapshots, secret handles, declaration generator |
06-counter-upgrade.cinch |
Concrete state migration and operation models | Natural arithmetic, consuming ownership, upgrade coordinator for deployment |
07-rejected-programs.cinch |
Independent expected rejection cases | The rules identified by each case |
08-platform-simd.cinch |
Target-specific wrapping reduction and dispatch | Instruction semantics, capability detection, memory proofs, and checked lowering |
09-foreign-codec.cinch |
Foreign wrapper contract | Explicit native assumptions or isolation profile |
10-wasm-component.cinch and codec.wit |
Checked component adapter | WIT bindings, host failure policy, runtime bound check |
11-structured-tasks.cinch |
Scoped concurrent requests | Task outcome, cancellation and cleanup contracts |
Copy permits intentional element duplication. Mathematical Int and Nat do not silently use wrapping machine arithmetic. Proof constructors are logical primitives or checked library lemmas. Named generator and runtime services describe required library contracts rather than pretend implementations.
Bounded indexing
checkedIndex(3, 2) returns an index usable with a vector of length three. checkedIndex(3, 3) returns None. A successful runtime comparison creates evidence about the concrete value; that evidence is erased, while the comparison remains where static proof is unavailable.
Expected rejection: fabricating Fin 3 for the value seven. Expected acceptance: branching on a checked bound and using the result only on the successful branch.
Vector filtering
Filtering [1, 2, 3, 4] with an even predicate returns an existential length of two and [2, 4]. Filtering the empty vector returns length zero. Filtering with an always-false predicate returns the empty vector.
The algorithm records predicate decisions in source order before recursing. The example returns a dependent pair but does not silently claim the additional proofs. The accompanying proof targets are size preservation and exact subsequence correctness. The induction outline shows what must be supplied to expose those stronger guarantees.
Map fusion
For pure total functions, the list induction supplies a proof of the map-composition equation. The rewrite uses that exact theorem. The intended optimization removes an intermediate list under the selected pure semantic model.
An effectful counterexample uses callbacks that log. Nested eager maps log every inner callback before any outer callback. A fused map interleaves those logs. The pure theorem is inapplicable, and the compiler must reject that instantiation.
Productive streams
from(0) supports every finite requested prefix. Mapping square over it produces 0, 1, 4, 9, .... The delayed recursive call is guarded; a raw self-reference that fails to produce a head must be rejected.
The bisimulation outline compares heads and then guarded tails. A full implementation must select and formalize the guarded calculus before this syntax can be accepted. Arbitrary filtering remains a process unless a constructive progress interface justifies productive output.
Schema generation
The schema example scopes a compile-time database connection, captures introspection input, and passes the snapshot to a generator. No connection is attempted by this documentation package. The secret name is illustrative and contains no value. The check’s build inputs are the SCHEMA_DATABASE_URL name present in the build environment and CINCH_SCHEMA_TOOL naming an introspection tool; examples/source/schema-tool.sh records a fixed snapshot so the example checks without a database.
Expected mode behavior: refresh obtains and records input; replay uses recorded input; live explicitly contacts the database. Generated declarations require checking. Runtime bindings require a compatible schema and a policy maintaining the facts they rely on.
Counter migration
For old state value = 12, migration produces base = 12, delta = 0. Reading returns twelve. After three increments, the new representation returns fifteen. The relation is equality of total values, not equality of layouts.
These finite observations are illustrative checks, not the universal proof. The arithmetic proof establishes the relation for all naturals. Deployment also requires the operational and dependency checks described in the runtime specification.
Conformance matrix
| Case | Intended outcome | Reason |
|---|---|---|
| Branch-certified vector access | Accept | Bound evidence matches the live vector |
| Retained existential output length | Accept | Runtime witness supports the dependent value |
| Pure map-composition theorem | Accept | Structural induction and equality congruence |
| Productive guarded natural stream | Accept under selected guarded calculus | Each observation is justified |
| Unknown index without a check | Reject | Required evidence is unresolved |
Recursive proof of False |
Reject | Logical termination fails |
| Arbitrary productive stream filter | Reject claimed total signature | No next accepted element may exist |
| Effectful use of pure fusion rule | Reject | The theorem’s effect conditions fail |
| Embedded compile-time file handle | Reject | Resource cannot cross stages by serialization |
| Same-module acyclic generator | Accept | Compile-time dependencies can be scheduled |
| Genuine generator dependency cycle | Reject | Generator cannot be compiled before its own result |
| Layout migration with a surviving borrow | Reject activation | Old reference would become invalid |
| Upgrade omitting affected specialized clients | Reject activation | Checked assumptions of old machine code may fail |
Platform specific SIMD
The wrapping-sum example has a scalar semantic definition and a conditional SIMD rule. Its correctness theorem is parameterized by the target module. Positive cases include empty inputs, inputs shorter than a vector, exact blocks, partial tails, and arithmetic wrapping. A correct implementation handles all lengths through a general proof, not just those examples.
Expected rejection: an unsupported vector instruction without availability evidence, a full-width load beyond the valid tail, or reuse of the wrapping-integer theorem for floating-point reassociation. A scalar fallback keeps the public operation usable on the baseline platform.
Reading an incomplete example
A named proof module in an upgrade sketch is an obligation to implement, not evidence by naming. An example comment listing proof targets is not an axiom declaration. This distinction is deliberate: the documentation should be useful for implementation without claiming that an unspecified prelude or runtime has already been verified.
Source examples
These source examples are provided individually and reproduced below. The WIT interface accompanies the component adapter.
Bounded indexing
-- Surface 0.2. Proposed prelude and borrow-pattern rules; not compiled.module BoundedIndex where checkedIndex :: (n :: Nat) -> Nat -> Option (Fin n) checkedIndex n i = case decide (i < n) of Yes bound -> Some (Fin i bound) No _ -> None
tryGet :: forall a n region. using (copy :: Copy a) => Ref region (Vec n a) -> Nat -> Option a tryGet xs i = case checkedIndex n i of Some index -> Some (Vec.getCopy xs index) None -> None
-- For xs = [10, 20, 30], indices 0 and 2 succeed; index 3 returns None. -- Comparison stays executable; its successful proof is erased.Vector filtering
-- Surface 0.2. Algorithm; additional sequence laws are proof targets.module VectorFilter where filter :: forall a n region. using (copy :: Copy a) => (a -> Bool) -> Ref region (Vec n a) -> Sigma (m :: Nat). Vec m a filter predicate xs = filterFrom predicate xs 0
-- Matching Nil/Cons against `Vec n a` at a rigid `n` is refused (D35: -- this slice does not refine rigid indices), so the walk dispatches -- through `decide` and reads elements at computed indices with -- checked bounds. The output length builds at computed indices too. filterFrom :: forall a n region. using (copy :: Copy a) => (a -> Bool) -> Ref region (Vec n a) -> Nat -> Sigma (m :: Nat). Vec m a filterFrom predicate xs i = case decide (i < n) of No _ -> (0, Nil) Yes bound -> let elem = Vec.getCopy xs (Fin i bound) keep = predicate elem packed = filterFrom predicate xs (i + 1) in case packed of (m, tail) -> if keep then (m + 1, Cons elem tail) else (m, tail)
-- Strict let preserves source predicate order: the decision at index -- i is recorded before the walk continues to i + 1. -- Vec.getCopy copies the element out of the borrow and requires Copy -- evidence. -- Prove by induction: m <= n and exact predicate-selected subsequence. -- The result retains the witness m, not just an erased proof of existence.Map fusion
-- Surface 0.2. Pure finite reusable lists and total callbacks.module PureMapFusion where proof mapFusion :: (f :: Int -> Int) -> (g :: Int -> Int) -> (xs :: List Int) -> Eq (List.map f (List.map g xs)) (List.map (\x -> f (g x)) xs) proof mapFusion f g xs = case xs of Nil -> refl Cons x rest -> congr (\ys -> Cons (f (g x)) ys) (mapFusion f g rest)
rewrite mapMap forall (f :: Int -> Int) (g :: Int -> Int) (xs :: List Int). where match List.map f (List.map g xs) replace List.map (\x -> f (g x)) xs justify mapFusion f g xs
-- This theorem does not allow effectful callbacks or extend definitional equality.Productive streams
-- Surface 0.2. The guarded Later calculus still needs a formal choice.module NaturalStreams where codata Stream (a :: Type) where head :: a tail :: Later (Stream a)
corec from :: Nat -> Stream Nat corec from n = Stream { head = n, tail = delay (\() -> from (n + 1)) }
corec map :: forall a b. (a -> b) -> Stream a -> Stream b corec map f xs = Stream { head = f xs.head , tail = delay (\() -> map f (force xs.tail)) }
-- delay takes a checked guarded thunk; ordinary strict calls do not create delay. -- Finite observations of map (\x -> x * x) (from 0): 0, 1, 4, 9, ... -- Bisimulation needs matching heads and guarded tails. -- Arbitrary filtering remains a process without recurring-match evidence.Schema generation
-- Surface 0.2. API sketch; no real database connection or credentials.module SchemaBindings where stage derive :: SchemaSnapshot -> Declarations stage derive schema = CodecGenerator.derive schema
module Billing where import stage SchemaBindings
generate do snapshot <- Stage.snapshot "billing-schema" (\io -> Stage.withDatabase io (secret "SCHEMA_DATABASE_URL") ReadSchema (\db -> introspectConsistently db)) emit (SchemaBindings.derive snapshot)
-- Generator effects are checked against compile-time capabilities. -- Refresh captures input, replay uses it, live explicitly contacts a database. -- Generated bindings are checked; runtime use needs schema compatibility. -- Build inputs: SCHEMA_DATABASE_URL present in the build environment -- (referenced by name only) and CINCH_SCHEMA_TOOL naming the -- introspection tool; examples/source/schema-tool.sh supplies a -- recorded snapshot so this checks without a live database.Counter upgrade
-- Surface 0.2. State model, not a complete deployable package.module CounterEvolution where record StateV1 where value :: Nat record StateV2 where base :: Nat delta :: Nat
viewV1 :: StateV1 -> Nat viewV1 s = s.value viewV2 :: StateV2 -> Nat viewV2 s = s.base + s.delta incrementV1 :: StateV1 %1 -> StateV1 incrementV1 s = StateV1 { value = s.value + 1 } incrementV2 :: StateV2 %1 -> StateV2 incrementV2 s = StateV2 { base = s.base, delta = s.delta + 1 } migrate :: StateV1 %1 -> StateV2 migrate s = StateV2 { base = s.value, delta = 0 }
-- Related old next means old.value = next.base + next.delta. -- Migration preserves the view by Nat's zero law; increments by addition laws. -- Drain-and-replace also needs quiescence, resources and dependency evidence.Expected rejections
-- Independent intended semantic rejections; not one accepted module.module Rejections where badIndex :: Fin 3 badIndex = Fin 7 refl
proof impossible :: Void proof impossible = impossible
hiddenSuspend :: Request -> Bytes hiddenSuspend request = fetch request
-- Other required rejections: -- A task outliving a borrowed buffer; copying a mutable handle. -- An unknown proof hole in a deployable artifact. -- An unguarded recursive stream, or filter claiming productivity without progress. -- Reusing a bound after mutating the indexed buffer. -- An effectful map instantiated at the pure fusion theorem. -- An unsupported SIMD module selected before validation. -- FFI inside retryable STM, or freeing a cancelled foreign operation's buffer. -- Two ambiguous do providers, or changing a closure's captured runtime implicitly.Platform specific SIMD source
-- Surface 0.2. Target APIs and theorem module are obligations, not supplied proofs.module PlatformSum where scalar :: forall n region. Ref region (Vec n U32) -> U32 scalar xs = Stream.fold U32.zero U32.wrapping-add (Vec.stream xs)
-- The instruction law (platform section 5), stated over this module's -- own scalar model so the rewrite's justification proves the rule's -- equation. Like the target APIs it is an obligation, not a supplied -- proof: citing it records the assumption in the artifact manifest. signature SumProofs where scalar-to-simd :: forall t w n region. (vectors :: VecU32Target t w) -> (xs :: Ref region (Vec n U32)) -> Eq (scalar xs) (simd-sum-wrap32 vectors xs)
target rewrite sumWrap32Vector forall t w n region (xs :: Ref region (Vec n U32)). using (vectors :: VecU32Target t w) where match scalar xs replace Simd.sum-wrap32 vectors xs require Available vectors justify SumProofs.scalar-to-simd vectors xs
dispatched :: forall n region. Ref region (Vec n U32) -> U32 dispatched xs = case Target.detect-vec-u32 () of Some available -> Simd.sum-wrap32 available xs None -> scalar xs
-- detect-vec-u32 reads runtime-established metadata in this proposed pure API. -- Bounds, tails, modular arithmetic, intrinsic semantics and target availability -- are required proof obligations. Floating-point reassociation needs other laws. -- Wasm can require separate variants selected before module instantiation.09-foreign-codec.cinch
module ForeignCodecContract where -- Surface 0.2. A fictional codec interface, not an implemented wrapper. signature SafeCodec where opaque type Decoder :: Type record BoundedBytes (limit :: Nat) where bytes :: Bytes erased bound :: length bytes <= limit
decode :: forall region. Mut region Decoder -> Ref region Bytes -> (limit :: Nat) ->{Foreign Codec, Blocking, Diverge} Result DecodeError (BoundedBytes limit)
-- The signature intentionally leaves the concrete wrapper implementation abstract. -- The implementation must check target size conversions and allocator pairing, -- establish pointer access, interpret initialization, and check written <= limit. -- A native safety assumption remains unless verified; a postcheck cannot undo -- prior corruption. Isolation plus output validation is a separate trust profile. -- Cancellation must not free buffers or unload callbacks before acknowledgment.10-wasm-component.cinch
-- Surface 0.2. Adapter sketch for codec.wit; host failure policy is explicit.module CheckedComponentClient where record BoundedBytes (limit :: Nat) where bytes :: Bytes erased bound :: length bytes <= limit
decode :: forall region. Ref region Bytes -> (limit :: U32) ->{Foreign Component, Diverge} Result BoundaryError (BoundedBytes (toNat limit)) decode input limit = do outcome <- Raw.decode input limit case outcome of Err e -> Err (ForeignError e) Ok bytes -> case decide (length bytes <= toNat limit) of Yes bound -> Ok (BoundedBytes { bytes = bytes, bound = bound }) No _ -> Err ContractViolation
-- Direct do binds the whole Result; it does not automatically short-circuit. -- Only the concrete bound is proved, not all-input decompression correctness. -- Instance resource identity and trap policy survive adapter generation.11-structured-tasks.cinch
-- Surface 0.2. Ordinary functions; no async/await function category.module StructuredTasks where loadPair :: forall r. using (io :: Io r) => Request -> Request ->{Async r, IO r, Cancel r, Diverge} Result LoadError (Bytes, Bytes) loadPair left right = withScope $ \s -> do a <- spawn s (\() -> fetch left) b <- spawn s (\() -> fetch right) joinAllOrCancel s a b
-- spawn consumes a thunk; strict argument evaluation must not start fetch early. -- Direct sequencing is the default; a and b are task handles. -- On supported failure, request sibling cancellation and join cleanup. -- Shutdown is not time-bounded without progress assumptions. -- Migratable tasks additionally need transfer-safe captures/results. -- io is a lexical capability; its region identity is retained by tasks.codec.wit
package example:codec@0.1.0;
interface decoder { enum decode-error { malformed, too-large } decode: func(input: list<u8>, limit: u32) -> result<list<u8>, decode-error>;}
world codec-plugin { export decoder;}Runtime effects and unqualified do
The effect-polymorphic traversal works with both pure and suspending callbacks. A separate module selects Result sequencing through its signature parameter; the source still uses ordinary do.
-- Surface 0.2. Proposed APIs, not a compiled program.module GenericEffects where traverse :: forall a b e. (a ->{|e} b) -> List a ->{|e} List b traverse f xs = case xs of Nil -> Nil Cons x rest -> do y <- f x ys <- traverse f rest pure (Cons y ys)
-- One definition supports pure and suspending callbacks through row e. -- Direct sequencing binds ordinary results; callbacks are reusable here.
module ImportConfig (Seq :: ResultSequencing ConfigError) where -- The signature marks Seq as this module's sequencing provider. loadConfig :: forall r. using (io :: Io r) => Path ->{IO r, Async r, Cancel r, Diverge} Result ConfigError Config loadConfig path = do bytes <- read-config-bytes path config <- parse-config bytes pure config
-- Same do spelling, explicitly selected Result composition. -- io is a lexical runtime argument. Supplying it does not handle effects. -- An explicit call can use: loadConfig @{io = chosenIO} path -- Handler installation belongs to the entry point or an enclosing runtime scope.