fieldtest: remove-mut-var-assign — 4 examples, all working; milestone CLOSED
Post-audit downstream-LLM-author field test of the post-removal Form-A surface. 4 fresh real-world programs written from DESIGN.md + form_a.md + public examples only (no compiler source): running sum-of-squares accumulator (loop/recur → 385), grade cascade (let-threaded if → 4/2/0), Horner polynomial straight-line build-up (let-shadow chain → 73), multi-state bracket scanner threading (rest,depth,ok) by tail recursion → true/false. 0 bugs, 0 friction, 0 spec_gap, 4 working — every task clean and correct on the first try with only let/if/loop/recur; all parse|render|parse byte-identical; zero mut/var/assign tokens produced (a doc-faithful author did not reach for the removed construct). The closest-to-friction case (multi-state machine restates the full state tuple per tail-call) is correctly classified working, not a spec_gap: that explicit-dataflow cost is the local-reasoning pillar working as designed; mut's implicit cross-iteration persistence is exactly the failure class the removal eliminates. mut-keyword rejection is fail-closed with a diagnostic that enumerates the surviving forms (no tombstone, no-nostalgia, as spec'd). Removal thesis empirically CONFIRMED — mut was redundant with let/if/loop/recur in 100% of the fresh tasks. The remove-mut-var-assign milestone is fully ratified and CLOSED: spec+plan+iter, audit clean (architect [high] form_a.md fixed in .tidy, bench causally exonerated), fieldtest clean. Roadmap P0 flipped [~]→[x]; WhatsNew user-facing entry appended.
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
; Axis: running numeric accumulator over a bounded range.
|
||||
;
|
||||
; Imperative instinct (the shape `mut` would invite):
|
||||
; s = 0
|
||||
; for i in 1..=n: s = s + i*i
|
||||
; return s
|
||||
;
|
||||
; Surviving-surface shape: a `loop` with two binders (i counter,
|
||||
; acc accumulator) and a `recur` in the tail of the else branch.
|
||||
; sum_sq(10) = 1+4+9+16+25+36+49+64+81+100 = 385.
|
||||
; Expected stdout: 385
|
||||
|
||||
(module remove-mut_1_sum_of_squares
|
||||
|
||||
(fn sum_sq
|
||||
(doc "Sum of i*i for i in 1..=n via loop/recur. Two binders: i (counter), acc (running total).")
|
||||
(type (fn-type (params (con Int)) (ret (con Int))))
|
||||
(params n)
|
||||
(body
|
||||
(loop (i (con Int) 1) (acc (con Int) 0)
|
||||
(if (app > i n)
|
||||
acc
|
||||
(recur (app + i 1) (app + acc (app * i i)))))))
|
||||
|
||||
(fn main
|
||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||
(params)
|
||||
(body
|
||||
(app print (app sum_sq 10)))))
|
||||
@@ -0,0 +1,38 @@
|
||||
; Axis: conditional classification an imperative author writes as
|
||||
; "set a code variable through a cascade of if-branches".
|
||||
;
|
||||
; Imperative instinct (the shape `mut` would invite):
|
||||
; g = 0 ; 0=F
|
||||
; if score >= 60: g = 1 ; D
|
||||
; if score >= 70: g = 2 ; C
|
||||
; if score >= 80: g = 3 ; B
|
||||
; if score >= 90: g = 4 ; A
|
||||
; return g
|
||||
;
|
||||
; Surviving-surface shape: either a let-threaded `g` updated by
|
||||
; nested `if`, or a single nested `if` cascade. Both are pure
|
||||
; expressions; the `mut` flag was never needed.
|
||||
; grade(95)=4 (A), grade(72)=2 (C), grade(50)=0 (F).
|
||||
; Expected stdout (per line): 4, 2, 0
|
||||
|
||||
(module remove-mut_2_grade_cascade
|
||||
|
||||
(fn grade
|
||||
(doc "Letter-grade code (4=A..0=F) from a numeric score, written as the let-threaded equivalent of a mutable cascade.")
|
||||
(type (fn-type (params (con Int)) (ret (con Int))))
|
||||
(params score)
|
||||
(body
|
||||
(let g 0
|
||||
(let g (if (app >= score 60) 1 g)
|
||||
(let g (if (app >= score 70) 2 g)
|
||||
(let g (if (app >= score 80) 3 g)
|
||||
(let g (if (app >= score 90) 4 g)
|
||||
g)))))))
|
||||
|
||||
(fn main
|
||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||
(params)
|
||||
(body
|
||||
(seq (app print (app grade 95))
|
||||
(seq (app print (app grade 72))
|
||||
(app print (app grade 50)))))))
|
||||
@@ -0,0 +1,35 @@
|
||||
; Axis: multi-step straight-line numeric build-up (Horner-form
|
||||
; polynomial evaluation over fixed coefficients).
|
||||
;
|
||||
; Evaluate p(x) = 2x^4 + 3x^3 + 0x^2 + 5x + 7 at x.
|
||||
; Imperative instinct (the shape `mut` would invite):
|
||||
; acc = 2
|
||||
; acc = acc*x + 3
|
||||
; acc = acc*x + 0
|
||||
; acc = acc*x + 5
|
||||
; acc = acc*x + 7
|
||||
; return acc
|
||||
;
|
||||
; Surviving-surface shape: a straight chain of `let acc` shadowings,
|
||||
; each step a pure expression. p(2) = 2*16+3*8+0+5*2+7 = 32+24+10+7
|
||||
; = 73. Expected stdout: 73
|
||||
|
||||
(module remove-mut_3_horner_poly
|
||||
|
||||
(fn poly
|
||||
(doc "Horner-form evaluation of 2x^4+3x^3+0x^2+5x+7 as a straight-line let chain (the faithful let/if form of a mutable acc).")
|
||||
(type (fn-type (params (con Int)) (ret (con Int))))
|
||||
(params x)
|
||||
(body
|
||||
(let acc 2
|
||||
(let acc (app + (app * acc x) 3)
|
||||
(let acc (app + (app * acc x) 0)
|
||||
(let acc (app + (app * acc x) 5)
|
||||
(let acc (app + (app * acc x) 7)
|
||||
acc)))))))
|
||||
|
||||
(fn main
|
||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||
(params)
|
||||
(body
|
||||
(app print (app poly 2)))))
|
||||
@@ -0,0 +1,83 @@
|
||||
; Axis: a small streaming-feel state machine threading MORE THAN
|
||||
; ONE piece of state, updating only a SUBSET per branch.
|
||||
;
|
||||
; Scan a token stream (a recursive Int list; 1 = '(', 2 = ')',
|
||||
; 0 = any other token) and decide if the brackets are balanced.
|
||||
;
|
||||
; Imperative instinct (exactly what `mut` would invite):
|
||||
; depth = 0
|
||||
; ok = true
|
||||
; for t in stream:
|
||||
; if t == 1: depth = depth + 1 ; only depth changes
|
||||
; elif t == 2:
|
||||
; if depth == 0: ok = false ; only ok changes
|
||||
; else: depth = depth - 1 ; only depth changes
|
||||
; ; t == 0 -> neither changes
|
||||
; return ok && depth == 0
|
||||
;
|
||||
; Surviving-surface shape: a recursive scanner fn threading
|
||||
; (rest, depth, ok) — `loop`/`recur` cannot walk an ADT (it rebinds
|
||||
; positionally, there is no structural pattern in a recur), so the
|
||||
; stream traversal is ordinary tail recursion; the per-branch
|
||||
; "update a subset of the state" becomes "pass the unchanged values
|
||||
; through unchanged". This is the task that most stresses the
|
||||
; removal: an imperative author updates one variable and leaves the
|
||||
; others implicitly alone; here every recur must restate all three.
|
||||
;
|
||||
; balanced "(()())" -> true ; stream 1 1 2 1 2 2
|
||||
; balanced ")(" -> false ; stream 2 1
|
||||
; Expected stdout (per line): true, false
|
||||
|
||||
(module remove-mut_4_bracket_scanner
|
||||
|
||||
(data TokStream
|
||||
(doc "1='(' , 2=')' , 0=other.")
|
||||
(ctor Nil)
|
||||
(ctor Cons (con Int) (con TokStream)))
|
||||
|
||||
(fn scan
|
||||
(doc "Thread (rest, depth, ok). Each arm updates a subset of state; the unchanged components must be restated in every tail call.")
|
||||
(type
|
||||
(fn-type
|
||||
(params (own (con TokStream)) (con Int) (con Bool))
|
||||
(ret (con Bool))))
|
||||
(params rest depth ok)
|
||||
(body
|
||||
(match rest
|
||||
(case (pat-ctor Nil)
|
||||
(if ok (app == depth 0) false))
|
||||
(case (pat-ctor Cons t more)
|
||||
(match t
|
||||
(case (pat-lit 1)
|
||||
(tail-app scan more (app + depth 1) ok))
|
||||
(case (pat-lit 2)
|
||||
(if (app == depth 0)
|
||||
(tail-app scan more depth false)
|
||||
(tail-app scan more (app - depth 1) ok)))
|
||||
(case _
|
||||
(tail-app scan more depth ok)))))))
|
||||
|
||||
(fn balanced
|
||||
(type (fn-type (params (own (con TokStream))) (ret (con Bool))))
|
||||
(params s)
|
||||
(body (app scan s 0 true)))
|
||||
|
||||
(fn main
|
||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||
(params)
|
||||
(body
|
||||
(seq
|
||||
(app print
|
||||
(app balanced
|
||||
(term-ctor TokStream Cons 1
|
||||
(term-ctor TokStream Cons 1
|
||||
(term-ctor TokStream Cons 2
|
||||
(term-ctor TokStream Cons 1
|
||||
(term-ctor TokStream Cons 2
|
||||
(term-ctor TokStream Cons 2
|
||||
(term-ctor TokStream Nil)))))))))
|
||||
(app print
|
||||
(app balanced
|
||||
(term-ctor TokStream Cons 2
|
||||
(term-ctor TokStream Cons 1
|
||||
(term-ctor TokStream Nil)))))))))
|
||||
Reference in New Issue
Block a user