Begin removing view related code and docs
This commit is contained in:
98
lib/base.tri
98
lib/base.tri
@@ -119,6 +119,47 @@ maybeBind m f = matchMaybe nothing f m
|
||||
maybeOr default m = matchMaybe default id m
|
||||
maybe? = matchMaybe false (_ : true)
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Lazy eliminators
|
||||
--
|
||||
-- A strict eliminator evaluates both branches because they are ordinary
|
||||
-- arguments. Give a branch that recurses, looks something up, or builds
|
||||
-- structure to one of these instead: it becomes a thunk and only the selected
|
||||
-- branch is ever applied.
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
lazyBool = (thenK elseK cond :
|
||||
((chosen : chosen t)
|
||||
(matchBool
|
||||
thenK
|
||||
elseK
|
||||
cond)))
|
||||
|
||||
-- This module has no list matcher, so `triage` is used directly: a cons is a
|
||||
-- Fork, which is why the cons case sits in the fork slot, exactly as in
|
||||
-- `matchList` in lib/list.tri.
|
||||
lazyList = (nilK consK xs :
|
||||
((chosen : chosen t)
|
||||
(triage
|
||||
nilK
|
||||
_
|
||||
(h r : (_ : consK h r))
|
||||
xs)))
|
||||
|
||||
lazyMaybe = (noneK someK m :
|
||||
((chosen : chosen t)
|
||||
(matchMaybe
|
||||
noneK
|
||||
(x : (_ : someK x))
|
||||
m)))
|
||||
|
||||
lazyResult = (errK okK result :
|
||||
((chosen : chosen t)
|
||||
(matchResult
|
||||
(code rest : (_ : errK code rest))
|
||||
(value rest : (_ : okK value rest))
|
||||
result)))
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Basic arithmetic
|
||||
-- ---------------------------------------------------------------------------
|
||||
@@ -137,18 +178,15 @@ andLazy? = (a bK :
|
||||
|
||||
pred = y (self : triage
|
||||
0
|
||||
(_ : 0)
|
||||
0
|
||||
(bit rest :
|
||||
matchBool
|
||||
(matchBool
|
||||
ifLazy
|
||||
bit
|
||||
(_ : matchBool
|
||||
(t t rest)
|
||||
0
|
||||
(pair 0 rest)
|
||||
(equal? rest 0))
|
||||
(matchBool
|
||||
0
|
||||
(pair 1 (self rest))
|
||||
(equal? rest 0))
|
||||
bit))
|
||||
rest)
|
||||
(_ : t (t t) (self rest))))
|
||||
|
||||
isZero? = triage true (_ : false) (_ _ : false)
|
||||
|
||||
@@ -190,6 +228,42 @@ mul = y (self a b :
|
||||
(_ : 0)
|
||||
(_ : add a (self a (pred b))))
|
||||
|
||||
div = y (self a b :
|
||||
ifLazy
|
||||
(isZero? b)
|
||||
(_ : 0)
|
||||
(_ : ifLazy
|
||||
(lt? a b)
|
||||
(_ : 0)
|
||||
(_ : succ (self (sub a b) b))))
|
||||
|
||||
mod = y (self a b :
|
||||
ifLazy
|
||||
(isZero? b)
|
||||
(_ : 0)
|
||||
(_ : ifLazy
|
||||
(lt? a b)
|
||||
(_ : a)
|
||||
(_ : self (sub a b) b)))
|
||||
|
||||
pow = y (self a b :
|
||||
ifLazy
|
||||
(isZero? b)
|
||||
(_ : 1)
|
||||
(_ : mul a (self a (pred b))))
|
||||
|
||||
even? n = (triage
|
||||
true
|
||||
(_ : false)
|
||||
(bit _ : isZero? bit)
|
||||
n)
|
||||
|
||||
odd? = (n : not? (even? n))
|
||||
|
||||
min = (a b : ifLazy (lte? a b) (_ : a) (_ : b))
|
||||
|
||||
max = (a b : ifLazy (lte? a b) (_ : b) (_ : a))
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Result combinators
|
||||
-- ---------------------------------------------------------------------------
|
||||
@@ -217,7 +291,3 @@ resultMapErr = (f result :
|
||||
(code rest : err (f code) rest)
|
||||
(value rest : ok value rest)
|
||||
result)
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- View facts
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
240
lib/contracts.tri
Normal file
240
lib/contracts.tri
Normal file
@@ -0,0 +1,240 @@
|
||||
!import "base" !Local
|
||||
!import "list" !Local
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Core contract type
|
||||
--
|
||||
-- A contract is an ordinary tricu function: Tree -> Tree -> Result Tree Tree.
|
||||
-- The second argument is the conventional "rest" slot. On success a contract
|
||||
-- returns the checked value wrapped in the standard ok shape; on failure it
|
||||
-- returns a diagnostic wrapped in the standard err shape.
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
contractOk = (value : (rest : ok value rest))
|
||||
contractErr = (msg : (rest : err msg rest))
|
||||
|
||||
-- Apply a contract with the conventional rest slot and return the raw Result.
|
||||
checkContract = (contract value : contract value t)
|
||||
|
||||
-- Apply a contract and continue with either the onOk or onFail branch.
|
||||
withContract = (contract value onOk onFail :
|
||||
matchResult
|
||||
(msg _ : onFail msg)
|
||||
(checked _ : onOk checked)
|
||||
(contract value t))
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Basic contracts
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
-- Any value passes.
|
||||
anyC = (value : contractOk value)
|
||||
|
||||
-- Always fails with the supplied message.
|
||||
neverC = (msg : (value : contractErr msg))
|
||||
|
||||
-- Build a contract from a predicate that inspects only the value.
|
||||
guardC = (msg predicate value rest :
|
||||
lazyBool
|
||||
(_ : contractOk value rest)
|
||||
(_ : contractErr msg rest)
|
||||
(predicate value))
|
||||
|
||||
-- Natural number contract.
|
||||
nat? = guardC "not a natural number" (n : gte? n 0)
|
||||
|
||||
-- Non-zero number contract.
|
||||
nonZero? = guardC "non-zero" (n : not? (isZero? n))
|
||||
|
||||
-- Boolean contract.
|
||||
bool? = guardC "not a boolean" (b : or? (equal? b true) (equal? b false))
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Contract combinators
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
andC = (c1 c2 value rest :
|
||||
matchResult
|
||||
(msg _ : contractErr msg rest)
|
||||
(v _ : c2 v rest)
|
||||
(c1 value rest))
|
||||
|
||||
orC = (c1 c2 value rest :
|
||||
matchResult
|
||||
(msg _ : c2 value rest)
|
||||
(v _ : contractOk v rest)
|
||||
(c1 value rest))
|
||||
|
||||
notC = (c value rest :
|
||||
matchResult
|
||||
(msg _ : contractOk value rest)
|
||||
(_ _ : contractErr "notC: predicate succeeded" rest)
|
||||
(c value rest))
|
||||
|
||||
mapC = (f c value rest :
|
||||
matchResult
|
||||
(msg _ : contractErr msg rest)
|
||||
(v _ : contractOk (f v) rest)
|
||||
(c value rest))
|
||||
|
||||
bindC = (c f value rest :
|
||||
matchResult
|
||||
(msg _ : contractErr msg rest)
|
||||
(v _ : f v value rest)
|
||||
(c value rest))
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Collection contracts
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
listOf = (c value rest :
|
||||
y (self orig xs :
|
||||
matchList
|
||||
(contractOk orig rest)
|
||||
(h r :
|
||||
matchResult
|
||||
(msg _ : contractErr msg rest)
|
||||
(_ _ : self orig r)
|
||||
(c h rest))
|
||||
xs) value value)
|
||||
|
||||
nonEmptyListOf = (c :
|
||||
andC (guardC "empty list" (xs : not? (emptyList? xs))) (listOf c))
|
||||
|
||||
pairOf = (c1 c2 p rest :
|
||||
matchPair
|
||||
(a b :
|
||||
matchResult
|
||||
(msg _ : contractErr msg rest)
|
||||
(a' _ :
|
||||
matchResult
|
||||
(msg _ : contractErr msg rest)
|
||||
(b' _ : contractOk (pair a' b') rest)
|
||||
(c2 b rest))
|
||||
(c1 a rest))
|
||||
p)
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Higher-order function contracts
|
||||
--
|
||||
-- These return a Result-wrapped proxy. The proxy itself is a contract: it
|
||||
-- checks arguments on the way in and results on the way out.
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
fnContract = (argC resC f rest :
|
||||
contractOk
|
||||
(x : (rest1 :
|
||||
withContract argC x
|
||||
(x' :
|
||||
withContract resC (f x')
|
||||
(y : contractOk y rest1)
|
||||
(msg : contractErr msg rest1))
|
||||
(msg : contractErr msg rest1)))
|
||||
rest)
|
||||
|
||||
fn2 = (arg1C arg2C resC f rest :
|
||||
contractOk
|
||||
(x : (rest1 :
|
||||
withContract arg1C x
|
||||
(x' :
|
||||
contractOk
|
||||
(y : (rest2 :
|
||||
withContract arg2C y
|
||||
(y' :
|
||||
withContract resC (f x' y')
|
||||
(z : contractOk z rest2)
|
||||
(msg : contractErr msg rest2))
|
||||
(msg : contractErr msg rest2)))
|
||||
rest1)
|
||||
(msg : contractErr msg rest1)))
|
||||
rest)
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Interaction-tree effect layer
|
||||
--
|
||||
-- These constructors and combinators layer catchable, composable failures on
|
||||
-- top of the core Result contracts. They reuse the same tags as tricu IO:
|
||||
-- 0 = pureE
|
||||
-- 1 = bindE
|
||||
-- 2 = exceptE
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
pureE = (value : pair 0 value)
|
||||
bindE = (action k : pair 1 (pair action k))
|
||||
exceptE = (tag value k : pair 2 (pair tag (pair value k)))
|
||||
|
||||
pureM = pureE
|
||||
bindM = bindE
|
||||
|
||||
-- Lift a contract failure into an interaction tree.
|
||||
checkM = (contract value :
|
||||
matchResult
|
||||
(msg _ : exceptE "contract" msg (_ : pureE t))
|
||||
(checked _ : pureE checked)
|
||||
(contract value t))
|
||||
|
||||
-- Lift a pure function into the interaction tree.
|
||||
liftM = (f : (x : pureE (f x)))
|
||||
|
||||
-- Interpret a pure interaction tree into a Result.
|
||||
runM = (tree :
|
||||
run tree
|
||||
where run =
|
||||
y (self tree :
|
||||
matchPair
|
||||
(op payload :
|
||||
matchBool
|
||||
-- pureE
|
||||
(contractOk (snd tree) t)
|
||||
(matchBool
|
||||
-- bindE
|
||||
(matchPair
|
||||
(action k :
|
||||
matchResult
|
||||
(msg _ : contractErr msg t)
|
||||
(v _ : self (k v))
|
||||
(self action))
|
||||
payload)
|
||||
-- exceptE
|
||||
(matchPair
|
||||
(tag pair :
|
||||
matchPair
|
||||
(value k :
|
||||
contractErr value t)
|
||||
pair)
|
||||
payload)
|
||||
(equal? op 1))
|
||||
(equal? op 0))
|
||||
tree))
|
||||
|
||||
-- Handle matching exceptE nodes by applying the handler to the value and the
|
||||
-- resumption continuation. Non-matching exceptions are left in place.
|
||||
handleM = (tag handler tree :
|
||||
handle tree
|
||||
where handle =
|
||||
y (self tree :
|
||||
matchPair
|
||||
(op payload :
|
||||
matchBool
|
||||
-- pureE
|
||||
tree
|
||||
(matchBool
|
||||
-- bindE
|
||||
(matchPair
|
||||
(action k :
|
||||
bindE (self action) (v : self (k v)))
|
||||
payload)
|
||||
-- exceptE
|
||||
(matchPair
|
||||
(et pair :
|
||||
matchPair
|
||||
(value k :
|
||||
matchBool
|
||||
(self (handler value k))
|
||||
tree
|
||||
(equal? et tag))
|
||||
pair)
|
||||
payload)
|
||||
(equal? op 1))
|
||||
(equal? op 0))
|
||||
tree))
|
||||
24
lib/guardedBase.tri
Normal file
24
lib/guardedBase.tri
Normal file
@@ -0,0 +1,24 @@
|
||||
!import "base" !Local
|
||||
!import "list" !Local
|
||||
!import "contracts" !Local
|
||||
!import "intensional" !Local
|
||||
|
||||
-- Runtime-guarded wrappers around partial or structurally-sensitive base/list
|
||||
-- functions. Each wrapper uses the frontend @ / =@ desugaring and is exported
|
||||
-- with an advertised contract so manifests carry the contract terms.
|
||||
|
||||
safeHead xs@(nonEmptyListOf anyC) =@anyC head xs
|
||||
safeTail xs@(nonEmptyListOf anyC) =@(listOf anyC) tail xs
|
||||
|
||||
safeDiv a@nat? b@(andC nat? nonZero?) =@nat? div a b
|
||||
|
||||
safeHalf n@(andC nat? evenC?) =@nat? div n 2
|
||||
|
||||
-- last is only guaranteed to return the maximum if the input list is sorted.
|
||||
sortedMax xs@(sortedList? nat?) =@nat? last xs
|
||||
|
||||
!export safeHead : fnContract (nonEmptyListOf anyC) anyC
|
||||
!export safeTail : fnContract (nonEmptyListOf anyC) (listOf anyC)
|
||||
!export safeDiv : fn2 nat? nonZero? nat?
|
||||
!export safeHalf : fnContract (andC nat? evenC?) nat?
|
||||
!export sortedMax : fnContract (sortedList? nat?) nat?
|
||||
55
lib/intensionalContracts.tri
Normal file
55
lib/intensionalContracts.tri
Normal file
@@ -0,0 +1,55 @@
|
||||
!import "base" !Local
|
||||
!import "list" !Local
|
||||
!import "contracts" !Local
|
||||
|
||||
-- Structural contracts that exploit Tree Calculus's intensional nature.
|
||||
-- These are not simple type tags; they recursively inspect the tree shape.
|
||||
|
||||
-- Any value that is not Leaf.
|
||||
nonEmptyTree? = guardC "empty tree" (x : not? (isZero? x))
|
||||
|
||||
-- Every internal node is a Fork with two children; Stems are not allowed.
|
||||
fullTree? = guardC "not a full binary tree"
|
||||
(y (self x :
|
||||
triage
|
||||
true
|
||||
(_ : false)
|
||||
(l r : and? (self l) (self r))
|
||||
x))
|
||||
|
||||
-- Even and odd number contracts that inspect the LSB bit tree.
|
||||
evenC? = guardC "not even" even?
|
||||
oddC? = guardC "not odd" odd?
|
||||
|
||||
-- A power of two has exactly one '1' bit in its LSB encoding.
|
||||
powerOfTwo? = guardC "not a power of two"
|
||||
(y (self n :
|
||||
triage
|
||||
false
|
||||
true
|
||||
(bit rest :
|
||||
matchBool
|
||||
(self rest)
|
||||
false
|
||||
(isZero? bit))
|
||||
n))
|
||||
|
||||
-- A string (list of numbers) where every code point is in the ASCII range.
|
||||
asciiString? = listOf
|
||||
(guardC "non-ascii byte" (n : and? (gte? n 0) (lte? n 127)))
|
||||
|
||||
-- Check that a list of numbers is sorted in ascending order.
|
||||
-- The element contract parameter is applied separately by listOf.
|
||||
isSorted_ = (self xs :
|
||||
matchList
|
||||
true
|
||||
(h r :
|
||||
matchBool
|
||||
(self r)
|
||||
false
|
||||
(matchList true (h2 _ : lte? h h2) r))
|
||||
xs)
|
||||
|
||||
isSorted = y isSorted_
|
||||
|
||||
sortedList? = (c : andC (listOf c) (guardC "not sorted" isSorted))
|
||||
30
lib/lazy.tri
30
lib/lazy.tri
@@ -1,30 +0,0 @@
|
||||
!import "base" !Local
|
||||
!import "list" !Local
|
||||
|
||||
lazyBool = (thenK elseK cond :
|
||||
((chosen : chosen t)
|
||||
(matchBool
|
||||
thenK
|
||||
elseK
|
||||
cond)))
|
||||
|
||||
lazyList = (nilK consK xs :
|
||||
((chosen : chosen t)
|
||||
(matchList
|
||||
nilK
|
||||
(h r : (_ : consK h r))
|
||||
xs)))
|
||||
|
||||
lazyMaybe = (noneK someK m :
|
||||
((chosen : chosen t)
|
||||
(matchMaybe
|
||||
noneK
|
||||
(x : (_ : someK x))
|
||||
m)))
|
||||
|
||||
lazyResult = (errK okK result :
|
||||
((chosen : chosen t)
|
||||
(matchResult
|
||||
(code rest : (_ : errK code rest))
|
||||
(value rest : (_ : okK value rest))
|
||||
result)))
|
||||
131
lib/list.tri
131
lib/list.tri
@@ -232,54 +232,103 @@ contains?_ self needle haystack =
|
||||
(startsWith? needle haystack)
|
||||
contains? = needle haystack : y contains?_ needle haystack
|
||||
|
||||
linesFinish current accRev =
|
||||
reverse (pair (reverse current) accRev)
|
||||
sum = foldl (acc x : add x acc) 0
|
||||
product = foldl (acc x : mul x acc) 1
|
||||
|
||||
lines_ self str accRev current =
|
||||
matchList
|
||||
(linesFinish current accRev)
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Generic separators
|
||||
--
|
||||
-- `lines`, `unlines`, `words` and `unwords` at the bottom of this section are
|
||||
-- the byte-valued special cases of these primitives.
|
||||
--
|
||||
-- Joining takes any separator; splitting takes one byte. Separators are removed
|
||||
-- rather than kept, and empty fields are preserved.
|
||||
--
|
||||
-- The workers below follow notes/tricu-normalization-rules.md: consumed data
|
||||
-- first, lazy eliminators around every recursive branch, `y` only inside the
|
||||
-- public wrapper, and `pair`-only state updates.
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
takeWhile_ self xs f =
|
||||
lazyList
|
||||
(_ : t)
|
||||
(h r :
|
||||
matchBool
|
||||
(self r (pair (reverse current) accRev) t)
|
||||
(self r accRev (pair h current))
|
||||
(equal? h 10))
|
||||
str
|
||||
lines = str : y lines_ str t t
|
||||
lazyBool
|
||||
(_ : pair h (self r f))
|
||||
(_ : t)
|
||||
(f h))
|
||||
xs
|
||||
takeWhile = f xs : y takeWhile_ xs f
|
||||
|
||||
unlines_ self lines =
|
||||
matchList
|
||||
""
|
||||
(h r : append h (append "\n" (self r)))
|
||||
lines
|
||||
unlines = lines : y unlines_ lines
|
||||
|
||||
wordsAdd current accRev =
|
||||
matchBool
|
||||
accRev
|
||||
(pair (reverse current) accRev)
|
||||
(emptyList? current)
|
||||
|
||||
words_ self str accRev current =
|
||||
matchList
|
||||
(reverse (wordsAdd current accRev))
|
||||
dropWhile_ self xs f =
|
||||
lazyList
|
||||
(_ : t)
|
||||
(h r :
|
||||
matchBool
|
||||
(self r (wordsAdd current accRev) t)
|
||||
(self r accRev (pair h current))
|
||||
(equal? h 32))
|
||||
str
|
||||
words = str : y words_ str t t
|
||||
lazyBool
|
||||
(_ : self r f)
|
||||
(_ : pair h r)
|
||||
(f h))
|
||||
xs
|
||||
dropWhile = f xs : y dropWhile_ xs f
|
||||
|
||||
unwords_ self words =
|
||||
matchList
|
||||
""
|
||||
-- Byte-level whitespace only: space and horizontal tab (HTTP OWS).
|
||||
spaceByte? = b : equal? b 32
|
||||
tabByte? = b : equal? b 9
|
||||
trimByte? = b : or? (spaceByte? b) (tabByte? b)
|
||||
|
||||
trim = xs : dropWhile trimByte? (reverse (dropWhile trimByte? (reverse xs)))
|
||||
|
||||
intercalate_ self xs sep =
|
||||
lazyList
|
||||
(_ : t)
|
||||
(h r :
|
||||
matchBool
|
||||
h
|
||||
(append h (append " " (self r)))
|
||||
lazyBool
|
||||
(_ : h)
|
||||
(_ : append h (append sep (self r sep)))
|
||||
(emptyList? r))
|
||||
words
|
||||
unwords = words : y unwords_ words
|
||||
xs
|
||||
intercalate = sep xs : y intercalate_ xs sep
|
||||
|
||||
-- Separator after every field, including the last one. Line-oriented formats
|
||||
-- want this: `joinSuffix "\n" xs` terminates the final line while
|
||||
-- `intercalate "\n" xs` does not.
|
||||
joinSuffix_ self xs sep =
|
||||
lazyList
|
||||
(_ : t)
|
||||
(h r : append (append h sep) (self r sep))
|
||||
xs
|
||||
joinSuffix = sep xs : y joinSuffix_ xs sep
|
||||
|
||||
-- Split on a single byte. A separator byte is never stored, so the state
|
||||
-- updates stay `pair`s and every recursive argument is a variable: the input is
|
||||
-- walked exactly once and the fields are reversed back once, when it ends.
|
||||
--
|
||||
-- Splitting on a multi-byte separator is deliberately not here. Detecting a
|
||||
-- separator longer than a byte means re-walking the remaining input at every
|
||||
-- split point (or splicing the field), which is quadratic in the best case and
|
||||
-- blew up when tried. `http.tri` wants CRLF and `:` splits; that wants a shape
|
||||
-- where the separator drives the recursion instead of the input.
|
||||
--
|
||||
-- Empty fields are preserved: `splitOnByte 58 "a::b"` is ["a" "" "b"].
|
||||
splitByte_ self str byte acc current =
|
||||
lazyList
|
||||
(_ : map reverse (reverse (pair current acc)))
|
||||
(h r :
|
||||
lazyBool
|
||||
(_ : self r byte (pair current acc) t)
|
||||
(_ : self r byte acc (pair h current))
|
||||
(equal? h byte))
|
||||
str
|
||||
splitOnByte = byte str : y splitByte_ str byte t t
|
||||
|
||||
-- Every one of these keeps its arguments bound: partially applying a
|
||||
-- multi-argument function at the top level leaves a fixed point exposed.
|
||||
lines = str : splitOnByte 10 str
|
||||
unlines = xs : joinSuffix "\n" xs
|
||||
|
||||
-- Runs of separators collapse: empty fields are dropped.
|
||||
words = str : filter (w : not? (emptyList? w)) (splitOnByte 32 str)
|
||||
unwords = xs : intercalate " " xs
|
||||
|
||||
zipWith_ self f xs ys =
|
||||
matchList
|
||||
|
||||
@@ -3,5 +3,4 @@
|
||||
!import "base" !Local
|
||||
!import "list" !Local
|
||||
!import "bytes" !Local
|
||||
!import "lazy" !Local
|
||||
!import "conversions" !Local
|
||||
|
||||
1656
lib/view.tri
1656
lib/view.tri
File diff suppressed because it is too large
Load Diff
@@ -1,267 +0,0 @@
|
||||
!import "prelude" !Local
|
||||
!import "view" !Local
|
||||
|
||||
-- Stdlib-shaped typed-program catalog. These helpers are stable lowering
|
||||
-- targets for frontend-emitted API contracts. They are monomorphic
|
||||
-- instantiations of familiar polymorphic shapes.
|
||||
listMapUseContract = (elemIn elemOut mapSym fnSym xsSym partialSym outSym :
|
||||
typedProgram
|
||||
outSym
|
||||
[(typedDeclareFn
|
||||
mapSym
|
||||
[(viewFn [(elemIn)] elemOut) (viewList elemIn)]
|
||||
(viewList elemOut)
|
||||
t)
|
||||
(typedDeclareFn fnSym [(elemIn)] elemOut t)
|
||||
(typedValue xsSym (viewList elemIn) t)
|
||||
(typedApply partialSym mapSym fnSym t)
|
||||
(typedApply outSym partialSym xsSym t)
|
||||
(typedRequire outSym (viewList elemOut) t)])
|
||||
|
||||
headMaybeUseContract = (elem headSym xsSym outSym :
|
||||
typedProgram
|
||||
outSym
|
||||
[(typedDeclareFn headSym [(viewList elem)] (viewMaybe elem) t)
|
||||
(typedValue xsSym (viewList elem) t)
|
||||
(typedApply outSym headSym xsSym t)
|
||||
(typedRequire outSym (viewMaybe elem) t)])
|
||||
|
||||
listFilterUseContract = (elem filterSym predSym xsSym partialSym outSym :
|
||||
typedProgram
|
||||
outSym
|
||||
[(typedDeclareFn
|
||||
filterSym
|
||||
[(viewFn [(elem)] viewBool) (viewList elem)]
|
||||
(viewList elem)
|
||||
t)
|
||||
(typedDeclareFn predSym [(elem)] viewBool t)
|
||||
(typedValue xsSym (viewList elem) t)
|
||||
(typedApply partialSym filterSym predSym t)
|
||||
(typedApply outSym partialSym xsSym t)
|
||||
(typedRequire outSym (viewList elem) t)])
|
||||
|
||||
listFoldUseContract = (acc elem foldSym fnSym initSym xsSym partialFnSym partialInitSym outSym :
|
||||
typedProgram
|
||||
outSym
|
||||
[(typedDeclareFn
|
||||
foldSym
|
||||
[(viewFn [(acc) (elem)] acc) acc (viewList elem)]
|
||||
acc
|
||||
t)
|
||||
(typedDeclareFn fnSym [(acc) (elem)] acc t)
|
||||
(typedValue initSym acc t)
|
||||
(typedValue xsSym (viewList elem) t)
|
||||
(typedApply partialFnSym foldSym fnSym t)
|
||||
(typedApply partialInitSym partialFnSym initSym t)
|
||||
(typedApply outSym partialInitSym xsSym t)
|
||||
(typedRequire outSym acc t)])
|
||||
|
||||
listMapMaybeUseContract = (elemIn elemOut mapMaybeSym fnSym xsSym partialSym outSym :
|
||||
typedProgram
|
||||
outSym
|
||||
[(typedDeclareFn
|
||||
mapMaybeSym
|
||||
[(viewFn [(elemIn)] (viewMaybe elemOut)) (viewList elemIn)]
|
||||
(viewList elemOut)
|
||||
t)
|
||||
(typedDeclareFn fnSym [(elemIn)] (viewMaybe elemOut) t)
|
||||
(typedValue xsSym (viewList elemIn) t)
|
||||
(typedApply partialSym mapMaybeSym fnSym t)
|
||||
(typedApply outSym partialSym xsSym t)
|
||||
(typedRequire outSym (viewList elemOut) t)])
|
||||
|
||||
-- Concrete stdlib-shaped typed programs. These are deliberately monomorphic
|
||||
-- examples of the shapes a frontend can emit for polymorphic library functions.
|
||||
listMapBoolStringExpr = cFn <|
|
||||
[(viewFn [(viewBool)] viewString) (viewList viewBool)] (viewList viewString)
|
||||
|> cApply (cFn [(viewBool)] viewString)
|
||||
|> cApply (cValue (viewList viewBool))
|
||||
|> cRequire (viewList viewString)
|
||||
|
||||
headMaybeBoolExpr = cFn <|
|
||||
[(viewList viewBool)] (viewMaybe viewBool)
|
||||
|> cApply (cValue (viewList viewBool))
|
||||
|> cRequire (viewMaybe viewBool)
|
||||
|
||||
listFilterBoolExpr = cFn <|
|
||||
[(viewFn [(viewBool)] viewBool) (viewList viewBool)] (viewList viewBool)
|
||||
|> cApply (cFn [(viewBool)] viewBool)
|
||||
|> cApply (cValue (viewList viewBool))
|
||||
|> cRequire (viewList viewBool)
|
||||
|
||||
listFoldStringBoolExpr = cFn <|
|
||||
[(viewFn [(viewString) (viewBool)] viewString) viewString (viewList viewBool)] viewString
|
||||
|> cApply (cFn [(viewString) (viewBool)] viewString)
|
||||
|> cApply (cValue viewString)
|
||||
|> cApply (cValue (viewList viewBool))
|
||||
|> cRequire viewString
|
||||
|
||||
listMapMaybeBoolStringExpr = cFn <|
|
||||
[(viewFn [(viewBool)] (viewMaybe viewString)) (viewList viewBool)] (viewList viewString)
|
||||
|> cApply (cFn [(viewBool)] (viewMaybe viewString))
|
||||
|> cApply (cValue (viewList viewBool))
|
||||
|> cRequire (viewList viewString)
|
||||
|
||||
-- Keep catalog exports as explicit finite typed-programs. `cCompileAt` is useful
|
||||
-- as a frontend-emission helper, but forcing generated node lists at module
|
||||
-- import time can violate top-level normalization discipline.
|
||||
listMapBoolStringContract =
|
||||
listMapUseContract viewBool viewString 100 101 102 103 104
|
||||
headMaybeBoolContract =
|
||||
headMaybeUseContract viewBool 110 111 112
|
||||
listFilterBoolContract =
|
||||
listFilterUseContract viewBool 120 121 122 123 124
|
||||
listFoldStringBoolContract =
|
||||
listFoldUseContract viewString viewBool 130 131 132 133 134 135 136
|
||||
listMapMaybeBoolStringContract =
|
||||
listMapMaybeUseContract viewBool viewString 140 141 142 143 144
|
||||
|
||||
listMapWrongFunctionArgContract =
|
||||
typedProgram
|
||||
152
|
||||
[(typedDeclareFn
|
||||
150
|
||||
[(viewFn [(viewBool)] viewString) (viewList viewBool)]
|
||||
(viewList viewString)
|
||||
t)
|
||||
(typedDeclareFn 151 [(viewString)] viewString t)
|
||||
(typedApply 152 150 151 t)]
|
||||
|
||||
listMapWrongListArgContract =
|
||||
typedProgram
|
||||
164
|
||||
[(typedDeclareFn
|
||||
160
|
||||
[(viewFn [(viewBool)] viewString) (viewList viewBool)]
|
||||
(viewList viewString)
|
||||
t)
|
||||
(typedDeclareFn 161 [(viewBool)] viewString t)
|
||||
(typedValue 162 (viewList viewString) t)
|
||||
(typedApply 163 160 161 t)
|
||||
(typedApply 164 163 162 t)]
|
||||
|
||||
listMapWrongOutputContract =
|
||||
typedProgram
|
||||
174
|
||||
[(typedDeclareFn
|
||||
170
|
||||
[(viewFn [(viewBool)] viewString) (viewList viewBool)]
|
||||
(viewList viewString)
|
||||
t)
|
||||
(typedDeclareFn 171 [(viewBool)] viewString t)
|
||||
(typedValue 172 (viewList viewBool) t)
|
||||
(typedApply 173 170 171 t)
|
||||
(typedApply 174 173 172 t)
|
||||
(typedRequire 174 (viewList viewBool) t)]
|
||||
|
||||
listFilterWrongPredicateContract =
|
||||
typedProgram
|
||||
182
|
||||
[(typedDeclareFn
|
||||
180
|
||||
[(viewFn [(viewBool)] viewBool) (viewList viewBool)]
|
||||
(viewList viewBool)
|
||||
t)
|
||||
(typedDeclareFn 181 [(viewBool)] viewString t)
|
||||
(typedApply 182 180 181 t)]
|
||||
|
||||
listMapWrongListArgExpr = cFn <|
|
||||
[(viewFn [(viewBool)] viewString) (viewList viewBool)] (viewList viewString)
|
||||
|> cApply (cFn [(viewBool)] viewString)
|
||||
|> cApply (cValue (viewList viewString))
|
||||
|> cRequire (viewList viewString)
|
||||
|
||||
listMapWrongListArgExprContract =
|
||||
typedProgram
|
||||
194
|
||||
[(typedDeclareFn
|
||||
190
|
||||
[(viewFn [(viewBool)] viewString) (viewList viewBool)]
|
||||
(viewList viewString)
|
||||
t)
|
||||
(typedDeclareFn 191 [(viewBool)] viewString t)
|
||||
(typedValue 193 (viewList viewString) t)
|
||||
(typedApply 192 190 191 t)
|
||||
(typedApply 194 192 193 t)
|
||||
(typedRequire 194 (viewList viewString) t)]
|
||||
|
||||
viewCatalogSelfTests =
|
||||
append
|
||||
viewContractSelfTests
|
||||
[ (typedContractCheck listMapBoolStringContract)
|
||||
(typedContractCheck headMaybeBoolContract)
|
||||
(typedContractCheck listFilterBoolContract)
|
||||
(typedContractCheck listFoldStringBoolContract)
|
||||
(typedContractCheck listMapMaybeBoolStringContract)
|
||||
(viewContractExpectResult
|
||||
"function argument view is not known"
|
||||
(checkTypedProgramWith policyStrict listMapWrongFunctionArgContract))
|
||||
(viewContractExpectResult
|
||||
"function argument view is not known"
|
||||
(checkTypedProgramWith policyStrict listMapWrongListArgContract))
|
||||
(viewContractExpectResult
|
||||
"required view is not known"
|
||||
(checkTypedProgramWith policyStrict listMapWrongOutputContract))
|
||||
(viewContractExpectResult
|
||||
"function argument view is not known"
|
||||
(checkTypedProgramWith policyStrict listFilterWrongPredicateContract))
|
||||
(viewContractExpectResult
|
||||
"function argument view is not known"
|
||||
(checkTypedProgramWith policyStrict listMapWrongListArgExprContract))
|
||||
(viewContractExpectErrorTag
|
||||
errorTagOk
|
||||
(checkTypedProgram listMapBoolStringContract))
|
||||
(viewContractExpectErrorTag
|
||||
errorTagMissingFunctionArgumentView
|
||||
(checkTypedProgramWith policyStrict listMapWrongFunctionArgContract))
|
||||
(viewContractExpectErrorTag
|
||||
errorTagMissingFunctionArgumentView
|
||||
(checkTypedProgramWith policyStrict listMapWrongListArgContract))
|
||||
(viewContractExpectErrorTag
|
||||
errorTagMissingFunctionArgumentView
|
||||
(checkTypedProgramWith policyStrict listMapWrongListArgExprContract))
|
||||
(viewContractExpectErrorTag
|
||||
errorTagMissingRequiredView
|
||||
(checkTypedProgramWith policyStrict listMapWrongOutputContract))
|
||||
(viewContractExpectDiagnostic
|
||||
errorTagMissingFunctionArgumentView
|
||||
162
|
||||
(viewList viewBool)
|
||||
(checkTypedProgramWith policyStrict listMapWrongListArgContract))
|
||||
(viewContractExpectDiagnostic
|
||||
errorTagMissingRequiredView
|
||||
174
|
||||
(viewList viewBool)
|
||||
(checkTypedProgramWith policyStrict listMapWrongOutputContract))
|
||||
(viewContractExpectDiagnosticActual
|
||||
errorTagMissingFunctionArgumentView
|
||||
162
|
||||
(viewList viewBool)
|
||||
(viewList viewString)
|
||||
(checkTypedProgramWith policyStrict listMapWrongListArgContract))
|
||||
(viewContractExpectDiagnosticActual
|
||||
errorTagMissingFunctionArgumentView
|
||||
193
|
||||
(viewList viewBool)
|
||||
(viewList viewString)
|
||||
(checkTypedProgramWith policyStrict listMapWrongListArgExprContract))
|
||||
(viewContractExpectDiagnosticActual
|
||||
errorTagMissingRequiredView
|
||||
174
|
||||
(viewList viewBool)
|
||||
(viewList viewString)
|
||||
(checkTypedProgramWith policyStrict listMapWrongOutputContract))
|
||||
(viewContractExpectDiagnosticActual
|
||||
errorTagMissingFunctionArgumentView
|
||||
181
|
||||
(viewFn [(viewBool)] viewBool)
|
||||
(viewFn [(viewBool)] viewString)
|
||||
(checkTypedProgramWith policyStrict listFilterWrongPredicateContract))
|
||||
(matchResult
|
||||
(diag env :
|
||||
viewContractProbe
|
||||
(equal?
|
||||
(renderDiagnostic diag)
|
||||
"symbol 162 expected List Bool but got List String"))
|
||||
(env rest : "fail")
|
||||
(checkTypedProgramWith policyStrict listMapWrongListArgContract))]
|
||||
Reference in New Issue
Block a user