Multi-line let body wrapping in expand-let (eigentrust pitfall #5)#11
Conversation
Pitfall #11 (lazy argument reduction makes deep iteration scale as O(k^2) for non-fixed-point iterates) had no general fix because reduction is call-by-name everywhere and the user has no way to mark an argument position as "evaluate before passing." When every intermediate value differs bit-for-bit (Posit32, non-fixed-point Rat) the reducer redoes O(n) levels on every iteration, totalling ~O(k^2) terms expanded across k rounds. This commit picks approach (a) from the suggested-fix triage: a new expression form [force e] / (force e) that, at whnf time, fully normalizes its argument and returns the NF (with the force wrapper elided). Type-and-usage-transparent: infer(force(e)) = infer(e), inferQ(force(e)) = inferQ(e). Lowest blast radius — does not change existing reduction semantics for any expression that does not mention `force`. Users who hit pitfall #11 can wrap the recursive tail-call argument: ;; Before (slow): [eigentrust-iterate c p alpha eps budget [eigentrust-step c p alpha t]] ;; After (fast): [eigentrust-iterate c p alpha eps budget [force [eigentrust-step c p alpha t]]] Future work, deferred: (b) Make whnf eagerly normalize specific forms (numeric literals, list literals) so even unwrapped lazy chains collapse at WHNF. More general but architectural — needs care around QTT linearity (an expression marked m1 must not be evaluated twice by an "eager" optimizer that didn't see it was inside an eliminator). (c) Type-driven strictness for tail-call argument positions when the type is concrete. Hardest; requires call-site analysis and a way to mark "strict" in the function signature. Pipeline coverage (per .claude/rules/pipeline.md "New AST Node", user-facing surface syntax variant — 13 of the 15 listed files): Core (8): syntax.rkt expr-force struct + provide + expr? entry substitution.rkt shift, subst (recursive) zonk.rkt zonk, zonk-at-depth, default-metas reduction.rkt whnf-impl/match -> nf(arg); nf-whnf clause pretty-print.rkt pp-expr "[force ...]" + uses-bvar0? pnet-serialize.rkt reg1! typing-core.rkt infer (delegates to argument) qtt.rkt inferQ (delegates to argument) User-facing surface syntax (5): surface-syntax.rkt surf-force struct + provide parser.rkt (force e) keyword case tree-parser.rkt "force" surf-force in builtin-unary-ops elaborator.rkt surf-force -> expr-force macros.rkt surf-force recursive case in expand-expression Driver / generic recursion (2 — defensive coverage): driver.rkt contains-unsupported-qtt?, rewrite-spec effect-ordering.rkt fv-expr Not touched (deliberate): unify.rkt classify-whnf-problem already handles unknown forms via fall-through; force is type-identity so unification of [force e] with t reduces to unification of e with t after one whnf step. foreign.rkt force is not a runtime interop concept. typing-propagators.rkt no new structural typing behavior; force inherits whatever the argument has. Tests (tests/test-force-strict.rkt, 13 tests): 1. Basic semantics (5): whnf/nf on ground values, beta-redex, suc chains. 2. Type identity (2): infer(force(e)) = infer(e). 3. QTT identity (2): inferQ(force(e)) preserves type and the full usage vector — ESPECIALLY under a linear (m1) binder (force does NOT consume an extra unit). 4. Idempotence (2): force around already-WHNF / nested force. 5. Performance demo (2): synthetic deep chain with natrec at each level. Confirms lazy and strict produce the same NF, and asserts strict <= lazy + small slack at k=18. Empirical numbers from a synthetic natrec-per-level chain on the agent machine (the real eigentrust workload sees a much larger gap because Posit32 step is genuinely expensive per level): k=12: lazy=196ms strict=44ms ~4.5x k=16: lazy=297ms strict=55ms ~5.4x k=20: lazy=437ms strict=74ms ~5.9x k=24: lazy=555ms strict=83ms ~6.7x k=28: lazy=797ms strict=89ms ~9.0x The lazy curve is super-linear (~10x runtime for ~3.5x more depth); the strict curve is roughly linear in k. This is the O(k^2) vs O(k) shape predicted by pitfall #11. Verification: raco make racket/prologos/tests/test-force-strict.rkt ok raco test racket/prologos/tests/test-force-strict.rkt 13 / 13 raco test racket/prologos/tests/test-reduction.rkt 27 / 27 raco test racket/prologos/tests/test-parser.rkt 82 / 82 raco test racket/prologos/tests/test-syntax.rkt 20 / 20 raco test racket/prologos/tests/test-elaborator.rkt 40 / 40 Co-authored-by: kumavis <1474978+kumavis@users.noreply.github.com>
c66a6d7 to
ff851d8
Compare
The 2026-04-23 eigentrust pitfalls memo (forthcoming branch) enumerated 16 items hit during the EigenTrust implementation. Items #1-7 and #11-15 are language/elaboration defects with their own PRs. Items #8, #9, #10, and #16 are observations rather than Prologos defects; no compiler change is needed for them but the memo deserves a parallel disposition note so a future reader does not double-count them as open work. #8 (exact-Rat slow on deep iter): intrinsic to exact rational arithmetic; benchmark-scope guidance, not a fix. #9 (Posit32 literals work): positive observation; `~` literal prefix is unambiguous unlike `0/1`. No action. #10 (PVec preserves where List does not): subsumed by pitfall #3 fix. After #3 lands, both literal forms preserve element type uniformly. Close as duplicate. #16 (column-stochastic vs row-stochastic): algorithm/spec clarification, not a Prologos defect. The eigentrust implementation branch already takes column-stochastic M directly and validates via col-stochastic?. https://claude.ai/code/session_01MbncYJnrvjzhbVWw4xGi5x Co-authored-by: kumavis <1474978+kumavis@users.noreply.github.com>
kumavis
left a comment
There was a problem hiding this comment.
hiero wants to review further
ff851d8 to
e30fde2
Compare
Pitfall #11 (lazy argument reduction makes deep iteration scale as O(k^2) for non-fixed-point iterates) had no general fix because reduction is call-by-name everywhere and the user has no way to mark an argument position as "evaluate before passing." When every intermediate value differs bit-for-bit (Posit32, non-fixed-point Rat) the reducer redoes O(n) levels on every iteration, totalling ~O(k^2) terms expanded across k rounds. This commit picks approach (a) from the suggested-fix triage: a new expression form [force e] / (force e) that, at whnf time, fully normalizes its argument and returns the NF (with the force wrapper elided). Type-and-usage-transparent: infer(force(e)) = infer(e), inferQ(force(e)) = inferQ(e). Lowest blast radius — does not change existing reduction semantics for any expression that does not mention `force`. Users who hit pitfall #11 can wrap the recursive tail-call argument: ;; Before (slow): [eigentrust-iterate c p alpha eps budget [eigentrust-step c p alpha t]] ;; After (fast): [eigentrust-iterate c p alpha eps budget [force [eigentrust-step c p alpha t]]] Future work, deferred: (b) Make whnf eagerly normalize specific forms (numeric literals, list literals) so even unwrapped lazy chains collapse at WHNF. More general but architectural — needs care around QTT linearity (an expression marked m1 must not be evaluated twice by an "eager" optimizer that didn't see it was inside an eliminator). (c) Type-driven strictness for tail-call argument positions when the type is concrete. Hardest; requires call-site analysis and a way to mark "strict" in the function signature. Pipeline coverage (per .claude/rules/pipeline.md "New AST Node", user-facing surface syntax variant — 13 of the 15 listed files): Core (8): syntax.rkt expr-force struct + provide + expr? entry substitution.rkt shift, subst (recursive) zonk.rkt zonk, zonk-at-depth, default-metas reduction.rkt whnf-impl/match -> nf(arg); nf-whnf clause pretty-print.rkt pp-expr "[force ...]" + uses-bvar0? pnet-serialize.rkt reg1! typing-core.rkt infer (delegates to argument) qtt.rkt inferQ (delegates to argument) User-facing surface syntax (5): surface-syntax.rkt surf-force struct + provide parser.rkt (force e) keyword case tree-parser.rkt "force" surf-force in builtin-unary-ops elaborator.rkt surf-force -> expr-force macros.rkt surf-force recursive case in expand-expression Driver / generic recursion (2 — defensive coverage): driver.rkt contains-unsupported-qtt?, rewrite-spec effect-ordering.rkt fv-expr Not touched (deliberate): unify.rkt classify-whnf-problem already handles unknown forms via fall-through; force is type-identity so unification of [force e] with t reduces to unification of e with t after one whnf step. foreign.rkt force is not a runtime interop concept. typing-propagators.rkt no new structural typing behavior; force inherits whatever the argument has. Tests (tests/test-force-strict.rkt, 13 tests): 1. Basic semantics (5): whnf/nf on ground values, beta-redex, suc chains. 2. Type identity (2): infer(force(e)) = infer(e). 3. QTT identity (2): inferQ(force(e)) preserves type and the full usage vector — ESPECIALLY under a linear (m1) binder (force does NOT consume an extra unit). 4. Idempotence (2): force around already-WHNF / nested force. 5. Performance demo (2): synthetic deep chain with natrec at each level. Confirms lazy and strict produce the same NF, and asserts strict <= lazy + small slack at k=18. Empirical numbers from a synthetic natrec-per-level chain on the agent machine (the real eigentrust workload sees a much larger gap because Posit32 step is genuinely expensive per level): k=12: lazy=196ms strict=44ms ~4.5x k=16: lazy=297ms strict=55ms ~5.4x k=20: lazy=437ms strict=74ms ~5.9x k=24: lazy=555ms strict=83ms ~6.7x k=28: lazy=797ms strict=89ms ~9.0x The lazy curve is super-linear (~10x runtime for ~3.5x more depth); the strict curve is roughly linear in k. This is the O(k^2) vs O(k) shape predicted by pitfall #11. Verification: raco make racket/prologos/tests/test-force-strict.rkt ok raco test racket/prologos/tests/test-force-strict.rkt 13 / 13 raco test racket/prologos/tests/test-reduction.rkt 27 / 27 raco test racket/prologos/tests/test-parser.rkt 82 / 82 raco test racket/prologos/tests/test-syntax.rkt 20 / 20 raco test racket/prologos/tests/test-elaborator.rkt 40 / 40 Co-authored-by: kumavis <1474978+kumavis@users.noreply.github.com>
The 2026-04-23 eigentrust pitfalls memo (forthcoming branch) enumerated 16 items hit during the EigenTrust implementation. Items #1-7 and #11-15 are language/elaboration defects with their own PRs. Items #8, #9, #10, and #16 are observations rather than Prologos defects; no compiler change is needed for them but the memo deserves a parallel disposition note so a future reader does not double-count them as open work. #8 (exact-Rat slow on deep iter): intrinsic to exact rational arithmetic; benchmark-scope guidance, not a fix. #9 (Posit32 literals work): positive observation; `~` literal prefix is unambiguous unlike `0/1`. No action. #10 (PVec preserves where List does not): subsumed by pitfall #3 fix. After #3 lands, both literal forms preserve element type uniformly. Close as duplicate. #16 (column-stochastic vs row-stochastic): algorithm/spec clarification, not a Prologos defect. The eigentrust implementation branch already takes column-stochastic M directly and validates via col-stochastic?. https://claude.ai/code/session_01MbncYJnrvjzhbVWw4xGi5x Co-authored-by: kumavis <1474978+kumavis@users.noreply.github.com>
…rks in WS (eigentrust pitfalls #5) EigenTrust pitfall #5 (2026-04-23) reported that (let [tnew := [eigentrust-step c p alpha t]] match [rat-lt [linf-norm [sub-vec tnew t]] eps] | true -> tnew | false -> [eigentrust-iterate c p alpha eps [int- budget 1] tnew]) failed with `let: let with bracket bindings requires: (let [bindings...] body)`. Working `let` examples either kept the body on the same line as `let ...]` or used a bracket-grouped expression body — nested `match` inside the body did not parse. Root cause: the whole let form is wrapped in `(...)`. parse-reader's `group-items` applies its "brackets win" rule and DROPS the indent-open/indent-close markers around the body line. The body's continuation tokens (`match x | _ -> x`) end up spliced flat into the let's argument list, so `expand-let` saw `((x := 1) match x ...)` instead of the expected `((x := 1) <body>)` shape. Branch 1 of `expand-let` rejected anything other than `(length rest) = 2`, hence the error. Fix: in `expand-let`'s bracket-bindings branch, when `rest` has more than 2 elements, treat all post-bindings tokens as the body and wrap them as a single application list. This matches the usual "continuation lines are indented further than `let`" convention that `defn` and `match` already honour at the top level. Bare let and empty-body let still raise as before. Test coverage in `tests/test-let-multiline-ws.rkt`: - Read-level shape checks (single-line, single-token continuation, bracket-grouped body, multi-token continuation) document the parser behavior the fix relies on - End-to-end `run-ns-ws-last` checks for: single-line, simple body, bracket-grouped body, multi-token application body, the eigentrust reproducer (multi-line match inside let body), and two-binding let with multi-token body - Empty-body let still raises Co-authored-by: kumavis <1474978+kumavis@users.noreply.github.com>
e30fde2 to
7007081
Compare
| @@ -1 +1 @@ | |||
| (1 "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos:1771838514" #hasheq((add . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Nat))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-bvar 0) (#(struct:expr-reduce-arm zero 0 #(struct:expr-bvar 1)) #(struct:expr-reduce-arm suc 1 #(struct:expr-suc #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::add) #(struct:expr-bvar 2)) #(struct:expr-bvar 0))))) #t))))) (apply . (#(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi mw #(struct:expr-Pi mw #(struct:expr-bvar 1) #(struct:expr-bvar 1)) #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-bvar 2))))) . #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam mw #(struct:expr-Pi mw #(struct:expr-bvar 1) #(struct:expr-bvar 1)) #(struct:expr-lam mw #(struct:expr-bvar 2) #(struct:expr-app #(struct:expr-bvar 1) #(struct:expr-bvar 0)))))))) (bool-to-nat . (#(struct:expr-Pi mw #(struct:expr-Bool) #(struct:expr-Nat)) . #(struct:expr-lam mw #(struct:expr-Bool) #(struct:expr-reduce #(struct:expr-bvar 0) (#(struct:expr-reduce-arm true 0 #(struct:expr-nat-val 1)) #(struct:expr-reduce-arm false 0 #(struct:expr-nat-val 0))) #t)))) (clamp . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Nat)))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-hole) #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::max) #(struct:expr-bvar 2)) #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::min) #(struct:expr-bvar 0)) #(struct:expr-bvar 1)))))))) (compose . (#(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi mw #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-bvar 2)) #(struct:expr-Pi mw #(struct:expr-Pi mw #(struct:expr-bvar 1) #(struct:expr-bvar 4)) #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-bvar 4))))))) . #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam mw #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-bvar 2)) #(struct:expr-lam mw #(struct:expr-Pi mw #(struct:expr-bvar 1) #(struct:expr-bvar 4)) #(struct:expr-lam mw #(struct:expr-bvar 2) #(struct:expr-app #(struct:expr-bvar 2) #(struct:expr-app #(struct:expr-bvar 1) #(struct:expr-bvar 0))))))))))) (const . (#(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi mw #(struct:expr-bvar 1) #(struct:expr-Pi mw #(struct:expr-bvar 1) #(struct:expr-bvar 3))))) . #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam mw #(struct:expr-bvar 1) #(struct:expr-lam mw #(struct:expr-bvar 1) #(struct:expr-bvar 1))))))) (double . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Nat)) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-bvar 0) (#(struct:expr-reduce-arm zero 0 #(struct:expr-nat-val 0)) #(struct:expr-reduce-arm suc 1 #(struct:expr-suc #(struct:expr-suc #(struct:expr-app #(struct:expr-fvar prologos::data::nat::double) #(struct:expr-bvar 0)))))) #t)))) (flip . (#(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi mw #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-bvar 2))) #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-Pi mw #(struct:expr-bvar 4) #(struct:expr-bvar 3))))))) . #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam mw #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-bvar 2))) #(struct:expr-lam mw #(struct:expr-bvar 2) #(struct:expr-lam mw #(struct:expr-bvar 4) #(struct:expr-app #(struct:expr-app #(struct:expr-bvar 2) #(struct:expr-bvar 0)) #(struct:expr-bvar 1)))))))))) (ge? . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Bool))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::le?) #(struct:expr-bvar 0)) #(struct:expr-bvar 1)))))) (gt? . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Bool))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::lt?) #(struct:expr-bvar 0)) #(struct:expr-bvar 1)))))) (id . (#(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi mw #(struct:expr-bvar 0) #(struct:expr-bvar 1))) . #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam mw #(struct:expr-bvar 0) #(struct:expr-bvar 0))))) (le? . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Bool))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-app #(struct:expr-fvar prologos::data::nat::zero?) #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::sub) #(struct:expr-bvar 1)) #(struct:expr-bvar 0))))))) (lt? . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Bool))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::le?) #(struct:expr-bvar 0)) #(struct:expr-bvar 1)) (#(struct:expr-reduce-arm true 0 #(struct:expr-false)) #(struct:expr-reduce-arm false 0 #(struct:expr-true))) #t))))) (max . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Nat))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::le?) #(struct:expr-bvar 1)) #(struct:expr-bvar 0)) (#(struct:expr-reduce-arm true 0 #(struct:expr-bvar 0)) #(struct:expr-reduce-arm false 0 #(struct:expr-bvar 1))) #t))))) (min . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Nat))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::le?) #(struct:expr-bvar 1)) #(struct:expr-bvar 0)) (#(struct:expr-reduce-arm true 0 #(struct:expr-bvar 1)) #(struct:expr-reduce-arm false 0 #(struct:expr-bvar 0))) #t))))) (mult . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Nat))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-bvar 0) (#(struct:expr-reduce-arm zero 0 #(struct:expr-nat-val 0)) #(struct:expr-reduce-arm suc 1 #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::add) #(struct:expr-bvar 2)) #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::mult) #(struct:expr-bvar 2)) #(struct:expr-bvar 0))))) #t))))) (nat-eq? . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Bool))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::le?) #(struct:expr-bvar 1)) #(struct:expr-bvar 0)) (#(struct:expr-reduce-arm true 0 #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::le?) #(struct:expr-bvar 0)) #(struct:expr-bvar 1))) #(struct:expr-reduce-arm false 0 #(struct:expr-false))) #t))))) (on . (#(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi mw #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-Pi mw #(struct:expr-bvar 3) #(struct:expr-bvar 3))) #(struct:expr-Pi mw #(struct:expr-Pi mw #(struct:expr-bvar 1) #(struct:expr-bvar 4)) #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-Pi mw #(struct:expr-bvar 3) #(struct:expr-bvar 5)))))))) . #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam mw #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-Pi mw #(struct:expr-bvar 3) #(struct:expr-bvar 3))) #(struct:expr-lam mw #(struct:expr-Pi mw #(struct:expr-bvar 1) #(struct:expr-bvar 4)) #(struct:expr-lam mw #(struct:expr-bvar 2) #(struct:expr-lam mw #(struct:expr-bvar 3) #(struct:expr-app #(struct:expr-app #(struct:expr-bvar 3) #(struct:expr-app #(struct:expr-bvar 2) #(struct:expr-bvar 1))) #(struct:expr-app #(struct:expr-bvar 2) #(struct:expr-bvar 0)))))))))))) (pow . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Nat))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-bvar 0) (#(struct:expr-reduce-arm zero 0 #(struct:expr-nat-val 1)) #(struct:expr-reduce-arm suc 1 #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::mult) #(struct:expr-bvar 2)) #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::pow) #(struct:expr-bvar 2)) #(struct:expr-bvar 0))))) #t))))) (pred . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Nat)) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-bvar 0) (#(struct:expr-reduce-arm zero 0 #(struct:expr-nat-val 0)) #(struct:expr-reduce-arm suc 1 #(struct:expr-bvar 0))) #t)))) (prologos::core::apply . (#(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi mw #(struct:expr-Pi mw #(struct:expr-bvar 1) #(struct:expr-bvar 1)) #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-bvar 2))))) . #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam mw #(struct:expr-Pi mw #(struct:expr-bvar 1) #(struct:expr-bvar 1)) #(struct:expr-lam mw #(struct:expr-bvar 2) #(struct:expr-app #(struct:expr-bvar 1) #(struct:expr-bvar 0)))))))) (prologos::core::compose . (#(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi mw #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-bvar 2)) #(struct:expr-Pi mw #(struct:expr-Pi mw #(struct:expr-bvar 1) #(struct:expr-bvar 4)) #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-bvar 4))))))) . #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam mw #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-bvar 2)) #(struct:expr-lam mw #(struct:expr-Pi mw #(struct:expr-bvar 1) #(struct:expr-bvar 4)) #(struct:expr-lam mw #(struct:expr-bvar 2) #(struct:expr-app #(struct:expr-bvar 2) #(struct:expr-app #(struct:expr-bvar 1) #(struct:expr-bvar 0))))))))))) (prologos::core::const . (#(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi mw #(struct:expr-bvar 1) #(struct:expr-Pi mw #(struct:expr-bvar 1) #(struct:expr-bvar 3))))) . #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam mw #(struct:expr-bvar 1) #(struct:expr-lam mw #(struct:expr-bvar 1) #(struct:expr-bvar 1))))))) (prologos::core::flip . (#(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi mw #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-bvar 2))) #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-Pi mw #(struct:expr-bvar 4) #(struct:expr-bvar 3))))))) . #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam mw #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-bvar 2))) #(struct:expr-lam mw #(struct:expr-bvar 2) #(struct:expr-lam mw #(struct:expr-bvar 4) #(struct:expr-app #(struct:expr-app #(struct:expr-bvar 2) #(struct:expr-bvar 0)) #(struct:expr-bvar 1)))))))))) (prologos::core::id . (#(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi mw #(struct:expr-bvar 0) #(struct:expr-bvar 1))) . #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam mw #(struct:expr-bvar 0) #(struct:expr-bvar 0))))) (prologos::core::on . (#(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-Pi mw #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-Pi mw #(struct:expr-bvar 3) #(struct:expr-bvar 3))) #(struct:expr-Pi mw #(struct:expr-Pi mw #(struct:expr-bvar 1) #(struct:expr-bvar 4)) #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-Pi mw #(struct:expr-bvar 3) #(struct:expr-bvar 5)))))))) . #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam m0 #(struct:expr-Type #(struct:lzero)) #(struct:expr-lam mw #(struct:expr-Pi mw #(struct:expr-bvar 2) #(struct:expr-Pi mw #(struct:expr-bvar 3) #(struct:expr-bvar 3))) #(struct:expr-lam mw #(struct:expr-Pi mw #(struct:expr-bvar 1) #(struct:expr-bvar 4)) #(struct:expr-lam mw #(struct:expr-bvar 2) #(struct:expr-lam mw #(struct:expr-bvar 3) #(struct:expr-app #(struct:expr-app #(struct:expr-bvar 3) #(struct:expr-app #(struct:expr-bvar 2) #(struct:expr-bvar 1))) #(struct:expr-app #(struct:expr-bvar 2) #(struct:expr-bvar 0)))))))))))) (prologos::data::nat::add . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Nat))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-bvar 0) (#(struct:expr-reduce-arm zero 0 #(struct:expr-bvar 1)) #(struct:expr-reduce-arm suc 1 #(struct:expr-suc #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::add) #(struct:expr-bvar 2)) #(struct:expr-bvar 0))))) #t))))) (prologos::data::nat::bool-to-nat . (#(struct:expr-Pi mw #(struct:expr-Bool) #(struct:expr-Nat)) . #(struct:expr-lam mw #(struct:expr-Bool) #(struct:expr-reduce #(struct:expr-bvar 0) (#(struct:expr-reduce-arm true 0 #(struct:expr-nat-val 1)) #(struct:expr-reduce-arm false 0 #(struct:expr-nat-val 0))) #t)))) (prologos::data::nat::clamp . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Nat)))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-hole) #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::max) #(struct:expr-bvar 2)) #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::min) #(struct:expr-bvar 0)) #(struct:expr-bvar 1)))))))) (prologos::data::nat::double . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Nat)) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-bvar 0) (#(struct:expr-reduce-arm zero 0 #(struct:expr-nat-val 0)) #(struct:expr-reduce-arm suc 1 #(struct:expr-suc #(struct:expr-suc #(struct:expr-app #(struct:expr-fvar prologos::data::nat::double) #(struct:expr-bvar 0)))))) #t)))) (prologos::data::nat::ge? . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Bool))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::le?) #(struct:expr-bvar 0)) #(struct:expr-bvar 1)))))) (prologos::data::nat::gt? . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Bool))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::lt?) #(struct:expr-bvar 0)) #(struct:expr-bvar 1)))))) (prologos::data::nat::le? . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Bool))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-app #(struct:expr-fvar prologos::data::nat::zero?) #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::sub) #(struct:expr-bvar 1)) #(struct:expr-bvar 0))))))) (prologos::data::nat::lt? . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Bool))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::le?) #(struct:expr-bvar 0)) #(struct:expr-bvar 1)) (#(struct:expr-reduce-arm true 0 #(struct:expr-false)) #(struct:expr-reduce-arm false 0 #(struct:expr-true))) #t))))) (prologos::data::nat::max . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Nat))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::le?) #(struct:expr-bvar 1)) #(struct:expr-bvar 0)) (#(struct:expr-reduce-arm true 0 #(struct:expr-bvar 0)) #(struct:expr-reduce-arm false 0 #(struct:expr-bvar 1))) #t))))) (prologos::data::nat::min . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Nat))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::le?) #(struct:expr-bvar 1)) #(struct:expr-bvar 0)) (#(struct:expr-reduce-arm true 0 #(struct:expr-bvar 1)) #(struct:expr-reduce-arm false 0 #(struct:expr-bvar 0))) #t))))) (prologos::data::nat::mult . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Nat))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-bvar 0) (#(struct:expr-reduce-arm zero 0 #(struct:expr-nat-val 0)) #(struct:expr-reduce-arm suc 1 #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::add) #(struct:expr-bvar 2)) #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::mult) #(struct:expr-bvar 2)) #(struct:expr-bvar 0))))) #t))))) (prologos::data::nat::nat-eq? . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Bool))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::le?) #(struct:expr-bvar 1)) #(struct:expr-bvar 0)) (#(struct:expr-reduce-arm true 0 #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::le?) #(struct:expr-bvar 0)) #(struct:expr-bvar 1))) #(struct:expr-reduce-arm false 0 #(struct:expr-false))) #t))))) (prologos::data::nat::pow . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Nat))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-bvar 0) (#(struct:expr-reduce-arm zero 0 #(struct:expr-nat-val 1)) #(struct:expr-reduce-arm suc 1 #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::mult) #(struct:expr-bvar 2)) #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::pow) #(struct:expr-bvar 2)) #(struct:expr-bvar 0))))) #t))))) (prologos::data::nat::pred . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Nat)) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-bvar 0) (#(struct:expr-reduce-arm zero 0 #(struct:expr-nat-val 0)) #(struct:expr-reduce-arm suc 1 #(struct:expr-bvar 0))) #t)))) (prologos::data::nat::sub . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Nat))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-bvar 0) (#(struct:expr-reduce-arm zero 0 #(struct:expr-bvar 1)) #(struct:expr-reduce-arm suc 1 #(struct:expr-app #(struct:expr-fvar prologos::data::nat::pred) #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::sub) #(struct:expr-bvar 2)) #(struct:expr-bvar 0))))) #t))))) (prologos::data::nat::zero? . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Bool)) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-bvar 0) (#(struct:expr-reduce-arm zero 0 #(struct:expr-true)) #(struct:expr-reduce-arm suc 1 #(struct:expr-false))) #t)))) (sub . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Nat))) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-bvar 0) (#(struct:expr-reduce-arm zero 0 #(struct:expr-bvar 1)) #(struct:expr-reduce-arm suc 1 #(struct:expr-app #(struct:expr-fvar prologos::data::nat::pred) #(struct:expr-app #(struct:expr-app #(struct:expr-fvar prologos::data::nat::sub) #(struct:expr-bvar 2)) #(struct:expr-bvar 0))))) #t))))) (zero? . (#(struct:expr-Pi mw #(struct:expr-Nat) #(struct:expr-Bool)) . #(struct:expr-lam mw #(struct:expr-Nat) #(struct:expr-reduce #(struct:expr-bvar 0) (#(struct:expr-reduce-arm zero 0 #(struct:expr-true)) #(struct:expr-reduce-arm suc 1 #(struct:expr-false))) #t))))) #hasheq((add . #(struct:spec-entry ((Nat Nat -> Nat)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () () #f #f)) (apply . #(struct:spec-entry (((A -> B) A -> B)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () ((A Type 0) (B Type 0)) #f #f)) (bool-to-nat . #(struct:spec-entry ((Bool -> Nat)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () () #f #f)) (clamp . #(struct:spec-entry ((Nat Nat -> Nat -> Nat)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () () #f #f)) (compose . #(struct:spec-entry (((B -> C) (A -> B) A -> C)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () ((B Type 0) (C Type 0) (A Type 0)) #f #f)) (const . #(struct:spec-entry ((A B -> A)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () ((A Type 0) (B Type 0)) #f #f)) (double . #(struct:spec-entry ((Nat -> Nat)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () () #f #f)) (flip . #(struct:spec-entry (((A -> B -> C) B A -> C)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () ((A Type 0) (B Type 0) (C Type 0)) #f #f)) (ge? . #(struct:spec-entry ((Nat Nat -> Bool)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () () #f #f)) (gt? . #(struct:spec-entry ((Nat Nat -> Bool)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () () #f #f)) (id . #(struct:spec-entry ((A -> A)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () ((A Type 0)) #f #f)) (le? . #(struct:spec-entry ((Nat Nat -> Bool)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () () #f #f)) (lt? . #(struct:spec-entry ((Nat Nat -> Bool)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () () #f #f)) (max . #(struct:spec-entry ((Nat Nat -> Nat)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () () #f #f)) (min . #(struct:spec-entry ((Nat Nat -> Nat)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () () #f #f)) (mult . #(struct:spec-entry ((Nat Nat -> Nat)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () () #f #f)) (nat-eq? . #(struct:spec-entry ((Nat Nat -> Bool)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () () #f #f)) (on . #(struct:spec-entry (((B -> B -> C) (A -> B) A A -> C)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () ((B Type 0) (C Type 0) (A Type 0)) #f #f)) (pow . #(struct:spec-entry ((Nat Nat -> Nat)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () () #f #f)) (pred . #(struct:spec-entry ((Nat -> Nat)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () () #f #f)) (sub . #(struct:spec-entry ((Nat Nat -> Nat)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () () #f #f)) (zero? . #(struct:spec-entry ((Nat -> Bool)) #f #f #(struct:srcloc "<unknown>" 0 0 0) () () #f #f))) #hasheq((Ordering . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/ordering.prologos" 8 0 40)) (add . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 10 0 69)) (and . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/bool.prologos" 17 0 62)) (apply . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/core.prologos" 25 0 23)) (bool-eq . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/bool.prologos" 38 0 66)) (bool-to-nat . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 119 0 74)) (clamp . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 126 0 54)) (compose . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/core.prologos" 20 0 29)) (const . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/core.prologos" 15 0 20)) (double . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 24 0 79)) (eq-ord . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/ordering.prologos" 8 0 40)) (flip . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/core.prologos" 30 0 26)) (ge? . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 85 0 24)) (gt-ord . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/ordering.prologos" 8 0 40)) (gt? . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 80 0 24)) (id . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/core.prologos" 10 0 15)) (implies . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/bool.prologos" 59 0 33)) (le? . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 68 0 31)) (lt-ord . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/ordering.prologos" 8 0 40)) (lt? . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 73 0 73)) (max . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 108 0 66)) (min . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 101 0 66)) (mult . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 17 0 76)) (nand . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/bool.prologos" 49 0 30)) (nat-eq? . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 90 0 80)) (nor . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/bool.prologos" 54 0 28)) (not . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/bool.prologos" 10 0 63)) (on . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/core.prologos" 36 0 32)) (or . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/bool.prologos" 24 0 60)) (pow . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 57 0 92)) (pred . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 31 0 60)) (prologos::core::apply . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/core.prologos" 25 0 23)) (prologos::core::compose . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/core.prologos" 20 0 29)) (prologos::core::const . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/core.prologos" 15 0 20)) (prologos::core::flip . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/core.prologos" 30 0 26)) (prologos::core::id . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/core.prologos" 10 0 15)) (prologos::core::on . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/core.prologos" 36 0 32)) (prologos::data::bool::and . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/bool.prologos" 17 0 62)) (prologos::data::bool::bool-eq . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/bool.prologos" 38 0 66)) (prologos::data::bool::implies . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/bool.prologos" 59 0 33)) (prologos::data::bool::nand . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/bool.prologos" 49 0 30)) (prologos::data::bool::nor . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/bool.prologos" 54 0 28)) (prologos::data::bool::not . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/bool.prologos" 10 0 63)) (prologos::data::bool::or . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/bool.prologos" 24 0 60)) (prologos::data::bool::xor . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/bool.prologos" 31 0 62)) (prologos::data::nat::add . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 10 0 69)) (prologos::data::nat::bool-to-nat . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 119 0 74)) (prologos::data::nat::clamp . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 126 0 54)) (prologos::data::nat::double . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 24 0 79)) (prologos::data::nat::ge? . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 85 0 24)) (prologos::data::nat::gt? . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 80 0 24)) (prologos::data::nat::le? . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 68 0 31)) (prologos::data::nat::lt? . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 73 0 73)) (prologos::data::nat::max . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 108 0 66)) (prologos::data::nat::min . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 101 0 66)) (prologos::data::nat::mult . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 17 0 76)) (prologos::data::nat::nat-eq? . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 90 0 80)) (prologos::data::nat::pow . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 57 0 92)) (prologos::data::nat::pred . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 31 0 60)) (prologos::data::nat::sub . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 50 0 70)) (prologos::data::nat::zero? . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 38 0 65)) (prologos::data::ordering::Ordering . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/ordering.prologos" 8 0 40)) (prologos::data::ordering::eq-ord . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/ordering.prologos" 8 0 40)) (prologos::data::ordering::gt-ord . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/ordering.prologos" 8 0 40)) (prologos::data::ordering::lt-ord . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/ordering.prologos" 8 0 40)) (sub . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 50 0 70)) (xor . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/bool.prologos" 31 0 62)) (zero? . #(struct:srcloc "/Users/avanti/dev/projects/prologos/racket/prologos/lib/prologos/data/nat.prologos" 38 0 65))) (add mult double pred zero? sub pow le? lt? gt? ge? nat-eq? min max bool-to-nat clamp) "prologos::data::nat" #hasheq(($compose . expand-compose-sexp) ($list-literal . expand-list-literal) ($lseq-literal . expand-lseq-literal) ($mixfix . expand-mixfix-form) ($pipe-gt . expand-pipe-block) ($quasiquote . expand-quasiquote) ($quote . expand-quote) (cond . expand-cond) (do . expand-do) (if . expand-if) (let . expand-let) (pipe2 . #(struct:preparse-macro pipe2 (pipe2 $x $f $g) ($g ($f $x)))) (pipe3 . #(struct:preparse-macro pipe3 (pipe3 $x $f $g $h) ($h ($g ($f $x))))) (twice . #(struct:preparse-macro twice (twice $f $x) ($f ($f $x)))) (unless . #(struct:preparse-macro unless (unless $cond $body) (if $cond unit $body))) (when . #(struct:preparse-macro when (when $cond $body) (if $cond $body unit))) (with-transient . expand-with-transient)) #hasheq((eq-ord . #(struct:ctor-meta Ordering () () () 1)) (false . #(struct:ctor-meta Bool () () () 1)) (gt-ord . #(struct:ctor-meta Ordering () () () 2)) (lt-ord . #(struct:ctor-meta Ordering () () () 0)) (suc . #(struct:ctor-meta Nat () (Nat) (#t) 1)) (true . #(struct:ctor-meta Bool () () () 0)) (unit . #(struct:ctor-meta Unit () () () 0)) (zero . #(struct:ctor-meta Nat () () () 0))) #hasheq((Bool . (true false)) (Nat . (zero suc)) (Ordering . (lt-ord eq-ord gt-ord)) (Unit . (unit))) #hasheq() #hasheq(((Posit32 . Posit64) . #t) ((Nat . Rat) . #t) ((Posit8 . Posit16) . #t) ((Posit16 . Posit64) . #t) ((Int . Rat) . #t) ((Posit16 . Posit32) . #t) ((Nat . Int) . #t) ((Posit8 . Posit64) . #t) ((Posit8 . Posit32) . #t)) #hasheq() #hasheq() #hasheq() #hasheq() #hasheq() #hasheq() #hasheq() #hasheq() #hasheq((add . (x y)) (and . (a b)) (apply . (A B f x)) (bool-eq . (a b)) (bool-to-nat . (b)) (clamp . (low high)) (compose . (B C A g f x)) (const . (A B x _)) (double . (n)) (flip . (A B C f b a)) (ge? . (x y)) (gt? . (x y)) (id . (A x)) (implies . (a b)) (le? . (x y)) (lt? . (x y)) (max . (x y)) (min . (x y)) (mult . (x y)) (nand . (a b)) (nat-eq? . (x y)) (nor . (a b)) (not . (b)) (on . (B C A f g x y)) (or . (a b)) (pow . (base exp)) (pred . (n)) (sub . (x y)) (xor . (a b)) (zero? . (n))) #hasheq() #hasheq() #hasheq()) No newline at end of file | |||
There was a problem hiding this comment.
crazy diff detected. @hierophantos should "cache" be in .gitignore ?
hierophantos
left a comment
There was a problem hiding this comment.
LGTM. Surgical 18-line fix in expand-let Branch 1 (bracket-bindings format). Replaces the strict (length rest) = 2 requirement with a cond that handles both the single-token body case ((cadr rest)) and the multi-token splice case ((cdr rest) wrapping post-bindings tokens as a body application).
Architectural discipline I appreciated: the PR explicitly debunks the "fix in parse-reader" hypothesis from the original pitfall report and explains why the parser-level fix would have been wrong — parse-reader's "brackets suppress indent" rule inside (...) parens is intentional for non-let forms (we don't want (foo arg1\n arg2) to splice). The macro-level fix is the architecturally-correct location.
Test coverage strategic (11 cases): regressions for single-line / single-token-continuation / bracket-grouped bodies; the eigentrust reproducer (nested match body); multi-binding case; error-case regression (let with bindings but no body still raises).
Audit: no test asserts the old "let with bracket bindings requires" error; multi-line (let [...] (let [...] ...)) patterns in examples/2026-03-16-track4-acceptance.prologos:625-626 would benefit from this fix.
Mergeable as-is, no conflicts.
Approving.
Wires the OCapN port to a real Racket toolchain and fixes the issues
the test run surfaced.
Library fixes
- vat.prologos: rename `spawn` -> `vat-spawn` (collision with the
reserved surface form recognised in macros.rkt:`'spawn`),
`spawn-actor` -> `vat-spawn-actor`. Same in core.prologos and the
acceptance file.
- vat.prologos: drop the `Sigma Vat Nat` return shape for spawn /
fresh-promise / send. Replace with a named `Allocated` struct +
`alloc-vat` / `alloc-id` accessors. The Sigma form ran into
"could not infer" elaborator errors when the body destructured
via `match | pair a b -> ...` and then re-constructed a Sigma;
`[fst p]` / `[snd p]` reused on the same `p` tripped QTT
multiplicity. The named struct sidesteps both.
- vat.prologos: reorder `resolve-promise` / `break-promise` BEFORE
`apply-effect` (forward-reference rule — module elaboration is
single-pass top-to-bottom). Also reorder `step-after-act` before
`deliver-msg` and `list-length-helper` before `queue-length`.
- vat.prologos: drop the queued-pipeline-flush in resolve-promise /
break-promise. PromiseState's queue is `List SyrupValue` (wire
repr); the vat queue is `List VatMsg` (decoded); flushing across
the boundary would need re-encoding. Phase 1.
Test-fixture fix (load-bearing)
- All 8 OCapN test files were updated to capture and restore
`current-ctor-registry` and `current-type-meta` across the setup-
-> run boundary. The standard fixture pattern from
`test-hashable-01.rkt` does NOT preserve these — fine for tests
that only declare traits, but breaks once a preamble's imports
declare new `data` types (every `data` in our 8 modules). Without
it, the reducer sees a stale ctor-registry and refuses to fire
pattern arms over user constructors; results print as un-reduced
`[reduce ... | vat x y z a -> x] : Nat` strings.
Documented as goblin-pitfall #12; the canonical fixture in
test-support.rkt should grow this for every future test.
Compat fence
- driver.rkt: guard
`(current-parallel-executor (make-parallel-thread-fire-all))` with
a feature-detection try/catch on `thread #:pool 'own`. Racket 9
ships parallel threads; Racket 8 does not. Fence preserves the
Racket-9 fast path and falls back to sequential firing on 8.
Acceptance
- examples/2026-04-27-ocapn-acceptance.prologos updated to match
the new vat-spawn/Allocated API and verified to run clean via
process-file.
Pitfalls catalogue (docs/tracking/2026-04-27_GOBLIN_PITFALLS.md)
- #0 (sandbox/no-Racket): closed.
- +#11 — Racket-8 vs Racket-9 `thread #:pool` compat
- +#12 — test fixture loses ctor-registry/type-meta across calls
[highest-impact; canonical fixture pattern needs update]
- +#13 — `spawn` is a reserved surface keyword; collides silently
- +#14 — `match | pair a b ->` on Sigma + Sigma reconstruction =>
"could not infer"
- +#15 — QTT multiplicity on `[fst p]`/`[snd p]` reused thrice
- +#16 — single-pass module elaboration: forward references error
- +#17 — promise-queue (Syrup) vs vat-queue (VatMsg) type clash
on flush — design pitfall, scope cut
Test results
refr 6/6 syrup 22/22 promise 16/16 message 19/19
behavior 13/13 vat 21/21 pipeline 5/5 captp 7/7
e2e 8/8 total 117/117 PASS
Per user review of #0-#10: many entries were either out-of-scope (env limitations, not Prologos issues) or wrong (claims I never actually tested). Re-tested every claim against a real Racket and revised the doc. Numbers are reserved per the user's instruction — entries marked DELETED keep their slot so cross-refs don't drift. Detail: #0 DELETED — out-of-scope (Racket toolchain not in sandbox). Environment limitation, not a Prologos issue. #1 REFRAMED — was "capability subtype + promise resolution composition." Re-titled to honestly reflect what this actually is: an OCapN-side Phase 0 deferred-implementation note (eventual cross-vat receive isn't wired up yet). NOT a Prologos bug. #2 DELETED — false claim. Tested with a real Racket: WS-mode wildcard match `match | _ -> body` on user data types elaborates AND evaluates correctly when the function carries a proper `spec`. The `prologos::data::datum` comment I cited applies to a narrower polymorphic-context case, not a blanket wildcard ban as I asserted. Cleanup of behavior.prologos (~250 -> ~70 LOC) follows. #3 DELETED — false claim. Tested: `data Step step : [Nat -> Nat]` (with bracketed function type per the lseq-cell convention) accepts a function value, including closures with captured state. Open-world actor behaviour storage IS supported. The closed-enum BehaviorTag in our implementation was a needless workaround driven by this incorrect pitfall. Cleanup tracked separately. #4 KEPT, REFRAMED — real, narrowed claim. grammar.ebnf §6 lines 1153/1187/1199 promise `Mu` (sexp) and `rec` (WS) for recursive sessions. Both elaborate to `Unknown session type: rec` / `Mu`. So pitfall #4 is now: "rec/Mu in grammar but not in elaborator." CapTP's stream-level well-typedness is therefore the documented ceiling; per-exchange sub-protocols remain the workaround. #5 KEPT — `none`/`some` need explicit type args in some inference contexts. Real ergonomics tension, accurately documented. #6 DELETED — out-of-scope. WS-mode `let p := body` and sexp-mode `(let (p v) body)` are TWO surface forms by design (grammar.ebnf §7 line 1236). User-error, not a Prologos bug. #7 DELETED — was a quantitative restatement of #2. With #2 recanted, #7 evaporates: behavior modules can be wildcard-collapsed, dropping ~180 LOC. #8 DELETED — false claim. Tested: `data Box1 box1 : [Sigma [_ <Nat>] Bool]` and `data Table table : Nat -> [List [Sigma [_ <Nat>] Bool]]` both elaborate cleanly. The named-struct ActorEntry/PromiseEntry workaround in vat.prologos was unnecessary; can be simplified back. #9 DELETED — user error. `def` for value bindings vs `defn` for functions is documented (grammar.ebnf §3 lines 189-190, prologos-syntax rules). Mis-using `defn` for a 0-ary constant isn't a Prologos bug. #10 DELETED — out-of-scope. Network sandbox blocking external docs is an environment limitation. #11-#20 were not in scope of this review and remain as-is for the user to review next.
Per user direction: - Replace the body of every DELETED entry with a single-sentence explanation. Numbers reserved per prior instruction. - Delete #15 (QTT multiplicity on fst/snd thrice). I re-tested with a real Racket — `pair [snd p] [fst p]` then a third use of `fst p` works fine; no multiplicity error. The failure I had conflated this with was actually #14's "match-and-reconstruct Sigma" issue. Result: pitfalls doc shrinks from 765 to 534 lines. Remaining real claims: #1, #4, #5, #11, #12, #13, #14, #16, #17, #18, #19, #20 (the user has reviewed only #0-10 so far; #11-20 still pending their review).
Adds to prologos-syntax.md § "Pattern matching and dispatch": Multi-line clause body: continuation indented past the `|`. When a clause body is more complex than a single inline expression (e.g., contains a nested `match`), put the body on the next line indented further than the `|` it belongs to. The mechanism reuses parse-reader's indent-grouping rule (same architectural pattern PR #11's multi-line let body fix builds on). Body at SAME indent as `|` is a layout violation — currently produces a hard parser error tracked as Case 6 in #27 for diagnostic improvement. Verified empirically with the canonical `nth` example. Convention is consistent across defn body, def := body, let body, AND clause -> body — same indent rule, four contexts. Dailies entry under "Parallel session continuation — language exploration + syntax convention codification" captures: the syntax update, cumulative issues filed (#23, #25, #26, #27), four lessons distilled.
Wires the OCapN port to a real Racket toolchain and fixes the issues
the test run surfaced.
Library fixes
- vat.prologos: rename `spawn` -> `vat-spawn` (collision with the
reserved surface form recognised in macros.rkt:`'spawn`),
`spawn-actor` -> `vat-spawn-actor`. Same in core.prologos and the
acceptance file.
- vat.prologos: drop the `Sigma Vat Nat` return shape for spawn /
fresh-promise / send. Replace with a named `Allocated` struct +
`alloc-vat` / `alloc-id` accessors. The Sigma form ran into
"could not infer" elaborator errors when the body destructured
via `match | pair a b -> ...` and then re-constructed a Sigma;
`[fst p]` / `[snd p]` reused on the same `p` tripped QTT
multiplicity. The named struct sidesteps both.
- vat.prologos: reorder `resolve-promise` / `break-promise` BEFORE
`apply-effect` (forward-reference rule — module elaboration is
single-pass top-to-bottom). Also reorder `step-after-act` before
`deliver-msg` and `list-length-helper` before `queue-length`.
- vat.prologos: drop the queued-pipeline-flush in resolve-promise /
break-promise. PromiseState's queue is `List SyrupValue` (wire
repr); the vat queue is `List VatMsg` (decoded); flushing across
the boundary would need re-encoding. Phase 1.
Test-fixture fix (load-bearing)
- All 8 OCapN test files were updated to capture and restore
`current-ctor-registry` and `current-type-meta` across the setup-
-> run boundary. The standard fixture pattern from
`test-hashable-01.rkt` does NOT preserve these — fine for tests
that only declare traits, but breaks once a preamble's imports
declare new `data` types (every `data` in our 8 modules). Without
it, the reducer sees a stale ctor-registry and refuses to fire
pattern arms over user constructors; results print as un-reduced
`[reduce ... | vat x y z a -> x] : Nat` strings.
Documented as goblin-pitfall #12; the canonical fixture in
test-support.rkt should grow this for every future test.
Compat fence
- driver.rkt: guard
`(current-parallel-executor (make-parallel-thread-fire-all))` with
a feature-detection try/catch on `thread #:pool 'own`. Racket 9
ships parallel threads; Racket 8 does not. Fence preserves the
Racket-9 fast path and falls back to sequential firing on 8.
Acceptance
- examples/2026-04-27-ocapn-acceptance.prologos updated to match
the new vat-spawn/Allocated API and verified to run clean via
process-file.
Pitfalls catalogue (docs/tracking/2026-04-27_GOBLIN_PITFALLS.md)
- #0 (sandbox/no-Racket): closed.
- +#11 — Racket-8 vs Racket-9 `thread #:pool` compat
- +#12 — test fixture loses ctor-registry/type-meta across calls
[highest-impact; canonical fixture pattern needs update]
- +#13 — `spawn` is a reserved surface keyword; collides silently
- +#14 — `match | pair a b ->` on Sigma + Sigma reconstruction =>
"could not infer"
- +#15 — QTT multiplicity on `[fst p]`/`[snd p]` reused thrice
- +#16 — single-pass module elaboration: forward references error
- +#17 — promise-queue (Syrup) vs vat-queue (VatMsg) type clash
on flush — design pitfall, scope cut
Test results
refr 6/6 syrup 22/22 promise 16/16 message 19/19
behavior 13/13 vat 21/21 pipeline 5/5 captp 7/7
e2e 8/8 total 117/117 PASS
Per user review of #0-#10: many entries were either out-of-scope (env limitations, not Prologos issues) or wrong (claims I never actually tested). Re-tested every claim against a real Racket and revised the doc. Numbers are reserved per the user's instruction — entries marked DELETED keep their slot so cross-refs don't drift. Detail: #0 DELETED — out-of-scope (Racket toolchain not in sandbox). Environment limitation, not a Prologos issue. #1 REFRAMED — was "capability subtype + promise resolution composition." Re-titled to honestly reflect what this actually is: an OCapN-side Phase 0 deferred-implementation note (eventual cross-vat receive isn't wired up yet). NOT a Prologos bug. #2 DELETED — false claim. Tested with a real Racket: WS-mode wildcard match `match | _ -> body` on user data types elaborates AND evaluates correctly when the function carries a proper `spec`. The `prologos::data::datum` comment I cited applies to a narrower polymorphic-context case, not a blanket wildcard ban as I asserted. Cleanup of behavior.prologos (~250 -> ~70 LOC) follows. #3 DELETED — false claim. Tested: `data Step step : [Nat -> Nat]` (with bracketed function type per the lseq-cell convention) accepts a function value, including closures with captured state. Open-world actor behaviour storage IS supported. The closed-enum BehaviorTag in our implementation was a needless workaround driven by this incorrect pitfall. Cleanup tracked separately. #4 KEPT, REFRAMED — real, narrowed claim. grammar.ebnf §6 lines 1153/1187/1199 promise `Mu` (sexp) and `rec` (WS) for recursive sessions. Both elaborate to `Unknown session type: rec` / `Mu`. So pitfall #4 is now: "rec/Mu in grammar but not in elaborator." CapTP's stream-level well-typedness is therefore the documented ceiling; per-exchange sub-protocols remain the workaround. #5 KEPT — `none`/`some` need explicit type args in some inference contexts. Real ergonomics tension, accurately documented. #6 DELETED — out-of-scope. WS-mode `let p := body` and sexp-mode `(let (p v) body)` are TWO surface forms by design (grammar.ebnf §7 line 1236). User-error, not a Prologos bug. #7 DELETED — was a quantitative restatement of #2. With #2 recanted, #7 evaporates: behavior modules can be wildcard-collapsed, dropping ~180 LOC. #8 DELETED — false claim. Tested: `data Box1 box1 : [Sigma [_ <Nat>] Bool]` and `data Table table : Nat -> [List [Sigma [_ <Nat>] Bool]]` both elaborate cleanly. The named-struct ActorEntry/PromiseEntry workaround in vat.prologos was unnecessary; can be simplified back. #9 DELETED — user error. `def` for value bindings vs `defn` for functions is documented (grammar.ebnf §3 lines 189-190, prologos-syntax rules). Mis-using `defn` for a 0-ary constant isn't a Prologos bug. #10 DELETED — out-of-scope. Network sandbox blocking external docs is an environment limitation. #11-#20 were not in scope of this review and remain as-is for the user to review next.
Per user direction: - Replace the body of every DELETED entry with a single-sentence explanation. Numbers reserved per prior instruction. - Delete #15 (QTT multiplicity on fst/snd thrice). I re-tested with a real Racket — `pair [snd p] [fst p]` then a third use of `fst p` works fine; no multiplicity error. The failure I had conflated this with was actually #14's "match-and-reconstruct Sigma" issue. Result: pitfalls doc shrinks from 765 to 534 lines. Remaining real claims: #1, #4, #5, #11, #12, #13, #14, #16, #17, #18, #19, #20 (the user has reviewed only #0-10 so far; #11-20 still pending their review).
Fixes pitfall #5 from the 2026-04-23 eigentrust pitfalls memo.
Summary
failed with
let: let with bracket bindings requires: (let [bindings…] body). The pitfall report attributed it to indent-handling. The actual root cause is different and instructive.Root cause
letlives inside(...)parens. parse-reader'sgroup-itemsapplies its "brackets win" rule and DROPSindent-open/indent-closemarkers around the body. So(let [x := 1]\n match x | _ -> x)parses to(let (x := 1) match x $pipe _ -> x)— body tokens flat, length 7 instead of length 2 (bindings + body). The bracket-bindings branch inexpand-letrequired exactly(length rest) = 2and rejected anything else.Fix
In
expand-letbranch 1 (bracket bindings), when(length rest) > 2, wrap the post-bindings tokens into a single body application. Localized, ~18 lines inmacros.rkt. Avoids touchingparse-reader.rkt's "brackets suppress indent" rule (which is intentional for non-letforms — we don't want(foo arg1\n arg2)to splice).Why the suggested fix would have been wrong
The pitfall's "suggested fix" (align WS
letparser with the indent rule thatdefn/matchhonour) misdiagnoses.defn/matchwork because they're at top-level (no enclosing parens), where indent grouping IS active. Inside(let ...), indent grouping is intentionally suppressed. The right fix is at theletmacro, not at the parser.Test plan
tests/test-let-multiline-ws.rkt— 11 cases: single-line baseline, multi-line with simple expression body, multi-line with nestedmatchbody (the eigentrust reproducer), edge casesbenchmarks/micro/info.rkt)Commits
4eb61d1— primary fix inexpand-letc66a6d7— CI fix (skip stale bench file)https://claude.ai/code/session_01MbncYJnrvjzhbVWw4xGi5x
Generated by Claude Code