505eb8484e
Post-audit field test of the operator-routing-eq-ord milestone (closed via5170b6a+4d45bc6). Five `.ail` Surface-form fixtures under `examples/fieldtest/` written by an LLM-author working strictly from the design/ ledger + public examples (no `crates/` / `runtime/` / `bench/` reads — Iron Law honoured): eqord_1_fizzbuzz.ail — FizzBuzz [1..15] via (app eq …) on Int+Str and (app gt …) on Int eqord_2_rational_eq.ail — data Rational + user-instance (class prelude.Eq) by cross-mult; inner Int-eq nested in instance body eqord_3_newton_sqrt.ail — Newton's method via float_lt (convergence + fabs) and float_eq (zero-guard) eqord_4_float_ord_must_fail.ail — (app lt 1.5 2.5) must reject at typecheck with float_lt hint eqord_5_float_eq_must_fail.ail — (app eq 1.5 1.5) must reject at typecheck with float_eq hint Findings: [working] x4 — primitive Eq/Ord at Int/Bool/Str/Unit; user-ADT Eq with nested primitive eq calls; Float named-fn surface (float_eq/float_lt/etc.); NoInstance Eq/Ord Float diagnostic with float_eq / float_lt addendum. The milestone's central thesis (class-dispatch is the only comparison surface; Float opts out via named fns) is LLM-natural — every (app eq …) / (app gt …) / (app float_lt …) call I wrote compiled on first try with no diagnostic friction. [spec_gap] x1 — `docs/specs/2026-05-20-operator-routing-eq-ord.md:113` north-star example writes bare `(class Eq)` where the language requires `(class prelude.Eq)`. An LLM-author who copies the spec verbatim hits `bare-cross-module-class-ref`. The milestone spec is the highest-information reference an LLM-author consults; the bare-vs-qualified drift mis-primes the pattern. Resolution: tighten-the-design-ledger — fix the spec example inline (separate follow-up commit). The existing `examples/eq_ord_user_adt.ail` already uses the qualified form, so the corpus is consistent; only the spec drifted. [friction] x1 — `(app compare 1.5 2.5)` at Float fires the same diagnostic as `(app lt …)` at Float, naming `float_eq / float_lt (and siblings)` as the alternative. But the alternatives don't return Ordering; an LLM-author who wanted three-way LT/EQ/GT can't satisfy that with float_lt + float_eq alone. The spec (lines 433-436) acknowledged this case in commentary — "no float_compare ships; build it from float_lt + float_eq if you need three-way" — but the diagnostic doesn't say so. Resolution: file as Gitea backlog issue for a follow-up tidy iteration (codegen-side: branch the Float-aware NoInstance addendum on the called method-name; the `compare` arm gets a one-sentence "no float_compare; build it from float_lt + float_eq if you need three-way" addendum). Status: clean — no bugs, no blockers, the milestone surface is solidly LLM-usable. Both non-working findings are tractable forward-fixes that don't disturb the milestone's core contracts. Spec: docs/specs/2026-05-21-fieldtest-operator-routing-eq-ord.md
74 lines
1.7 KiB
Plaintext
74 lines
1.7 KiB
Plaintext
; Fieldtest fixture — Axis 1: equality on primitive Int via `(app eq …)`.
|
|
;
|
|
; FizzBuzz over [1..15]:
|
|
; if n % 15 == 0 print "FizzBuzz"
|
|
; else if n % 3 == 0 print "Fizz"
|
|
; else if n % 5 == 0 print "Buzz"
|
|
; else print (show n)
|
|
;
|
|
; Equality dispatches through prelude.Eq.eq at Int (intercept arm
|
|
; eq__Int → `icmp eq i64`). Demonstrates the LLM-natural shape of
|
|
; `(app eq …)` on the primitive type that dominates most numerical
|
|
; code.
|
|
;
|
|
; Expected stdout (one per line):
|
|
; 1
|
|
; 2
|
|
; Fizz
|
|
; 4
|
|
; Buzz
|
|
; Fizz
|
|
; 7
|
|
; 8
|
|
; Fizz
|
|
; Buzz
|
|
; 11
|
|
; Fizz
|
|
; 13
|
|
; 14
|
|
; FizzBuzz
|
|
|
|
(module eqord_1_fizzbuzz
|
|
|
|
(fn classify
|
|
(doc "Return the FizzBuzz label for n, or the empty string if n is a plain number.")
|
|
(type
|
|
(fn-type
|
|
(params (con Int))
|
|
(ret (con Str))))
|
|
(params n)
|
|
(body
|
|
(if (app eq (app % n 15) 0)
|
|
"FizzBuzz"
|
|
(if (app eq (app % n 3) 0)
|
|
"Fizz"
|
|
(if (app eq (app % n 5) 0)
|
|
"Buzz"
|
|
"")))))
|
|
|
|
(fn emit_one
|
|
(doc "Print the FizzBuzz label or the number itself.")
|
|
(type (fn-type (params (con Int)) (ret (con Unit)) (effects IO)))
|
|
(params n)
|
|
(body
|
|
(let label (app classify n)
|
|
(if (app eq label "")
|
|
(app print n)
|
|
(app print label)))))
|
|
|
|
(fn loop
|
|
(doc "Tail-recursive driver over [i..stop].")
|
|
(type (fn-type (params (con Int) (con Int)) (ret (con Unit)) (effects IO)))
|
|
(params i stop)
|
|
(body
|
|
(if (app gt i stop)
|
|
(lit-unit)
|
|
(seq
|
|
(app emit_one i)
|
|
(tail-app loop (app + i 1) stop)))))
|
|
|
|
(fn main
|
|
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
|
(params)
|
|
(body (app loop 1 15))))
|