3b3c8c4f07
Post-ship field test of the shipped `series` library extension as a downstream Form-A author working from the public surface only. Five fixtures under examples/fieldtest/ across the construction/auto-import, ring-buffer/financial-indexing, len/total_count bookkeeping, param-in error-quality, and operator-naming axes; spec at docs/specs/0067-fieldtest-series-step1.md. Wins (carry-on): auto-import works with no `(import series)`; the financial index (0 = newest) maps directly onto the bounded-buffer mental model and stays correct after multiple wraps; the param-in diagnostic for a disallowed element type names the type, the type-variable, the qualified type, and the allowed set. Findings routed: - [bug] An owned ADT threaded through tail-recursion whose base case neither returns nor consumes it is never dropped — a general drop-soundness leak (a plain `Box` control with no Series/RawBuf also leaks). Series surfaces it heavily on the whitepaper's headline streaming pattern, and the committed reference examples/series_sma.ail itself leaks (live=8). Minimal repro: series-step1_5 (live=4). - [friction] `ail describe ... Series.push` (the canonical type-scoped form) reports module-not-found; only `series.push` / bare `push` resolve, and no command lists a type's op set. - [spec_gap] referencing a kernel base type (`RawBuf`) from a user ADT ctor field requires full qualification (`raw_buf.RawBuf`) while bare `Series` works in type-position via auto-import — the asymmetry is undocumented. The fixtures that leak still produce correct output; the leak is a separate observable under AILANG_RC_STATS and an orthogonal, pre-existing bug, not a Series defect. refs #61
80 lines
2.9 KiB
Plaintext
80 lines
2.9 KiB
Plaintext
; Fieldtest series-step1.1 — ring-buffer + financial-indexing + warmup.
|
|
;
|
|
; Task an LLM author is naturally given: "stream a sequence of Int
|
|
; readings into a window of size 3 and, after each push, print the
|
|
; maximum of the values currently in the window." This is the canonical
|
|
; bounded-buffer streaming task: the window only ever holds the last 3
|
|
; readings, so the running max must respect eviction (a large old value
|
|
; that has scrolled out of the window must NOT keep winning).
|
|
;
|
|
; Exercises:
|
|
; - (new Series (con Int) 3) + auto-import (no (import series))
|
|
; - Series.push threading the owned Series through the stream
|
|
; - Series.at with financial indexing (0 = newest) — we scan i in
|
|
; [0, Series.len) so warmup (fewer than 3 elements) is handled by
|
|
; reading only the live count, never a stale slot.
|
|
; - Series.len as the live-count bound (saturates at lookback=3).
|
|
;
|
|
; Stream: 4, 1, 7, 2, 3, 1
|
|
; after 4 -> window {4} max 4
|
|
; after 1 -> window {4,1} max 4
|
|
; after 7 -> window {4,1,7} max 7
|
|
; after 2 -> window {1,7,2} max 7 (4 evicted)
|
|
; after 3 -> window {7,2,3} max 7
|
|
; after 1 -> window {2,3,1} max 3 (7 evicted) <-- the eviction proof
|
|
; Expected stdout (one per line): 4 4 7 7 7 3
|
|
|
|
(module series-step1_1_rolling_max
|
|
|
|
(data IntList
|
|
(ctor INil)
|
|
(ctor ICons (con Int) (con IntList)))
|
|
|
|
; Max over the live window: scan indices 0..len, return the largest.
|
|
(fn window_max_step
|
|
(type (fn-type
|
|
(params (borrow (con Series (con Int))) (own (con Int)) (own (con Int)) (own (con Int)))
|
|
(ret (own (con Int)))))
|
|
(params s len i acc)
|
|
(body
|
|
(if (app eq i len)
|
|
acc
|
|
(tail-app window_max_step s len
|
|
(app + i 1)
|
|
(if (app gt (app Series.at s i) acc) (app Series.at s i) acc)))))
|
|
|
|
(fn window_max
|
|
(type (fn-type
|
|
(params (borrow (con Series (con Int))))
|
|
(ret (own (con Int)))))
|
|
(params s)
|
|
(body (app window_max_step s (app Series.len s) 0 0)))
|
|
|
|
(fn run_stream
|
|
(type (fn-type
|
|
(params (own (con Series (con Int))) (own (con IntList)))
|
|
(ret (own (con Unit))) (effects IO)))
|
|
(params s input)
|
|
(body
|
|
(match input
|
|
(case (pat-ctor INil) (do io/print_str ""))
|
|
(case (pat-ctor ICons v rest)
|
|
(let s_new (app Series.push s v)
|
|
(seq
|
|
(seq (app print (app window_max s_new)) (do io/print_str "\n"))
|
|
(tail-app run_stream s_new rest)))))))
|
|
|
|
(fn main
|
|
(type (fn-type (params) (ret (own (con Unit))) (effects IO)))
|
|
(params)
|
|
(body
|
|
(let s (new Series (con Int) 3)
|
|
(app run_stream s
|
|
(term-ctor IntList ICons 4
|
|
(term-ctor IntList ICons 1
|
|
(term-ctor IntList ICons 7
|
|
(term-ctor IntList ICons 2
|
|
(term-ctor IntList ICons 3
|
|
(term-ctor IntList ICons 1
|
|
(term-ctor IntList INil))))))))))))
|